[C++-11] User defined literals

Ed Smith-Rowland 3dw4rd@verizon.net
Mon Sep 19 08:33:00 GMT 2011


On 09/13/2011 09:52 PM, Jason Merrill wrote:
> Since we're starting to come up on the end of stage 1, I'll go ahead 
> and review the current patch even though it isn't finished yet.  
> Thanks for all your work on this, it definitely seems to be coming 
> together.
>
> On 09/13/2011 10:35 AM, Ed Smith-Rowland wrote:
>> +#define CPP_N_USERDEF  0x1000000 /* C++0x user-defned literal.  */
>
> "defined"
Done.
>
>> -extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *);
>> +extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *,
>> +                                    char **ud_suffix);
>> +
>> +/* Return the classification flags for a float suffix.  */
>> +unsigned int cpp_interpret_float_suffix (const char *s, size_t len);
>> +
>> +/* Return the classification flags for an int suffix.  */
>> +unsigned int cpp_interpret_int_suffix (const char *s, size_t len);
>>
>>  /* Evaluate a token classified as category CPP_N_INTEGER.  */
>>  extern cpp_num cpp_interpret_integer (cpp_reader *, const cpp_token *,
>
> Let's follow the pattern of the existing declarations by adding 
> explicit 'extern' and not naming the parameters.
Done.
>
>> @@ -327,6 +327,10 @@ pp_cxx_constant (cxx_pretty_printer *pp, tree t)
>> +    case USERDEF_LITERAL:
>> +      pp_c_constant (pp_c_base (pp), USERDEF_LITERAL_VALUE (t));
>> +      break;
>> @@ -1755,6 +1757,11 @@ dump_expr (tree t, int flags)
>> +    case USERDEF_LITERAL:
>> +      pp_constant (cxx_pp, USERDEF_LITERAL_VALUE (t));
>> +      dump_decl (USERDEF_LITERAL_SUFFIX_ID (t), flags);
>> +      break;
>
> These should be the same--or just call pp_cxx_constant from dump_expr.
Done, I think.
>
>> +/* Extract the suffix from a user-defined literal string or char.  */
>> +void
>> +cpp_get_userdef_suffix (cpp_string string, char delim, char *suffix)
>> +{
>> +  unsigned int len = string.len;
>> +  const char *text = (const char *)string.text;
>> +  int i;
>> +  for (i = len; i > 0; --i)
>> +    {
>> +      if (text[i - 1] == delim)
>> +       break;
>> +    }
>> +  strncpy (suffix, text + i, len - i);
>> +  suffix[len - i] = '\0';
>> +}
>
> Since you're just going to be passing the pointer to get_identifier 
> anyway, we don't need to copy the suffix into the pointer.  Just 
> return a pointer to the start of the suffix.
Done.
>
>> +             if (ud_suffix)
>> +               *ud_suffix = xstrdup ((const char *)str);
>
> Similarly here.
Done.
>
>> +             const char *curr_suffix = NULL;
>> +             suffix_id = USERDEF_LITERAL_SUFFIX_ID (tok->u.value);
>> +             curr_suffix = IDENTIFIER_POINTER (suffix_id);
>> +             if (have_suffix_p == 0)
>> +               {
>> +                 suffix = xstrdup (curr_suffix);
>> +                 have_suffix_p = 1;
>> +               }
>> +             else if (have_suffix_p == 1 && strcmp (suffix, 
>> curr_suffix) != 0)
>
> And here, you can compare the identifiers with ==, since identifiers 
> are unique.
Done.
>
>> +                 error ("inconsistent user-defined literal suffixes");
>
> Let's print the suffixes involved.
Done.
>
>> +             error ("%qD has illegal argument list", decl);
>
> Use "invalid" rather than "illegal".
Done.
>
>> +         suffix = UDLIT_OP_SUFFIX (DECL_NAME (decl));
>> +         if (long_long_unsigned_p)
>> +           {
>> +             if (cpp_interpret_int_suffix (suffix, strlen (suffix)))
>> +               warning (0, "integer suffix shadowed by 
>> implementation");
>> +           }
>> +         else if (long_double_p)
>> +           {
>> +             if (cpp_interpret_float_suffix (suffix, strlen (suffix)))
>> +               warning (0, "floating point suffix"
>> +                           " shadowed by implementation");
>> +           }
>
> Let's print the suffix as part of the warning.
Done.
>
>> +  if (dname
>> + && TREE_CODE (dname) == IDENTIFIER_NODE
>> + && UDLIT_OPER_P (dname)
>> + && innermost_code != cdk_function
>> + && ! (ctype && !declspecs->any_specifiers_p))
>
> I think we can drop the last check, as it only applies to constructors.
Done.
>
>> +/* User-defined literal operator.
>> +DEF_SIMPLE_OPERATOR ("\"\"", USERDEF_LITERAL_EXPR, "ud", 1)  */
>
> Are you planning to use this for something?
Removed.
>
>> +/* 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)
>
> There should be a blank line after the comment here and before the 
> other new functions, at least in gcc/.
Done in as many of my places as I could find.
>
>> +make_numeric_string(tree value)
>
> This function tries to recreate a printed form for a numeric constant, 
> but that's not right; we need the actual source characters, which are 
> likely to be different, especially for floating-point numbers.  So we 
> need to get back to the actual spelling of the token here.
>
> I notice that later in cp_parser_userdef_numeric_literal when calling 
> the variadic template version you assume that you have the spelling of 
> the token, which is indeed what we want.
Done.  I am now storing the numeric string along with the number and the 
suffix ID for numeric operators.  I'm keeping the numeric value because 
we need it too.
>
>> +check_literal_operator_args(const_tree decl,
>
> Space before (.
Done.
>
>> +      tree const_char_ptr_type_node
>> +          = build_pointer_type(build_type_variant(char_type_node, 1, 
>> 0));
>> +      tree const_wchar_ptr_type_node
>> +          = build_pointer_type(build_type_variant(wchar_type_node, 
>> 1, 0));
>> +      tree const_char16_ptr_type_node
>> +          = build_pointer_type(build_type_variant(char16_type_node, 
>> 1, 0));
>> +      tree const_char32_ptr_type_node
>> +          = build_pointer_type(build_type_variant(char32_type_node, 
>> 1, 0));
>
> It seems to me that rather than build these up to compare against, it 
> it would be faster to check for POINTER_TYPE, then check that the 
> pointed-to type is CP_TYPE_CONST_NON_VOLATILE_P, and then compare the 
> TYPE_MAIN_VARIANT to char_type_node, etc.
I tried this and couldn't get it to work.  I got a bunch of false 
negatives and then a crash.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
>
>> +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C
>> @@ -0,0 +1,16 @@
>> +// { dg-options "-std=c++0x" }
>> +
>> +//  Both of these can't have *both* of these.
>> +
>> +int
>> +operator"" _abc(const char*)
>> +  {
>> +    return 42;
>> +  }
>> +
>> +template<char...>
>> +  int
>> +  operator"" _abc()
>> +  {
>> +    return 13;
>> +  }
>
> Shouldn't this have a dg-error tag somewhere?
I'm working on checking this.  I need to test if both
   operator"" _foo(char*)
and
   template <char...>
     _foo();
are declared and error.  I'l looking over decl.c for this.
If I can't figure that out I'll take out the test.
>
> Jason
>
Attached are the results to date.
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: patch19
URL: <http://gcc.gnu.org/pipermail/gcc-patches/attachments/20110919/13f05e7d/attachment.ksh>


More information about the Gcc-patches mailing list