diff options
-rw-r--r-- | include/clang/Parse/Parser.h | 1 | ||||
-rw-r--r-- | include/clang/Sema/DeclSpec.h | 8 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 22 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 34 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 9 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp | 2 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp | 2 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp | 2 | ||||
-rw-r--r-- | test/Parser/cxx0x-ambig.cpp | 11 | ||||
-rw-r--r-- | test/Parser/cxx0x-decl.cpp | 10 | ||||
-rw-r--r-- | test/Parser/cxx0x-lambda-expressions.cpp | 5 |
11 files changed, 76 insertions, 30 deletions
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 0496057886..892d5fa501 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1622,6 +1622,7 @@ private: 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 }; diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 425335e95e..49460a5524 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -1428,9 +1428,10 @@ public: 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 @@ public: case BlockLiteralContext: case LambdaExprContext: case TemplateTypeArgContext: + case TrailingReturnContext: return true; } llvm_unreachable("unknown context kind!"); @@ -1635,6 +1637,7 @@ public: case BlockLiteralContext: case LambdaExprContext: case TemplateTypeArgContext: + case TrailingReturnContext: return false; } llvm_unreachable("unknown context kind!"); @@ -1679,6 +1682,7 @@ public: case BlockLiteralContext: case LambdaExprContext: case TemplateTypeArgContext: + case TrailingReturnContext: return false; } llvm_unreachable("unknown context kind!"); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index c1f6eb5d42..31a898cf5a 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -36,9 +36,13 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, 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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, 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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // 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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, 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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, 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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, 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()); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 391db1987a..979b4dd18f 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1114,11 +1114,16 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, 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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // &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 @@ TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) { 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, diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index f1b00e38d7..d8ac7636e2 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1832,6 +1832,9 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, 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 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, // 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 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, 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. diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp index 7b5577520d..a385aa9132 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp @@ -44,6 +44,6 @@ struct F : auto(*)()->int {}; // expected-error{{expected class name}} 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. diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp index ef48cd00b7..71f57dcc66 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp @@ -65,4 +65,4 @@ template<typename T = auto> struct G { }; // expected-error{{'auto' not allowed 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}} diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp index 4d71a8e4b4..574a3e7a79 100644 --- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp @@ -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}} diff --git a/test/Parser/cxx0x-ambig.cpp b/test/Parser/cxx0x-ambig.cpp index c955dc1690..b77bae500e 100644 --- a/test/Parser/cxx0x-ambig.cpp +++ b/test/Parser/cxx0x-ambig.cpp @@ -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'}} } } diff --git a/test/Parser/cxx0x-decl.cpp b/test/Parser/cxx0x-decl.cpp index 73aa3fdc40..b9f5141a53 100644 --- a/test/Parser/cxx0x-decl.cpp +++ b/test/Parser/cxx0x-decl.cpp @@ -6,3 +6,13 @@ namespace Commas { b [[ ]], c alignas(double); } + +struct S {}; +enum E { e }; + +auto f() -> struct S { + return S(); +} +auto g() -> enum E { + return E(); +} diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp index 87d14051e9..9c71941421 100644 --- a/test/Parser/cxx0x-lambda-expressions.cpp +++ b/test/Parser/cxx0x-lambda-expressions.cpp @@ -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 @@ class C { [=,&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 @@ class C { int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}} } }; - |