diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-03-12 08:56:40 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-03-12 08:56:40 +0000 |
commit | 7796eb5643244f3134834253ce5ea89107ac21c1 (patch) | |
tree | 223c93c51604d1e6128470ad42ea5af267b8abaf /lib/Parse | |
parent | 69730c115c2d0fec2f20609d905d920a5a41b29b (diff) |
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').
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152551 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 22 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 34 |
2 files changed, 33 insertions, 23 deletions
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, |