diff mbox

PR C++/60209 - Declaration of user-defined literal operator cause error

Message ID 53B599D0.4040104@verizon.net
State New
Headers show

Commit Message

Ed Smith-Rowland July 3, 2014, 5:58 p.m. UTC
Support operator"" ""(...) per CWG 1473.

I'll be AFK over the holiday.

Bootstrapped and tested on x86_64-linux.

OK?

I'm less sure if this is appropriate for 4.9.

cp/
	
2014-07-03  Edward Smith-Rowland  <3dw4rd@verizon.net>

	PR C++/60209 - Declaration of user-defined literal operator cause error
	* cp/parser.c (cp_parser_operator()): Fold treatment of strings
	and user-defined string literals.  Use the full string parser.
	(cp_parser_string_literal()): Add flag to not look for literal operator.


testsuite/
	
2014-07-03  Edward Smith-Rowland  <3dw4rd@verizon.net>

	PR C++/60209 - Declaration of user-defined literal operator cause error
	* g++.dg/cpp0x/pr60209-neg.C: New.
	* g++.dg/cpp0x/pr60209.C: New.
	* g++.dg/cpp1y/udlit-empty-string-neg.C: Adjust messages.
diff mbox

Patch

Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 212248)
+++ cp/parser.c	(working copy)
@@ -1895,7 +1895,7 @@ 
 static tree cp_parser_identifier
   (cp_parser *);
 static tree cp_parser_string_literal
-  (cp_parser *, bool, bool);
+  (cp_parser *, bool, bool, bool);
 static tree cp_parser_userdef_char_literal
   (cp_parser *);
 static tree cp_parser_userdef_string_literal
@@ -3566,7 +3566,8 @@ 
 
    FUTURE: ObjC++ will need to handle @-strings here.  */
 static tree
-cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
+cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
+			  bool lookup_udlit = true)
 {
   tree value;
   size_t count;
@@ -3721,7 +3722,10 @@ 
 	{
 	  tree literal = build_userdef_literal (suffix_id, value,
 						OT_NONE, NULL_TREE);
-	  value = cp_parser_userdef_string_literal (literal);
+	  if (lookup_udlit)
+	    value = cp_parser_userdef_string_literal (literal);
+	  else
+	    value = literal;
 	}
     }
   else
@@ -12635,7 +12639,7 @@ 
 {
   tree id = NULL_TREE;
   cp_token *token;
-  bool bad_encoding_prefix = false;
+  bool utf8 = false;
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
@@ -12835,83 +12839,73 @@ 
       cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
       return ansi_opname (ARRAY_REF);
 
+    case CPP_UTF8STRING:
+    case CPP_UTF8STRING_USERDEF:
+      utf8 = true;
+    case CPP_STRING:
     case CPP_WSTRING:
     case CPP_STRING16:
     case CPP_STRING32:
-    case CPP_UTF8STRING:
-     bad_encoding_prefix = true;
-      /* Fall through.  */
-
-    case CPP_STRING:
-      if (cxx_dialect == cxx98)
-	maybe_warn_cpp0x (CPP0X_USER_DEFINED_LITERALS);
-      if (bad_encoding_prefix)
-	{
-	  error ("invalid encoding prefix in literal operator");
-	  return error_mark_node;
-	}
-      if (TREE_STRING_LENGTH (token->u.value) > 2)
-	{
-	  error ("expected empty string after %<operator%> keyword");
-	  return error_mark_node;
-	}
-      /* Consume the string.  */
-      cp_lexer_consume_token (parser->lexer);
-      /* Look for the suffix identifier.  */
-      token = cp_lexer_peek_token (parser->lexer);
-      if (token->type == CPP_NAME)
-	{
-	  id = cp_parser_identifier (parser);
-	  if (id != error_mark_node)
-	    {
-	      const char *name = IDENTIFIER_POINTER (id);
-	      return cp_literal_operator_id (name);
-	    }
-	}
-      else if (token->type == CPP_KEYWORD)
-	{
-	  error ("unexpected keyword;"
-		 " remove space between quotes and suffix identifier");
-	  return error_mark_node;
-	}
-      else
-	{
-	  error ("expected suffix identifier");
-	  return error_mark_node;
-	}
-
+    case CPP_STRING_USERDEF:
     case CPP_WSTRING_USERDEF:
     case CPP_STRING16_USERDEF:
     case CPP_STRING32_USERDEF:
-    case CPP_UTF8STRING_USERDEF:
-      bad_encoding_prefix = true;
-      /* Fall through.  */
+      {
+	tree str, string_tree;
+	int sz, len;
 
-    case CPP_STRING_USERDEF:
-      if (cxx_dialect == cxx98)
-	maybe_warn_cpp0x (CPP0X_USER_DEFINED_LITERALS);
-      if (bad_encoding_prefix)
-	{
-	  error ("invalid encoding prefix in literal operator");
+	if (cxx_dialect == cxx98)
+	  maybe_warn_cpp0x (CPP0X_USER_DEFINED_LITERALS);
+
+	/* Consume the string.  */
+	str = cp_parser_string_literal (parser, /*translate=*/true,
+				      /*wide_ok=*/true, /*lookup_udlit=*/false);
+	if (str == error_mark_node)
 	  return error_mark_node;
-	}
-      {
-	tree string_tree = USERDEF_LITERAL_VALUE (token->u.value);
-	if (TREE_STRING_LENGTH (string_tree) > 2)
+	else if (TREE_CODE (str) == USERDEF_LITERAL)
 	  {
+	    string_tree = USERDEF_LITERAL_VALUE (str);
+	    id = USERDEF_LITERAL_SUFFIX_ID (str);
+	  }
+	else
+	  {
+	    string_tree = str;
+	    /* Look for the suffix identifier.  */
+	    token = cp_lexer_peek_token (parser->lexer);
+	    if (token->type == CPP_NAME)
+	      id = cp_parser_identifier (parser);
+	    else if (token->type == CPP_KEYWORD)
+	      {
+		error ("unexpected keyword;"
+		       " remove space between quotes and suffix identifier");
+		return error_mark_node;
+	      }
+	    else
+	      {
+		error ("expected suffix identifier");
+		return error_mark_node;
+	      }
+	  }
+	sz = TREE_INT_CST_LOW (TYPE_SIZE_UNIT
+			       (TREE_TYPE (TREE_TYPE (string_tree))));
+	len = TREE_STRING_LENGTH (string_tree) / sz - 1;
+	if (len != 0)
+	  {
 	    error ("expected empty string after %<operator%> keyword");
 	    return error_mark_node;
 	  }
-	id = USERDEF_LITERAL_SUFFIX_ID (token->u.value);
-	/* Consume the user-defined string literal.  */
-	cp_lexer_consume_token (parser->lexer);
+	if (utf8 || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (string_tree)))
+	    != char_type_node)
+	  {
+	    error ("invalid encoding prefix in literal operator");
+	    return error_mark_node;
+	  }
 	if (id != error_mark_node)
 	  {
 	    const char *name = IDENTIFIER_POINTER (id);
-	    return cp_literal_operator_id (name);
+	    id = cp_literal_operator_id (name);
 	  }
-	else
-	  return error_mark_node;
+	return id;
       }
 
     default:
Index: testsuite/g++.dg/cpp0x/pr60209-neg.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr60209-neg.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/pr60209-neg.C	(working copy)
@@ -0,0 +1,28 @@ 
+// PR c++/60209
+// { dg-do compile { target c++11 } }
+
+// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1473
+
+void operator "" "boo" _ya(unsigned long long); // { dg-error "expected empty string after" }
+
+void operator "" "boo"_ya(unsigned long long); // { dg-error "expected empty string after" }
+
+void operator "" u"" _u(unsigned long long); // { dg-error "invalid encoding prefix in literal operator" }
+
+void operator u"" "" _v(unsigned long long); // { dg-error "invalid encoding prefix in literal operator" }
+
+void operator U"" "" _w(unsigned long long); // { dg-error "invalid encoding prefix in literal operator" }
+
+void operator L"" "" _x(unsigned long long); // { dg-error "invalid encoding prefix in literal operator" }
+
+void operator u8"" "" _y(unsigned long long); // { dg-error "invalid encoding prefix in literal operator" }
+
+void operator u"" L"" _z(unsigned long long); // { dg-error "unsupported non-standard concatenation of string literals" }
+
+void operator ""_p ""_q(unsigned long long); // { dg-error "inconsistent user-defined literal suffixes" }
+
+void operator "" "" while(unsigned long long); // { dg-error "unexpected keyword; remove space between quotes and suffix identifier" }
+
+void operator "" ""(unsigned long long); // { dg-error "expected suffix identifier" }
+
+// { dg-error "invalid encoding prefix in literal operator" "invalid" { target *-*-* } 20 }
Index: testsuite/g++.dg/cpp0x/pr60209.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr60209.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/pr60209.C	(working copy)
@@ -0,0 +1,12 @@ 
+// PR c++/60209
+// { dg-do compile { target c++11 } }
+
+// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1473
+
+void operator "" "" _x(unsigned long long);
+
+void operator "" "" "" _x(unsigned long long);
+
+void operator "" ""_w(unsigned long long);
+
+void operator "" ""_w ""(unsigned long long);
Index: testsuite/g++.dg/cpp1y/udlit-empty-string-neg.C
===================================================================
--- testsuite/g++.dg/cpp1y/udlit-empty-string-neg.C	(revision 212248)
+++ testsuite/g++.dg/cpp1y/udlit-empty-string-neg.C	(working copy)
@@ -5,17 +5,17 @@ 
 { return 0; }
 
 int
-operator L"*"_Ls(unsigned long long) // { dg-error "invalid encoding prefix in literal operator" }
+operator L"*"_Ls(unsigned long long) // { dg-error "expected empty string after 'operator'" }
 { return 0; }
 
 int
-operator u"*"_s16(unsigned long long) // { dg-error "invalid encoding prefix in literal operator" }
+operator u"*"_s16(unsigned long long) // { dg-error "expected empty string after 'operator'" }
 { return 0; }
 
 int
-operator U"*"_s32(unsigned long long) // { dg-error "invalid encoding prefix in literal operator" }
+operator U"*"_s32(unsigned long long) // { dg-error "expected empty string after 'operator'" }
 { return 0; }
 
 int
-operator u8"*"_u8s(unsigned long long) // { dg-error "invalid encoding prefix in literal operator" }
+operator u8"*"_u8s(unsigned long long) // { dg-error "expected empty string after 'operator'" }
 { return 0; }