diff mbox

[C++] PR 50958 and correct lookup of literal operators

Message ID 4EB9EB6C.1010207@verizon.net
State New
Headers show

Commit Message

Ed Smith-Rowland Nov. 9, 2011, 2:54 a.m. UTC
Ping...
Sorry I forgot to cc you.
I needed rebase anyhow after all the churn recently.

Also, I started a food fight with 
http://gcc.gnu.org/ml/gcc/2011-11/msg00124.html.
My idea was that if C++ explicitly does not use the fixed point suffixes 
then, in C++11 mode, we should pass them along as user-defined literals.
I think the point was lost ;-).  But what would you say to a three-liner 
and a test case?  And the idea?

Ed

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

	* gcc/testsuite/g++.dg/cpp0x/udlit-raw-length.C: New.
	* gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg.C: New.
	* gcc/testsuite/g++.dg/cpp0x/udlit-resolve.C: New.
	* gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C: Adjust error message.
	* gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C: Ditto.
	* gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C: Ditto.

	* gcc/cp/parser.c: (lookup_literal_operator): New to correct lookup of
	literal operators.
	(cp_parser_userdef_char_literal, cp_parser_userdef_numeric_literal,
	cp_parser_userdef_string_literal): Use it.

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

Comments

Jason Merrill Nov. 9, 2011, 3:06 a.m. UTC | #1
On 11/08/2011 09:54 PM, Ed Smith-Rowland wrote:
> My idea was that if C++ explicitly does not use the fixed point suffixes
> then, in C++11 mode, we should pass them along as user-defined literals.

I don't think so.  Those suffixes are reserved to the implementation anyway.

I'll look at the patch now.

Jason
Jason Merrill Nov. 9, 2011, 5:15 a.m. UTC | #2
On 11/08/2011 09:54 PM, Ed Smith-Rowland wrote:
> +      if (TREE_CODE (TREE_TYPE (fn)) != LANG_TYPE)

You don't need to check this, since OVL_CURRENT always gives a function.

It seems like a lot of the complexity of lookup_literal_operator is for 
dealing with string literals, which is the case where we don't need to 
look at the parameter types anyway; we can just build a call.  2.14.8/5 
doesn't say anything about the overload set.

It also looks like lookup_literal_operator called with no arguments 
(i.e. for the template case of numeric literals) will just return the 
first function in the overload set, which may not be right.

Jason
diff mbox

Patch

Index: gcc/testsuite/g++.dg/cpp0x/udlit-raw-length.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-raw-length.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-raw-length.C	(revision 0)
@@ -0,0 +1,27 @@ 
+// { dg-options "-std=c++0x" }
+// PR c++/50958
+
+typedef decltype(sizeof(0)) size_type;
+
+constexpr size_type
+cstrlen_impl(const char* s, size_type i)
+{
+  return s[i] ? cstrlen_impl(s, i + 1) : i;
+}
+
+constexpr size_type
+cstrlen(const char* s)
+{
+  return s ? cstrlen_impl(s, 0) : throw 0;
+}
+
+constexpr size_type
+operator "" _lenraw(const char* digits)
+{
+  return cstrlen(digits);
+}
+
+static_assert(123_lenraw == 3, "Ouch");
+static_assert(1_lenraw == 1, "Ouch");
+static_assert(012_lenraw == 3, "Ouch");
+static_assert(0_lenraw == 1, "Ouch");
Index: gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C	(revision 181180)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C	(working copy)
@@ -5,4 +5,4 @@ 
 int operator"" _embedraw(const char*)
 { return 41; };
 
-int k = "Boo!"_embedraw;  //  { dg-error "unable to find valid user-defined string literal operator" }
+int k = "Boo!"_embedraw;  //  { dg-error "unable to find valid string literal operator" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C	(revision 181180)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C	(working copy)
@@ -8,7 +8,7 @@ 
 };
 
 int i = operator"" _Bar(U'x');  // { dg-error "was not declared in this scope" }
-int j = U'x'_Bar;  // { dg-error "unable to find user-defined character literal operator" }
+int j = U'x'_Bar;  // { dg-error "unable to find character literal operator" }
 
 int
 Foo::operator"" _Bar(char32_t)  // { dg-error "must be a non-member function" }
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,63 @@ 
+// { 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 cwcx = '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 wccx = 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 str8wstr = u8"str"_wchar_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str8str16 = u8"str"_char16_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str8str32 = u8"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/testsuite/g++.dg/cpp0x/udlit-declare-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C	(revision 181180)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C	(working copy)
@@ -3,13 +3,13 @@ 
 //  Check that undeclared literal operator calls and literals give appropriate errors.
 
 int i = operator"" _Bar('x');  // { dg-error "was not declared in this scope" }
-int j = 'x'_Bar;  // { dg-error "unable to find user-defined character literal operator" }
+int j = 'x'_Bar;  // { dg-error "unable to find character literal operator" }
 
 int ii = operator"" _BarCharStr("Howdy, Pardner!");  // { dg-error "was not declared in this scope" }
-int jj = "Howdy, Pardner!"_BarCharStr;  // { dg-error "unable to find user-defined string literal operator" }
+int jj = "Howdy, Pardner!"_BarCharStr;  // { dg-error "unable to find valid string literal operator" }
 
 unsigned long long iULL = operator"" _BarULL(666ULL);  // { dg-error "was not declared in this scope" }
-unsigned long long jULL = 666_BarULL;  // { dg-error "unable to find user-defined numeric literal operator" }
+unsigned long long jULL = 666_BarULL;  // { dg-error "unable to find numeric literal operator" }
 
 long double iLD = operator"" _BarLD(666.0L);  // { dg-error "was not declared in this scope" }
-long double jLD = 666.0_BarLD;  // { dg-error "unable to find user-defined numeric literal operator" }
+long double jLD = 666.0_BarLD;  // { dg-error "unable to find numeric literal operator" }
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 181180)
+++ gcc/cp/parser.c	(working copy)
@@ -3547,40 +3547,86 @@ 
   return value;
 }
 
+/* Look up a literal operator with the name and the exact arguments.  */
+
+static tree
+lookup_literal_operator(tree name, VEC(tree,gc) *args, bool *have_size)
+{
+  tree decl, fns;
+  if (have_size)
+    *have_size = false;
+  decl = lookup_name (name);
+  if (!decl || decl == error_mark_node)
+    return error_mark_node;
+
+  for (fns = decl; fns; fns = OVL_NEXT (fns))
+    {
+      unsigned int ix;
+      bool found = true;
+      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)
+	{
+	  for (ix = 0; ix < VEC_length (tree, args) && argtypes != NULL_TREE;
+	       ++ix, argtypes = TREE_CHAIN (argtypes))
+	    {
+	      bool ptr = TREE_CODE (TREE_VALUE (argtypes)) == POINTER_TYPE;
+	      bool arr = TREE_CODE (TREE_TYPE (VEC_index (tree, args, ix)))
+			 == ARRAY_TYPE;
+	      if ((ptr || arr
+		     || !same_type_p (TREE_VALUE (argtypes),
+				     TREE_TYPE (VEC_index (tree, args, ix))))
+		  && (!ptr || !arr
+		      || !same_type_p (TREE_TYPE (TREE_VALUE (argtypes)),
+			   TREE_TYPE (TREE_TYPE (VEC_index (tree, args, ix))))))
+		found = false;
+	      if (have_size && ix == 1
+		  && same_type_p (TREE_VALUE (argtypes), size_type_node))
+		*have_size = true;
+	    }
+	  if (found)
+	    return fn;
+	}
+    }
+
+  return error_mark_node;
+}
+
 /* Parse a user-defined char constant.  Returns a call to a user-defined
    literal operator taking the character as an argument.  */
 
 static tree
 cp_parser_userdef_char_literal (cp_parser *parser)
 {
-  cp_token *token = NULL;
-  tree literal, suffix_id, value;
-  tree name, decl;
-  tree result;
-  VEC(tree,gc) *vec;
+  cp_token *token = cp_lexer_consume_token (parser->lexer);
+  tree literal = token->u.value;
+  tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+  tree value = USERDEF_LITERAL_VALUE (literal);
+  tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+  tree decl, result;
 
-  token = cp_lexer_consume_token (parser->lexer);
-  literal = token->u.value;
-  suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
-  value = USERDEF_LITERAL_VALUE (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.  */
-  vec = make_tree_vector ();
-  VEC_safe_push (tree, gc, vec, value);
-  decl = lookup_function_nonclass (name, vec, /*block_p=*/false);
+  VEC(tree,gc) *args = make_tree_vector ();
+  VEC_safe_push (tree, gc, args, value);
+  decl = lookup_literal_operator(name, args, NULL);
   if (!decl || decl == error_mark_node)
     {
-      error ("unable to find user-defined character literal operator %qD",
-	     name);
-      release_tree_vector (vec);
+      error ("unable to find character literal operator %qD with %qT argument",
+	     name, TREE_TYPE (value));
+      release_tree_vector (args);
       return error_mark_node;
     }
-  result = finish_call_expr (decl, &vec, false, true, tf_warning_or_error);
-  release_tree_vector (vec);
+  result = finish_call_expr (decl, &args, false, true, tf_warning_or_error);
+  release_tree_vector (args);
+  if (result != error_mark_node)
+    return result;
 
-  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
@@ -3615,26 +3661,20 @@ 
 static tree
 cp_parser_userdef_numeric_literal (cp_parser *parser)
 {
-  cp_token *token = NULL;
-  tree literal, suffix_id, value, num_string;
-  tree name, decl;
-  tree result = error_mark_node;
+  cp_token *token = cp_lexer_consume_token (parser->lexer);
+  tree literal = token->u.value;
+  tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+  tree value = USERDEF_LITERAL_VALUE (literal);
+  tree num_string = USERDEF_LITERAL_NUM_STRING (literal);
+  tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+  tree decl, result;
   VEC(tree,gc) *args;
 
-  token = cp_lexer_consume_token (parser->lexer);
-  literal = token->u.value;
-  suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
-  value = USERDEF_LITERAL_VALUE (literal);
-  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.  */
+  /* Look for a literal operator taking the exact type of numeric argument
+     as the literal value.  */
   args = make_tree_vector ();
   VEC_safe_push (tree, gc, args, value);
-  decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+  decl = lookup_literal_operator (name, args, NULL);
   if (decl && decl != error_mark_node)
     {
       result = finish_call_expr (decl, &args, false, true, tf_none);
@@ -3651,7 +3691,7 @@ 
      in string format.  */
   args = make_tree_vector ();
   VEC_safe_push (tree, gc, args, num_string);
-  decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+  decl = lookup_literal_operator (name, args, NULL);
   if (decl && decl != error_mark_node)
     {
       result = finish_call_expr (decl, &args, false, true, tf_none);
@@ -3667,7 +3707,7 @@ 
      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);
+  decl = lookup_literal_operator (name, args, NULL);
   if (decl && decl != error_mark_node)
     {
       tree tmpl_args = make_char_string_pack (num_string);
@@ -3681,10 +3721,8 @@ 
     }
   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
@@ -3694,38 +3732,41 @@ 
 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)
+	/ TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (value)))) - 1;
+  bool have_size = false;
+  tree decl, result;
 
-  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)
-	/ TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (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);
+  VEC(tree,gc) *args = make_tree_vector ();
+  VEC_safe_push (tree, gc, args, value);
+  VEC_safe_push (tree, gc, args, build_int_cst (size_type_node, len));
+  decl = lookup_literal_operator (name, args, &have_size);
   if (!decl || decl == error_mark_node)
     {
-      error ("unable to find user-defined string literal operator %qD", name);
-      release_tree_vector (vec);
+      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 string literal operator %qD."
+	       "  Possible missing length argument in string literal operator.",
+	       name);
+      release_tree_vector (args);
       return error_mark_node;
     }
-  result = finish_call_expr (decl, &vec, false, true, tf_none);
-  if (result == error_mark_node)
-    error ("unable to find valid user-defined string literal operator %qD."
-	   "  Possible missing length argument in string literal operator.",
-	   name);
-  release_tree_vector (vec);
+  result = finish_call_expr (decl, &args, false, true, tf_none);
+  release_tree_vector (args);
+  if (result != error_mark_node)
+    return result;
 
-  return result;
+  error ("unable to find string literal operator %qD with %qT, %qT arguments",
+	 name, TREE_TYPE (value), size_type_node);
+  return error_mark_node;
 }
 
 
Index: libcpp/expr.c
===================================================================
--- libcpp/expr.c	(revision 181180)
+++ 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;
 }