[cfe-commits] r152551 - in /cfe/trunk: include/clang/Parse/Parser.h include/clang/Sema/DeclSpec.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/SemaType.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp test/CXX/dcl.dcl/dc

David Blaikie dblaikie at gmail.com
Mon Mar 12 09:24:21 PDT 2012


On Mon, Mar 12, 2012 at 1:56 AM, Richard Smith
<richard-llvm at metafoo.co.uk> wrote:
> Author: rsmith
> Date: Mon Mar 12 03:56:40 2012
> New Revision: 152551
>
> URL: http://llvm.org/viewvc/llvm-project?rev=152551&view=rev
> Log:
> Fix parsing of trailing-return-type. Types are syntactically prohibited from
> being defined here: [] () -> struct S {} does not define struct S.
>
> In passing, implement DR1318 (syntactic disambiguation of 'final').
>
> Modified:
>    cfe/trunk/include/clang/Parse/Parser.h
>    cfe/trunk/include/clang/Sema/DeclSpec.h
>    cfe/trunk/lib/Parse/ParseDecl.cpp
>    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
>    cfe/trunk/lib/Sema/SemaType.cpp
>    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
>    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
>    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
>    cfe/trunk/test/Parser/cxx0x-ambig.cpp
>    cfe/trunk/test/Parser/cxx0x-decl.cpp
>    cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp
>
> Modified: cfe/trunk/include/clang/Parse/Parser.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Parse/Parser.h (original)
> +++ cfe/trunk/include/clang/Parse/Parser.h Mon Mar 12 03:56:40 2012
> @@ -1622,6 +1622,7 @@
>     DSC_normal, // normal context
>     DSC_class,  // class context, enables 'friend'
>     DSC_type_specifier, // C++ type-specifier-seq
> +    DSC_trailing, // C++11 trailing-type-specifier in a trailing return type
>     DSC_top_level // top-level/namespace declaration context
>   };
>
>
> Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
> +++ cfe/trunk/include/clang/Sema/DeclSpec.h Mon Mar 12 03:56:40 2012
> @@ -1428,9 +1428,10 @@
>     ObjCCatchContext,    // Objective-C catch exception-declaration
>     BlockLiteralContext,  // Block literal declarator.
>     LambdaExprContext,   // Lambda-expression declarator.
> +    TrailingReturnContext, // C++11 trailing-type-specifier.
>     TemplateTypeArgContext, // Template type argument.
> -    AliasDeclContext,    // C++0x alias-declaration.
> -    AliasTemplateContext // C++0x alias-declaration template.
> +    AliasDeclContext,    // C++11 alias-declaration.
> +    AliasTemplateContext // C++11 alias-declaration template.
>   };
>
>  private:
> @@ -1604,6 +1605,7 @@
>     case BlockLiteralContext:
>     case LambdaExprContext:
>     case TemplateTypeArgContext:
> +    case TrailingReturnContext:
>       return true;
>     }
>     llvm_unreachable("unknown context kind!");
> @@ -1635,6 +1637,7 @@
>     case BlockLiteralContext:
>     case LambdaExprContext:
>     case TemplateTypeArgContext:
> +    case TrailingReturnContext:
>       return false;
>     }
>     llvm_unreachable("unknown context kind!");
> @@ -1679,6 +1682,7 @@
>     case BlockLiteralContext:
>     case LambdaExprContext:
>     case TemplateTypeArgContext:
> +    case TrailingReturnContext:
>       return false;
>     }
>     llvm_unreachable("unknown context kind!");
>
> Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Mar 12 03:56:40 2012
> @@ -36,9 +36,13 @@
>                                  Declarator::TheContext Context,
>                                  AccessSpecifier AS,
>                                  Decl **OwnedType) {
> +  DeclSpecContext DSC = DSC_normal;
> +  if (Context == Declarator::TrailingReturnContext)
> +    DSC = DSC_trailing;
> +
>   // Parse the common declaration-specifiers piece.
>   DeclSpec DS(AttrFactory);
> -  ParseSpecifierQualifierList(DS, AS);
> +  ParseSpecifierQualifierList(DS, AS, DSC);
>   if (OwnedType)
>     *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;
>
> @@ -2653,8 +2657,12 @@
>   while (Tok.is(tok::kw___declspec))
>     ParseMicrosoftDeclSpec(attrs);
>
> -  bool AllowFixedUnderlyingType
> -    = getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt || getLangOpts().ObjC2;
> +  // Enum definitions should not be parsed in a trailing-return-type.
> +  bool AllowDeclaration = DSC != DSC_trailing;
> +
> +  bool AllowFixedUnderlyingType = AllowDeclaration &&
> +    (getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt ||
> +     getLangOpts().ObjC2);
>
>   CXXScopeSpec &SS = DS.getTypeSpecScope();
>   if (getLangOpts().CPlusPlus) {
> @@ -2679,7 +2687,7 @@
>
>   // Must have either 'enum name' or 'enum {...}'.
>   if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&
> -      (AllowFixedUnderlyingType && Tok.isNot(tok::colon))) {
> +      !(AllowFixedUnderlyingType && Tok.is(tok::colon))) {
>     Diag(Tok, diag::err_expected_ident_lbrace);
>
>     // Skip the rest of this declarator, up until the comma or semicolon.
> @@ -2785,6 +2793,8 @@
>   Sema::TagUseKind TUK;
>   if (DS.isFriendSpecified())
>     TUK = Sema::TUK_Friend;
> +  else if (!AllowDeclaration)
> +    TUK = Sema::TUK_Reference;
>   else if (Tok.is(tok::l_brace))
>     TUK = Sema::TUK_Definition;
>   else if (Tok.is(tok::semi) && DSC != DSC_type_specifier)
> @@ -2850,7 +2860,7 @@
>   if (!TagDecl) {
>     // The action failed to produce an enumeration tag. If this is a
>     // definition, consume the entire definition.
> -    if (Tok.is(tok::l_brace)) {
> +    if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
>       ConsumeBrace();
>       SkipUntil(tok::r_brace);
>     }
> @@ -2859,7 +2869,7 @@
>     return;
>   }
>
> -  if (Tok.is(tok::l_brace)) {
> +  if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
>     if (TUK == Sema::TUK_Friend)
>       Diag(Tok, diag::err_friend_decl_defines_type)
>         << SourceRange(DS.getFriendSpecLoc());
>
> Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Mar 12 03:56:40 2012
> @@ -1114,11 +1114,16 @@
>   if (SuppressingAccessChecks)
>     Actions.ActOnStopSuppressingAccessChecks();
>
> -  // There are four options here.  If we have 'struct foo;', then this
> -  // is either a forward declaration or a friend declaration, which
> -  // have to be treated differently.  If we have 'struct foo {...',
> -  // 'struct foo :...' or 'struct foo final[opt]' then this is a
> -  // definition. Otherwise we have something like 'struct foo xyz', a reference.
> +  // There are four options here.
> +  //  - If we are in a trailing return type, this is always just a reference,
> +  //    and we must not try to parse a definition. For instance,
> +  //      [] () -> struct S { };
> +  //    does not define a type.
> +  //  - If we have 'struct foo {...', 'struct foo :...',
> +  //    'struct foo final :' or 'struct foo final {', then this is a definition.
> +  //  - If we have 'struct foo;', then this is either a forward declaration
> +  //    or a friend declaration, which have to be treated differently.
> +  //  - Otherwise we have something like 'struct foo xyz', a reference.
>   // However, in type-specifier-seq's, things look like declarations but are
>   // just references, e.g.
>   //   new struct s;
> @@ -1126,10 +1131,12 @@
>   //   &T::operator struct s;
>   // For these, DSC is DSC_type_specifier.
>   Sema::TagUseKind TUK;
> -  if (Tok.is(tok::l_brace) ||
> -      (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
> -      // FIXME: 'final' must be followed by ':' or '{' to mark a definition.
> -      isCXX0XFinalKeyword()) {
> +  if (DSC == DSC_trailing)
> +    TUK = Sema::TUK_Reference;
> +  else if (Tok.is(tok::l_brace) ||
> +           (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
> +           (isCXX0XFinalKeyword() &&
> +            NextToken().is(tok::l_brace) || NextToken().is(tok::colon))) {

This caused a -Wlogical-op-parentheses warning which caught a
crash-on-invalid (perhaps there are valid cases too, but the simple
case I tested (where the current token is 'foo', not 'final' and is
followed by a colon) was invalid). I fixed this & included the test
case in r152559. For completeness we could add a test case for the
reverse (the case where the brace and colon tests were switched around
& produced the same sort of bug) but I didn't bother.

- David

>     if (DS.isFriendSpecified()) {
>       // C++ [class.friend]p2:
>       //   A class shall not be defined in a friend declaration.
> @@ -2673,14 +2680,7 @@
>
>   ConsumeToken();
>
> -  // FIXME: Need to suppress declarations when parsing this typename.
> -  // Otherwise in this function definition:
> -  //
> -  //   auto f() -> struct X {}
> -  //
> -  // struct X is parsed as class definition because of the trailing
> -  // brace.
> -  return ParseTypeName(&Range);
> +  return ParseTypeName(&Range, Declarator::TrailingReturnContext);
>  }
>
>  /// \brief We have just started parsing the definition of a new class,
>
> Modified: cfe/trunk/lib/Sema/SemaType.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaType.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaType.cpp Mon Mar 12 03:56:40 2012
> @@ -1832,6 +1832,9 @@
>     case Declarator::AliasTemplateContext:
>       Error = 9; // Type alias
>       break;
> +    case Declarator::TrailingReturnContext:
> +      Error = 10; // Function return type
> +      break;
>     case Declarator::TypeNameContext:
>       Error = 11; // Generic
>       break;
> @@ -1885,6 +1888,11 @@
>     // Check the contexts where C++ forbids the declaration of a new class
>     // or enumeration in a type-specifier-seq.
>     switch (D.getContext()) {
> +    case Declarator::TrailingReturnContext:
> +      // Class and enumeration definitions are syntactically not allowed in
> +      // trailing return types.
> +      llvm_unreachable("parser should not have allowed this");
> +      break;
>     case Declarator::FileContext:
>     case Declarator::MemberContext:
>     case Declarator::BlockContext:
> @@ -2606,6 +2614,7 @@
>     case Declarator::ObjCCatchContext:
>     case Declarator::BlockLiteralContext:
>     case Declarator::LambdaExprContext:
> +    case Declarator::TrailingReturnContext:
>     case Declarator::TemplateTypeArgContext:
>       // FIXME: We may want to allow parameter packs in block-literal contexts
>       // in the future.
>
> Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp (original)
> +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp Mon Mar 12 03:56:40 2012
> @@ -44,6 +44,6 @@
>  template<typename T = auto(*)()->int> struct G { };
>
>  int g();
> -auto (*h)() -> auto = &g; // expected-error{{'auto' not allowed here}}
> +auto (*h)() -> auto = &g; // expected-error{{'auto' not allowed in function return type}}
>  auto (*i)() = &g; // ok; auto deduced as int.
>  auto (*k)() -> int = i; // ok; no deduction.
>
> Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp (original)
> +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp Mon Mar 12 03:56:40 2012
> @@ -65,4 +65,4 @@
>  using A = auto; // expected-error{{'auto' not allowed in type alias}}
>
>  // FIXME: don't issue the second diagnostic for this error.
> -auto k() -> auto; // expected-error{{'auto' not allowed here}} unexpected-error{{without trailing return type}}
> +auto k() -> auto; // expected-error{{'auto' not allowed in function return type}} unexpected-error{{without trailing return type}}
>
> Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp (original)
> +++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp Mon Mar 12 03:56:40 2012
> @@ -1,3 +1,3 @@
>  // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
>
> -auto j() -> enum { e3 }; // expected-error{{can not be defined in a type specifier}}
> +auto j() -> enum { e3 }; // expected-error{{unnamed enumeration must be a definition}} expected-error {{requires a specifier or qualifier}} expected-error {{without trailing return type}}
>
> Modified: cfe/trunk/test/Parser/cxx0x-ambig.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-ambig.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/test/Parser/cxx0x-ambig.cpp (original)
> +++ cfe/trunk/test/Parser/cxx0x-ambig.cpp Mon Mar 12 03:56:40 2012
> @@ -5,15 +5,24 @@
>  // final 'context sensitive' mess.
>  namespace final {
>   struct S { int n; };
> +  struct T { int n; };
>   namespace N {
>     int n;
> +    // These declare variables named final..
> +    extern struct S final;
> +    extern struct S final [[]];
> +    extern struct S final, foo;
> +    struct S final = S();
> +
>     // This defines a class, not a variable, even though it would successfully
>     // parse as a variable but not as a class. DR1318's wording suggests that
>     // this disambiguation is only performed on an ambiguity, but that was not
>     // the intent.
> -    struct S final {
> +    struct S final { // expected-note {{here}}
>       int(n) // expected-error {{expected ';'}}
>     };
> +    // This too.
> +    struct T final : S {}; // expected-error {{base 'S' is marked 'final'}}
>   }
>  }
>
>
> Modified: cfe/trunk/test/Parser/cxx0x-decl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-decl.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/test/Parser/cxx0x-decl.cpp (original)
> +++ cfe/trunk/test/Parser/cxx0x-decl.cpp Mon Mar 12 03:56:40 2012
> @@ -6,3 +6,13 @@
>   b [[ ]],
>   c alignas(double);
>  }
> +
> +struct S {};
> +enum E { e };
> +
> +auto f() -> struct S {
> +  return S();
> +}
> +auto g() -> enum E {
> +  return E();
> +}
>
> Modified: cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp (original)
> +++ cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp Mon Mar 12 03:56:40 2012
> @@ -1,5 +1,7 @@
>  // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s
>
> +enum E { e };
> +
>  class C {
>
>   int f() {
> @@ -19,6 +21,8 @@
>     [=,&foo] () {};
>     [&,foo] () {};
>     [this] () {};
> +    [] () -> class C { return C(); };
> +    [] () -> enum E { return e; };
>
>     [] -> int { return 0; }; // expected-error{{lambda requires '()' before return type}}
>     [] mutable -> int { return 0; }; // expected-error{{lambda requires '()' before 'mutable'}}
> @@ -37,4 +41,3 @@
>     int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}}
>   }
>  };
> -
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits




More information about the cfe-commits mailing list