diff mbox

[C++-11] User defined literals

Message ID 4EAD85D3.9010101@verizon.net
State New
Headers show

Commit Message

Ed Smith-Rowland Oct. 30, 2011, 5:13 p.m. UTC
On 10/27/2011 03:47 PM, Jason Merrill wrote:
> On 10/27/2011 03:32 PM, Ed Smith-Rowland wrote:
>> +  if (TREE_CODE (TREE_TYPE (decl)) != LANG_TYPE)
>> +    argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
>
> If you have multiple overloaded operator"" _foo, you need to iterate 
> over them looking for the one (or ones, in the case of numeric 
> literals) you want.
>
>> +  if (argtypes != NULL_TREE
>> + && TREE_VALUE (argtypes) != TREE_TYPE (value))
>
> I think you want
>
>  if (argtypes == NULL_TREE
>      || !same_type_p (TREE_VALUE (argtypes), TREE_TYPE (value)))
>
>> +  if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE)
>> +    {
>> +      if (argtypes != NULL_TREE
>> + && TREE_CODE (TREE_VALUE (argtypes)) == REAL_TYPE)
>> +    {
>> +      error ("unable to find %qD with %<unsigned long long int%> 
>> argument",
>> +         name);
>> +      return error_mark_node;
>> +    }
>> +    }
>> +  else if (TREE_CODE (TREE_TYPE (value)) == REAL_TYPE)
>> +    {
>> +      if (argtypes != NULL_TREE
>> + && TREE_CODE (TREE_VALUE (argtypes)) == INTEGER_TYPE)
>> +    {
>> +      error ("unable to find %qD with %<long double%> argument", name);
>> +      return error_mark_node;
>> +    }
>> +    }
>
> This looks like it will break raw operators.
>
> Jason
>
Here is a new patch that I think addresses these issues.
Basically, I am looping through all operators with the required suffix 
and looking for a perfectly matching argument for the given literal.

There are two issues.  One I think is just dg.  There are two FAILs but 
the error message comes out like I think it should.  I attached the sum 
and the log.  This is in udlit-implicit-conv-neg.C.  I tried for the 
life of me to copy the exact message from the terminal.  All the others 
work.

Also, as seen in udlit-resolve.C the version of an operator brought in 
by using a namespaced operator will win.

Ed
2011-10-30  Ed Smith-Rowland  <3dw4rd@verizon.net>

	gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg.C: New.
	gcc/testsuite/g++.dg/cpp0x/udlit-resolve.C: New.

	gcc/cp/parser.c: (cp_parser_userdef_char_literal,
	cp_parser_userdef_numeric_literal, cp_parser_userdef_string_literal):
	Loop through the possible functions looking for exact argument type
	matches to resolve literal operator call.  Use lookup_name instead of
	lookup_function_nonclass.

	libcpp/expr.c: (cpp_userdef_char_remove_type): Fix boneheaded paste-o.

Comments

Jason Merrill Oct. 31, 2011, 3:56 p.m. UTC | #1
On 10/30/2011 01:13 PM, Ed Smith-Rowland wrote:
> +  /* Look for a literal operator taking the exact type of numeric argument
> +     as the literal value.  */

Is this right?  Do numeric literals only get here with type unsigned 
long long or long double?

> +  while (fns)
>      {
>        tree tmpl_args = make_char_string_pack (num_string);
> -      decl = lookup_template_function (decl, tmpl_args);
> -      result = finish_call_expr (decl, &args, false, true, tf_none);
> -      if (result != error_mark_node)
> +      tree fn = OVL_CURRENT (fns);
> +      tree argtypes = NULL_TREE;
> +      if (TREE_CODE (TREE_TYPE (fn)) != LANG_TYPE)
> +	argtypes = TYPE_ARG_TYPES (TREE_TYPE (fn));
> +      if (argtypes != NULL_TREE
> +	  && same_type_p (TREE_VALUE (argtypes), void_type_node))

Let's wait to make the pack until we find a template.  Also, you should 
be able to just check for TEMPLATE_DECL since we won't accept a literal 
operator template with different parameter types.

For string and character literals, we can still just build up a call; we 
only need to walk the overload list here for numeric literals.

Jason
diff mbox

Patch

Index: gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg.C	(revision 0)
@@ -0,0 +1,59 @@ 
+// { dg-options -std=c++0x }
+
+#include <cstdint>
+
+int operator"" _bar (long double);
+
+double operator"" _foo (long long unsigned);
+
+int i = 12_bar; // { dg-error "unable to find numeric literal operator|with|argument" }
+
+double d = 1.2_foo; // { dg-error "unable to find numeric literal operator|with|argument" }
+
+int operator"" _char(char);
+
+int operator"" _wchar_t(wchar_t);
+
+int operator"" _char16_t(char16_t);
+
+int operator"" _char32_t(char32_t);
+
+int cwc = 'c'_wchar_t; // { dg-error "unable to find character literal operator|with|argument" }
+int cc16 = 'c'_char16_t; // { dg-error "unable to find character literal operator|with|argument" }
+int cc32 = 'c'_char32_t; // { dg-error "unable to find character literal operator|with|argument" }
+
+int wcc = L'c'_char; // { dg-error "unable to find character literal operator|with|argument" }
+int wcc16 = L'c'_char16_t; // { dg-error "unable to find character literal operator|with|argument" }
+int wcc32 = L'c'_char32_t; // { dg-error "unable to find character literal operator|with|argument" }
+
+int c16c = u'c'_char; // { dg-error "unable to find character literal operator|with|argument" }
+int c16wc = u'c'_wchar_t; // { dg-error "unable to find character literal operator|with|argument" }
+int c16c32 = u'c'_char32_t; // { dg-error "unable to find character literal operator|with|argument" }
+
+int c32c = U'c'_char; // { dg-error "unable to find character literal operator|with|argument" }
+int c32wc = U'c'_wchar_t; // { dg-error "unable to find character literal operator|with|argument" }
+int c32c16 = U'c'_char16_t; // { dg-error "unable to find character literal operator|with|argument" }
+
+int operator"" _char_str(const char*, std::size_t);
+
+int operator"" _wchar_t_str(const wchar_t*, std::size_t);
+
+int operator"" _char16_t_str(const char16_t*, std::size_t);
+
+int operator"" _char32_t_str(const char32_t*, std::size_t);
+
+int strwstr = "str"_wchar_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int strstr16 = "str"_char16_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int strstr32 = "str"_char32_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+
+int wstrstr = L"str"_char_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int wstrstr16 = L"str"_char16_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int wstrstr32 = L"str"_char32_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+
+int str16str = u"str"_char_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str16wstr = u"str"_wchar_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str16str32 = u"str"_char32_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+
+int str32str = U"str"_char_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str32wstr = U"str"_wchar_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str32str16 = U"str"_char16_t_str; // { dg-error "unable to find string literal operator string operator|with|arguments" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-resolve.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-resolve.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-resolve.C	(revision 0)
@@ -0,0 +1,43 @@ 
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+#include <cstdint>
+#include <cassert>
+
+int operator"" _foo(const char*)                  { return 0; }
+int operator"" _foo(unsigned long long int)       { return 1; }
+int operator"" _foo(long double)                  { return 2; }
+int operator"" _foo(char)                         { return 3; }
+int operator"" _foo(wchar_t)                      { return 4; }
+int operator"" _foo(char16_t)                     { return 5; }
+int operator"" _foo(char32_t)                     { return 6; }
+int operator"" _foo(const char*, std::size_t)     { return 7; }
+int operator"" _foo(const wchar_t*, std::size_t)  { return 8; }
+int operator"" _foo(const char16_t*, std::size_t) { return 9; }
+int operator"" _foo(const char32_t*, std::size_t) { return 10; }
+template<char...> int operator"" _foo2()          { return 20; }
+int operator"" _foo2(unsigned long long int)      { return 21; }
+
+namespace bar {
+int operator"" _foo(unsigned long long int)       { return 101; }
+}
+using namespace bar;
+
+int
+main()
+{
+  //assert(123_foo == 0);
+  //assert(123_foo == 1);
+  assert(123_foo == 101);
+  assert(0.123_foo == 2);
+  assert('c'_foo == 3);
+  assert(L'c'_foo == 4);
+  assert(u'c'_foo == 5);
+  assert(U'c'_foo == 6);
+  assert("abc"_foo == 7);
+  assert(L"abc"_foo == 8);
+  assert(u"abc"_foo == 9);
+  assert(U"abc"_foo == 10);
+  assert(123_foo2 == 21);
+  //assert(_foo == );
+}
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 180680)
+++ gcc/cp/parser.c	(working copy)
@@ -3532,9 +3532,7 @@ 
 {
   cp_token *token = NULL;
   tree literal, suffix_id, value;
-  tree name, decl;
-  tree result;
-  VEC(tree,gc) *vec;
+  tree name, decl, fns;
 
   token = cp_lexer_consume_token (parser->lexer);
   literal = token->u.value;
@@ -3544,20 +3542,37 @@ 
 
   /* Build up a call to the user-defined operator  */
   /* Lookup the name we got back from the id-expression.  */
-  vec = make_tree_vector ();
-  VEC_safe_push (tree, gc, vec, value);
-  decl = lookup_function_nonclass (name, vec, /*block_p=*/false);
+  decl = lookup_name (name);
   if (!decl || decl == error_mark_node)
     {
       error ("unable to find user-defined character literal operator %qD",
 	     name);
-      release_tree_vector (vec);
       return error_mark_node;
     }
-  result = finish_call_expr (decl, &vec, false, true, tf_warning_or_error);
-  release_tree_vector (vec);
+  fns = decl;
+  while (fns)
+    {
+      tree fn = OVL_CURRENT (fns);
+      tree argtypes = NULL_TREE;
+      if (TREE_CODE (TREE_TYPE (fn)) != LANG_TYPE)
+	argtypes = TYPE_ARG_TYPES (TREE_TYPE (fn));
+      if (argtypes != NULL_TREE
+	  && same_type_p (TREE_VALUE (argtypes), TREE_TYPE (value)))
+	{
+          tree result;
+          VEC(tree,gc) *vec = make_tree_vector ();
+          VEC_safe_push (tree, gc, vec, value);
+	  result = finish_call_expr (fn, &vec, false, true, tf_warning_or_error);
+	  release_tree_vector (vec);
+	  if (result != error_mark_node)
+	    return result;
+	}
+      fns = OVL_NEXT (fns);
+    }
 
-  return result;
+  error ("unable to find character literal operator %qD with %qT argument",
+	 name, TREE_TYPE (value));
+  return error_mark_node;
 }
 
 /* A subroutine of cp_parser_userdef_numeric_literal to
@@ -3594,9 +3609,7 @@ 
 {
   cp_token *token = NULL;
   tree literal, suffix_id, value, num_string;
-  tree name, decl;
-  tree result = error_mark_node;
-  VEC(tree,gc) *args;
+  tree name, decl, fns;
 
   token = cp_lexer_consume_token (parser->lexer);
   literal = token->u.value;
@@ -3605,63 +3618,87 @@ 
   num_string = USERDEF_LITERAL_NUM_STRING (literal);
   name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
 
-  /* Build up a call to the user-defined operator  */
-  /* Lookup the name we got back from the id-expression.  */
-  /* Try to find the literal operator by finishing the call expression
-     with the numeric argument.  */
-  args = make_tree_vector ();
-  VEC_safe_push (tree, gc, args, value);
-  decl = lookup_function_nonclass (name, args, /*block_p=*/false);
-  if (decl && decl != error_mark_node)
+  decl = lookup_name (name);
+  if (!decl || decl == error_mark_node)
     {
-      result = finish_call_expr (decl, &args, false, true, tf_none);
-      if (result != error_mark_node)
+      error ("unable to find user-defined numeric literal operator %qD", name);
+      return error_mark_node;
+    }
+
+  /* Look for a literal operator taking the exact type of numeric argument
+     as the literal value.  */
+  fns = decl;
+  while (fns)
+    {
+      tree fn = OVL_CURRENT (fns);
+      tree argtypes = NULL_TREE;
+      if (TREE_CODE (TREE_TYPE (fn)) != LANG_TYPE)
+	argtypes = TYPE_ARG_TYPES (TREE_TYPE (fn));
+      if (argtypes != NULL_TREE
+	  && same_type_p (TREE_VALUE (argtypes), TREE_TYPE (value)))
 	{
+          tree result;
+	  VEC(tree,gc) *args = make_tree_vector ();
+	  VEC_safe_push (tree, gc, args, value);
+	  result = finish_call_expr (fn, &args, false, true, tf_none);
 	  release_tree_vector (args);
-	  return result;
+	  if (result != error_mark_node)
+	    return result;
 	}
+      fns = OVL_NEXT (fns);
     }
-  release_tree_vector (args);
 
   /* If the numeric argument didn't work, look for a raw literal
      operator taking a const char* argument consisting of the number
      in string format.  */
-  args = make_tree_vector ();
-  VEC_safe_push (tree, gc, args, num_string);
-  decl = lookup_function_nonclass (name, args, /*block_p=*/false);
-  if (decl && decl != error_mark_node)
+  fns = decl;
+  while (fns)
     {
-      result = finish_call_expr (decl, &args, false, true, tf_none);
-      if (result != error_mark_node)
+      tree fn = OVL_CURRENT (fns);
+      tree argtypes = NULL_TREE;
+      if (TREE_CODE (TREE_TYPE (fn)) != LANG_TYPE)
+	argtypes = TYPE_ARG_TYPES (TREE_TYPE (fn));
+      if (argtypes != NULL_TREE
+	  && same_type_p (TREE_VALUE (argtypes), const_string_type_node))
 	{
+          tree result;
+	  VEC(tree,gc) *args = make_tree_vector ();
+	  VEC_safe_push (tree, gc, args, num_string);
+	  result = finish_call_expr (fn, &args, false, true, tf_none);
 	  release_tree_vector (args);
-	  return result;
+	  if (result != error_mark_node)
+	    return result;
 	}
+      fns = OVL_NEXT (fns);
     }
-  release_tree_vector (args);
 
   /* If the raw literal didn't work, look for a non-type template
      function with parameter pack char....  Call the function with
      template parameter characters representing the number.  */
-  args = make_tree_vector ();
-  decl = lookup_function_nonclass (name, args, /*block_p=*/false);
-  if (decl && decl != error_mark_node)
+  fns = decl;
+  while (fns)
     {
       tree tmpl_args = make_char_string_pack (num_string);
-      decl = lookup_template_function (decl, tmpl_args);
-      result = finish_call_expr (decl, &args, false, true, tf_none);
-      if (result != error_mark_node)
+      tree fn = OVL_CURRENT (fns);
+      tree argtypes = NULL_TREE;
+      if (TREE_CODE (TREE_TYPE (fn)) != LANG_TYPE)
+	argtypes = TYPE_ARG_TYPES (TREE_TYPE (fn));
+      if (argtypes != NULL_TREE
+	  && same_type_p (TREE_VALUE (argtypes), void_type_node))
 	{
+	  tree result;
+	  VEC(tree,gc) *args = make_tree_vector ();
+	  fn = lookup_template_function (fn, tmpl_args);
+	  result = finish_call_expr (fn, &args, false, true, tf_none);
 	  release_tree_vector (args);
-	  return result;
+	  if (result != error_mark_node)
+	    return result;
 	}
+      fns = OVL_NEXT (fns);
     }
-  release_tree_vector (args);
 
-  if (result == error_mark_node)
-    error ("unable to find user-defined numeric literal operator %qD", name);
-
-  return result;
+  error ("unable to find numeric literal operator %qD", name);
+  return error_mark_node;
 }
 
 /* Parse a user-defined string constant.  Returns a call to a user-defined
@@ -3671,38 +3708,60 @@ 
 static tree
 cp_parser_userdef_string_literal (cp_token *token)
 {
-  tree literal, suffix_id, value;
-  tree name, decl;
-  tree result;
-  VEC(tree,gc) *vec;
-  int len;
+  tree literal = token->u.value;
+  tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+  tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+  tree value = USERDEF_LITERAL_VALUE (literal);
+  int len = TREE_STRING_LENGTH (value) - 1;
+  tree fns;
+  bool have_size = false;
 
-  literal = token->u.value;
-  suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
-  name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
-  value = USERDEF_LITERAL_VALUE (literal);
-  len = TREE_STRING_LENGTH (value) - 1;
-
   /* Build up a call to the user-defined operator  */
   /* Lookup the name we got back from the id-expression.  */
-  vec = make_tree_vector ();
-  VEC_safe_push (tree, gc, vec, value);
-  VEC_safe_push (tree, gc, vec, build_int_cst (size_type_node, len));
-  decl = lookup_function_nonclass (name, vec, /*block_p=*/false);
+  tree decl = lookup_name (name);
   if (!decl || decl == error_mark_node)
     {
       error ("unable to find user-defined string literal operator %qD", name);
-      release_tree_vector (vec);
       return error_mark_node;
     }
-  result = finish_call_expr (decl, &vec, false, true, tf_none);
-  if (result == error_mark_node)
+  fns = decl;
+  while (fns)
+    {
+      tree fn = OVL_CURRENT (fns);
+      tree argtypes = NULL_TREE;
+      if (TREE_CODE (TREE_TYPE (fn)) != LANG_TYPE)
+	argtypes = TYPE_ARG_TYPES (TREE_TYPE (fn));
+      if (argtypes != NULL_TREE && TREE_CHAIN (argtypes) != NULL_TREE)
+	{
+	  tree tsize = TREE_CHAIN (argtypes);
+	  if (tsize && same_type_p (TREE_VALUE (tsize), size_type_node))
+	    have_size = true;
+	  if (TREE_CODE (TREE_VALUE (argtypes)) == POINTER_TYPE
+	      && same_type_p (TREE_TYPE (TREE_VALUE (argtypes)),
+			      TREE_TYPE (TREE_TYPE (value))))
+	    {
+	      tree result;
+	      VEC(tree,gc) *vec = make_tree_vector ();
+	      VEC_safe_push (tree, gc, vec, value);
+	      VEC_safe_push (tree, gc, vec,
+			     build_int_cst (size_type_node, len));
+	      result = finish_call_expr (fn, &vec, false, true, tf_none);
+	      release_tree_vector (vec);
+	      if (result != error_mark_node)
+		return result;
+	    }
+	}
+      fns = OVL_NEXT (fns);
+    }
+
+  if (have_size)
+    error ("unable to find string literal operator %qD with %qT, %qT arguments",
+	   name, TREE_TYPE (value), size_type_node);
+  else
     error ("unable to find valid user-defined string literal operator %qD."
 	   "  Possible missing length argument in string literal operator.",
 	   name);
-  release_tree_vector (vec);
-
-  return result;
+  return error_mark_node;
 }
 
 
Index: libcpp/expr.c
===================================================================
--- libcpp/expr.c	(revision 180680)
+++ libcpp/expr.c	(working copy)
@@ -284,9 +284,9 @@ 
   else if (type == CPP_WCHAR_USERDEF)
     return CPP_WCHAR;
   else if (type == CPP_CHAR16_USERDEF)
-    return CPP_STRING16;
+    return CPP_CHAR16;
   else if (type == CPP_CHAR32_USERDEF)
-    return CPP_STRING32;
+    return CPP_CHAR32;
   else
     return type;
 }