[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/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp test/Parser/cxx0x-ambig.cpp test/Parser/cxx0x-decl.cpp test/Parser/cxx0x-lambda-expressions.cpp

Richard Smith richard-llvm at metafoo.co.uk
Mon Mar 12 01:56:40 PDT 2012


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))) {
     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 *'}}
   }
 };
-





More information about the cfe-commits mailing list