<div class="gmail_quote">On Mon, Mar 12, 2012 at 9:24 AM, David Blaikie <span dir="ltr"><<a href="mailto:dblaikie@gmail.com">dblaikie@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
On Mon, Mar 12, 2012 at 1:56 AM, Richard Smith<br>
<<a href="mailto:richard-llvm@metafoo.co.uk">richard-llvm@metafoo.co.uk</a>> wrote:<br>
> Author: rsmith<br>
> Date: Mon Mar 12 03:56:40 2012<br>
> New Revision: 152551<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=152551&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=152551&view=rev</a><br>
> Log:<br>
> Fix parsing of trailing-return-type. Types are syntactically prohibited from<br>
> being defined here: [] () -> struct S {} does not define struct S.<br>
><br>
> In passing, implement DR1318 (syntactic disambiguation of 'final').<br>
><br>
> Modified:<br>
>    cfe/trunk/include/clang/Parse/Parser.h<br>
>    cfe/trunk/include/clang/Sema/DeclSpec.h<br>
>    cfe/trunk/lib/Parse/ParseDecl.cpp<br>
>    cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>
>    cfe/trunk/lib/Sema/SemaType.cpp<br>
>    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp<br>
>    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp<br>
>    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp<br>
>    cfe/trunk/test/Parser/cxx0x-ambig.cpp<br>
>    cfe/trunk/test/Parser/cxx0x-decl.cpp<br>
>    cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp<br>
><br>
> Modified: cfe/trunk/include/clang/Parse/Parser.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=152551&r1=152550&r2=152551&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=152551&r1=152550&r2=152551&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Parse/Parser.h (original)<br>
> +++ cfe/trunk/include/clang/Parse/Parser.h Mon Mar 12 03:56:40 2012<br>
> @@ -1622,6 +1622,7 @@<br>
>     DSC_normal, // normal context<br>
>     DSC_class,  // class context, enables 'friend'<br>
>     DSC_type_specifier, // C++ type-specifier-seq<br>
> +    DSC_trailing, // C++11 trailing-type-specifier in a trailing return type<br>
>     DSC_top_level // top-level/namespace declaration context<br>
>   };<br>
><br>
><br>
> Modified: cfe/trunk/include/clang/Sema/DeclSpec.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=152551&r1=152550&r2=152551&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=152551&r1=152550&r2=152551&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Sema/DeclSpec.h (original)<br>
> +++ cfe/trunk/include/clang/Sema/DeclSpec.h Mon Mar 12 03:56:40 2012<br>
> @@ -1428,9 +1428,10 @@<br>
>     ObjCCatchContext,    // Objective-C catch exception-declaration<br>
>     BlockLiteralContext,  // Block literal declarator.<br>
>     LambdaExprContext,   // Lambda-expression declarator.<br>
> +    TrailingReturnContext, // C++11 trailing-type-specifier.<br>
>     TemplateTypeArgContext, // Template type argument.<br>
> -    AliasDeclContext,    // C++0x alias-declaration.<br>
> -    AliasTemplateContext // C++0x alias-declaration template.<br>
> +    AliasDeclContext,    // C++11 alias-declaration.<br>
> +    AliasTemplateContext // C++11 alias-declaration template.<br>
>   };<br>
><br>
>  private:<br>
> @@ -1604,6 +1605,7 @@<br>
>     case BlockLiteralContext:<br>
>     case LambdaExprContext:<br>
>     case TemplateTypeArgContext:<br>
> +    case TrailingReturnContext:<br>
>       return true;<br>
>     }<br>
>     llvm_unreachable("unknown context kind!");<br>
> @@ -1635,6 +1637,7 @@<br>
>     case BlockLiteralContext:<br>
>     case LambdaExprContext:<br>
>     case TemplateTypeArgContext:<br>
> +    case TrailingReturnContext:<br>
>       return false;<br>
>     }<br>
>     llvm_unreachable("unknown context kind!");<br>
> @@ -1679,6 +1682,7 @@<br>
>     case BlockLiteralContext:<br>
>     case LambdaExprContext:<br>
>     case TemplateTypeArgContext:<br>
> +    case TrailingReturnContext:<br>
>       return false;<br>
>     }<br>
>     llvm_unreachable("unknown context kind!");<br>
><br>
> Modified: cfe/trunk/lib/Parse/ParseDecl.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=152551&r1=152550&r2=152551&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=152551&r1=152550&r2=152551&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Parse/ParseDecl.cpp (original)<br>
> +++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Mar 12 03:56:40 2012<br>
> @@ -36,9 +36,13 @@<br>
>                                  Declarator::TheContext Context,<br>
>                                  AccessSpecifier AS,<br>
>                                  Decl **OwnedType) {<br>
> +  DeclSpecContext DSC = DSC_normal;<br>
> +  if (Context == Declarator::TrailingReturnContext)<br>
> +    DSC = DSC_trailing;<br>
> +<br>
>   // Parse the common declaration-specifiers piece.<br>
>   DeclSpec DS(AttrFactory);<br>
> -  ParseSpecifierQualifierList(DS, AS);<br>
> +  ParseSpecifierQualifierList(DS, AS, DSC);<br>
>   if (OwnedType)<br>
>     *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;<br>
><br>
> @@ -2653,8 +2657,12 @@<br>
>   while (Tok.is(tok::kw___declspec))<br>
>     ParseMicrosoftDeclSpec(attrs);<br>
><br>
> -  bool AllowFixedUnderlyingType<br>
> -    = getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt || getLangOpts().ObjC2;<br>
> +  // Enum definitions should not be parsed in a trailing-return-type.<br>
> +  bool AllowDeclaration = DSC != DSC_trailing;<br>
> +<br>
> +  bool AllowFixedUnderlyingType = AllowDeclaration &&<br>
> +    (getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt ||<br>
> +     getLangOpts().ObjC2);<br>
><br>
>   CXXScopeSpec &SS = DS.getTypeSpecScope();<br>
>   if (getLangOpts().CPlusPlus) {<br>
> @@ -2679,7 +2687,7 @@<br>
><br>
>   // Must have either 'enum name' or 'enum {...}'.<br>
>   if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&<br>
> -      (AllowFixedUnderlyingType && Tok.isNot(tok::colon))) {<br>
> +      !(AllowFixedUnderlyingType && Tok.is(tok::colon))) {<br>
>     Diag(Tok, diag::err_expected_ident_lbrace);<br>
><br>
>     // Skip the rest of this declarator, up until the comma or semicolon.<br>
> @@ -2785,6 +2793,8 @@<br>
>   Sema::TagUseKind TUK;<br>
>   if (DS.isFriendSpecified())<br>
>     TUK = Sema::TUK_Friend;<br>
> +  else if (!AllowDeclaration)<br>
> +    TUK = Sema::TUK_Reference;<br>
>   else if (Tok.is(tok::l_brace))<br>
>     TUK = Sema::TUK_Definition;<br>
>   else if (Tok.is(tok::semi) && DSC != DSC_type_specifier)<br>
> @@ -2850,7 +2860,7 @@<br>
>   if (!TagDecl) {<br>
>     // The action failed to produce an enumeration tag. If this is a<br>
>     // definition, consume the entire definition.<br>
> -    if (Tok.is(tok::l_brace)) {<br>
> +    if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {<br>
>       ConsumeBrace();<br>
>       SkipUntil(tok::r_brace);<br>
>     }<br>
> @@ -2859,7 +2869,7 @@<br>
>     return;<br>
>   }<br>
><br>
> -  if (Tok.is(tok::l_brace)) {<br>
> +  if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {<br>
>     if (TUK == Sema::TUK_Friend)<br>
>       Diag(Tok, diag::err_friend_decl_defines_type)<br>
>         << SourceRange(DS.getFriendSpecLoc());<br>
><br>
> Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=152551&r1=152550&r2=152551&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=152551&r1=152550&r2=152551&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)<br>
> +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Mar 12 03:56:40 2012<br>
> @@ -1114,11 +1114,16 @@<br>
>   if (SuppressingAccessChecks)<br>
>     Actions.ActOnStopSuppressingAccessChecks();<br>
><br>
> -  // There are four options here.  If we have 'struct foo;', then this<br>
> -  // is either a forward declaration or a friend declaration, which<br>
> -  // have to be treated differently.  If we have 'struct foo {...',<br>
> -  // 'struct foo :...' or 'struct foo final[opt]' then this is a<br>
> -  // definition. Otherwise we have something like 'struct foo xyz', a reference.<br>
> +  // There are four options here.<br>
> +  //  - If we are in a trailing return type, this is always just a reference,<br>
> +  //    and we must not try to parse a definition. For instance,<br>
> +  //      [] () -> struct S { };<br>
> +  //    does not define a type.<br>
> +  //  - If we have 'struct foo {...', 'struct foo :...',<br>
> +  //    'struct foo final :' or 'struct foo final {', then this is a definition.<br>
> +  //  - If we have 'struct foo;', then this is either a forward declaration<br>
> +  //    or a friend declaration, which have to be treated differently.<br>
> +  //  - Otherwise we have something like 'struct foo xyz', a reference.<br>
>   // However, in type-specifier-seq's, things look like declarations but are<br>
>   // just references, e.g.<br>
>   //   new struct s;<br>
> @@ -1126,10 +1131,12 @@<br>
>   //   &T::operator struct s;<br>
>   // For these, DSC is DSC_type_specifier.<br>
>   Sema::TagUseKind TUK;<br>
> -  if (Tok.is(tok::l_brace) ||<br>
> -      (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||<br>
> -      // FIXME: 'final' must be followed by ':' or '{' to mark a definition.<br>
> -      isCXX0XFinalKeyword()) {<br>
> +  if (DSC == DSC_trailing)<br>
> +    TUK = Sema::TUK_Reference;<br>
> +  else if (Tok.is(tok::l_brace) ||<br>
> +           (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||<br>
> +           (isCXX0XFinalKeyword() &&<br>
> +            NextToken().is(tok::l_brace) || NextToken().is(tok::colon))) {<br>
<br>
This caused a -Wlogical-op-parentheses warning which caught a<br>
crash-on-invalid (perhaps there are valid cases too, but the simple<br>
case I tested (where the current token is 'foo', not 'final' and is<br>
followed by a colon) was invalid). I fixed this & included the test<br>
case in r152559. For completeness we could add a test case for the<br>
reverse (the case where the brace and colon tests were switched around<br>
& produced the same sort of bug) but I didn't bother.</blockquote><div><br></div><div>Oops, thanks! </div></div>