diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp | 327 |
1 files changed, 196 insertions, 131 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp index 5e6c4f5..3dc96cf 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp @@ -444,6 +444,13 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, CXXScopeSpec SS; SourceLocation TypenameLoc; bool IsTypeName; + ParsedAttributesWithRange attrs(AttrFactory); + + // FIXME: Simply skip the attributes and diagnose, don't bother parsing them. + MaybeParseCXX0XAttributes(attrs); + ProhibitAttributes(attrs); + attrs.clear(); + attrs.Range = SourceRange(); // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. @@ -480,7 +487,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } - ParsedAttributes attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); // Maybe this is an alias-declaration. bool IsAliasDecl = Tok.is(tok::equal); @@ -533,9 +540,14 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, TypeAlias = ParseTypeName(0, TemplateInfo.Kind ? Declarator::AliasTemplateContext : Declarator::AliasDeclContext, AS, OwnedType); - } else + } else { + // C++11 attributes are not allowed on a using-declaration, but GNU ones + // are. + ProhibitAttributes(attrs); + // Parse (optional) attributes (most likely GNU strong-using extension). MaybeParseGNUAttributes(attrs); + } // Eat ';'. DeclEnd = Tok.getLocation(); @@ -572,6 +584,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, MultiTemplateParamsArg TemplateParamsArg(Actions, TemplateParams ? TemplateParams->data() : 0, TemplateParams ? TemplateParams->size() : 0); + // FIXME: Propagate attributes. return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg, UsingLoc, Name, TypeAlias); } @@ -874,10 +887,12 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, } // We have an identifier; check whether it is actually a type. + IdentifierInfo *CorrectedII = 0; ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true, false, ParsedType(), /*IsCtorOrDtorName=*/false, - /*NonTrivialTypeSourceInfo=*/true); + /*NonTrivialTypeSourceInfo=*/true, + &CorrectedII); if (!Type) { Diag(IdLoc, diag::err_expected_class_name); return true; @@ -900,6 +915,77 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } +void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) { + while (Tok.is(tok::kw___single_inheritance) || + Tok.is(tok::kw___multiple_inheritance) || + Tok.is(tok::kw___virtual_inheritance)) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, AttributeList::AS_GNU); + } +} + +/// Determine whether the following tokens are valid after a type-specifier +/// which could be a standalone declaration. This will conservatively return +/// true if there's any doubt, and is appropriate for insert-';' fixits. +bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { + // This switch enumerates the valid "follow" set for type-specifiers. + switch (Tok.getKind()) { + default: break; + case tok::semi: // struct foo {...} ; + case tok::star: // struct foo {...} * P; + case tok::amp: // struct foo {...} & R = ... + case tok::identifier: // struct foo {...} V ; + case tok::r_paren: //(struct foo {...} ) {4} + case tok::annot_cxxscope: // struct foo {...} a:: b; + case tok::annot_typename: // struct foo {...} a ::b; + case tok::annot_template_id: // struct foo {...} a<int> ::b; + case tok::l_paren: // struct foo {...} ( x); + case tok::comma: // __builtin_offsetof(struct foo{...} , + return true; + case tok::colon: + return CouldBeBitfield; // enum E { ... } : 2; + // Type qualifiers + case tok::kw_const: // struct foo {...} const x; + case tok::kw_volatile: // struct foo {...} volatile x; + case tok::kw_restrict: // struct foo {...} restrict x; + case tok::kw_inline: // struct foo {...} inline foo() {}; + // Storage-class specifiers + case tok::kw_static: // struct foo {...} static x; + case tok::kw_extern: // struct foo {...} extern x; + case tok::kw_typedef: // struct foo {...} typedef x; + case tok::kw_register: // struct foo {...} register x; + case tok::kw_auto: // struct foo {...} auto x; + case tok::kw_mutable: // struct foo {...} mutable x; + case tok::kw_constexpr: // struct foo {...} constexpr x; + // As shown above, type qualifiers and storage class specifiers absolutely + // can occur after class specifiers according to the grammar. However, + // almost no one actually writes code like this. If we see one of these, + // it is much more likely that someone missed a semi colon and the + // type/storage class specifier we're seeing is part of the *next* + // intended declaration, as in: + // + // struct foo { ... } + // typedef int X; + // + // We'd really like to emit a missing semicolon error instead of emitting + // an error on the 'int' saying that you can't have two type specifiers in + // the same declaration of X. Because of this, we look ahead past this + // token to see if it's a type specifier. If so, we know the code is + // otherwise invalid, so we can produce the expected semi error. + if (!isKnownToBeTypeSpecifier(NextToken())) + return true; + break; + case tok::r_brace: // struct bar { struct foo {...} } + // Missing ';' at end of struct is accepted as an extension in C mode. + if (!getLangOpts().CPlusPlus) + return true; + break; + } + return false; +} + /// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or /// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which /// until we reach the start of a definition or see a token that @@ -968,11 +1054,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // As an extension we do not perform access checking on the names used to // specify explicit specializations either. This is important to allow // specializing traits classes for private types. - Sema::SuppressAccessChecksRAII SuppressAccess(Actions, - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + // + // Note that we don't suppress if this turns out to be an elaborated + // type specifier. + bool shouldDelayDiagsInTag = + (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag); - ParsedAttributes attrs(AttrFactory); + ParsedAttributesWithRange attrs(AttrFactory); // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) ParseGNUAttributes(attrs); @@ -981,6 +1071,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, while (Tok.is(tok::kw___declspec)) ParseMicrosoftDeclSpec(attrs); + // Parse inheritance specifiers. + if (Tok.is(tok::kw___single_inheritance) || + Tok.is(tok::kw___multiple_inheritance) || + Tok.is(tok::kw___virtual_inheritance)) + ParseMicrosoftInheritanceClassAttributes(attrs); + // If C++0x attributes exist here, parse them. // FIXME: Are we consistent with the ordering of parsing of different // styles of attributes? @@ -1103,10 +1199,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } } - // As soon as we're finished parsing the class's template-id, turn access - // checking back on. - SuppressAccess.done(); - // 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, @@ -1144,11 +1236,29 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Okay, this is a class definition. TUK = Sema::TUK_Definition; } - } else if (Tok.is(tok::semi) && DSC != DSC_type_specifier) + } else if (DSC != DSC_type_specifier && + (Tok.is(tok::semi) || + (Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(false)))) { TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; - else + if (Tok.isNot(tok::semi)) { + // A semicolon was missing after this declaration. Diagnose and recover. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, + TagType == DeclSpec::TST_class ? "class" : + TagType == DeclSpec::TST_struct ? "struct" : "union"); + PP.EnterToken(Tok); + Tok.setKind(tok::semi); + } + } else TUK = Sema::TUK_Reference; + // If this is an elaborated type specifier, and we delayed + // diagnostics before, just merge them into the current pool. + if (shouldDelayDiagsInTag) { + diagsFromTag.done(); + if (TUK == Sema::TUK_Reference) + diagsFromTag.redelay(); + } + if (!Name && !TemplateId && (DS.getTypeSpecType() == DeclSpec::TST_error || TUK != Sema::TUK_Definition)) { if (DS.getTypeSpecType() != DeclSpec::TST_error) { @@ -1175,6 +1285,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Sema::TUK_Declaration) { // This is an explicit instantiation of a class template. + ProhibitAttributes(attrs); + TagOrTempResult = Actions.ActOnExplicitInstantiation(getCurScope(), TemplateInfo.ExternLoc, @@ -1196,6 +1308,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } else if (TUK == Sema::TUK_Reference || (TUK == Sema::TUK_Friend && TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { + ProhibitAttributes(attrs); TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc, TemplateId->SS, TemplateId->TemplateKWLoc, @@ -1260,6 +1373,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // // template struct Outer<int>::Inner; // + ProhibitAttributes(attrs); + TagOrTempResult = Actions.ActOnExplicitInstantiation(getCurScope(), TemplateInfo.ExternLoc, @@ -1268,6 +1383,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, NameLoc, attrs.getList()); } else if (TUK == Sema::TUK_Friend && TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { + ProhibitAttributes(attrs); + TagOrTempResult = Actions.ActOnTemplatedFriendTag(getCurScope(), DS.getFriendSpecLoc(), TagType, StartLoc, SS, @@ -1281,6 +1398,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // FIXME: Diagnose this particular error. } + if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition) + ProhibitAttributes(attrs); + bool IsDependent = false; // Don't pass down template parameter lists if this is just a tag @@ -1344,77 +1464,19 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // impossible token occurs next, we assume that the programmer forgot a ; at // the end of the declaration and recover that way. // - // This switch enumerates the valid "follow" set for definition. - if (TUK == Sema::TUK_Definition) { - bool ExpectedSemi = true; - switch (Tok.getKind()) { - default: break; - case tok::semi: // struct foo {...} ; - case tok::star: // struct foo {...} * P; - case tok::amp: // struct foo {...} & R = ... - case tok::identifier: // struct foo {...} V ; - case tok::r_paren: //(struct foo {...} ) {4} - case tok::annot_cxxscope: // struct foo {...} a:: b; - case tok::annot_typename: // struct foo {...} a ::b; - case tok::annot_template_id: // struct foo {...} a<int> ::b; - case tok::l_paren: // struct foo {...} ( x); - case tok::comma: // __builtin_offsetof(struct foo{...} , - ExpectedSemi = false; - break; - // Type qualifiers - case tok::kw_const: // struct foo {...} const x; - case tok::kw_volatile: // struct foo {...} volatile x; - case tok::kw_restrict: // struct foo {...} restrict x; - case tok::kw_inline: // struct foo {...} inline foo() {}; - // Storage-class specifiers - case tok::kw_static: // struct foo {...} static x; - case tok::kw_extern: // struct foo {...} extern x; - case tok::kw_typedef: // struct foo {...} typedef x; - case tok::kw_register: // struct foo {...} register x; - case tok::kw_auto: // struct foo {...} auto x; - case tok::kw_mutable: // struct foo {...} mutable x; - case tok::kw_constexpr: // struct foo {...} constexpr x; - // As shown above, type qualifiers and storage class specifiers absolutely - // can occur after class specifiers according to the grammar. However, - // almost no one actually writes code like this. If we see one of these, - // it is much more likely that someone missed a semi colon and the - // type/storage class specifier we're seeing is part of the *next* - // intended declaration, as in: - // - // struct foo { ... } - // typedef int X; - // - // We'd really like to emit a missing semicolon error instead of emitting - // an error on the 'int' saying that you can't have two type specifiers in - // the same declaration of X. Because of this, we look ahead past this - // token to see if it's a type specifier. If so, we know the code is - // otherwise invalid, so we can produce the expected semi error. - if (!isKnownToBeTypeSpecifier(NextToken())) - ExpectedSemi = false; - break; - - case tok::r_brace: // struct bar { struct foo {...} } - // Missing ';' at end of struct is accepted as an extension in C mode. - if (!getLangOpts().CPlusPlus) - ExpectedSemi = false; - break; - } - - // C++ [temp]p3 In a template-declaration which defines a class, no - // declarator is permitted. - if (TemplateInfo.Kind) - ExpectedSemi = true; - - if (ExpectedSemi) { - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, - TagType == DeclSpec::TST_class ? "class" - : TagType == DeclSpec::TST_struct? "struct" : "union"); - // Push this token back into the preprocessor and change our current token - // to ';' so that the rest of the code recovers as though there were an - // ';' after the definition. - PP.EnterToken(Tok); - Tok.setKind(tok::semi); - } + // Also enforce C++ [temp]p3: + // In a template-declaration which defines a class, no declarator + // is permitted. + if (TUK == Sema::TUK_Definition && + (TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) { + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, + TagType == DeclSpec::TST_class ? "class" : + TagType == DeclSpec::TST_struct ? "struct" : "union"); + // Push this token back into the preprocessor and change our current token + // to ';' so that the rest of the code recovers as though there were an + // ';' after the definition. + PP.EnterToken(Tok); + Tok.setKind(tok::semi); } } @@ -1696,12 +1758,16 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } // Access declarations. + bool MalformedTypeSpec = false; if (!TemplateInfo.Kind && - (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && - !TryAnnotateCXXScopeToken() && - Tok.is(tok::annot_cxxscope)) { - bool isAccessDecl = false; - if (NextToken().is(tok::identifier)) + (Tok.is(tok::identifier) || Tok.is(tok::coloncolon))) { + if (TryAnnotateCXXScopeToken()) + MalformedTypeSpec = true; + + bool isAccessDecl; + if (Tok.isNot(tok::annot_cxxscope)) + isAccessDecl = false; + else if (NextToken().is(tok::identifier)) isAccessDecl = GetLookAheadToken(2).is(tok::semi); else isAccessDecl = NextToken().is(tok::kw_operator); @@ -1798,6 +1864,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this, TemplateDiags); DS.takeAttributesFrom(attrs); + if (MalformedTypeSpec) + DS.SetTypeSpecError(); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, &CommonLateParsedAttrs); @@ -1915,9 +1983,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, LateParsedAttrs.clear(); // Consume the ';' - it's optional unless we have a delete or default - if (Tok.is(tok::semi)) { - ConsumeToken(); - } + if (Tok.is(tok::semi)) + ConsumeExtraSemi(AfterMemberFunctionDefinition); return; } @@ -1961,18 +2028,19 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // goes before or after the GNU attributes and __asm__. ParseOptionalCXX0XVirtSpecifierSeq(VS); - bool HasDeferredInitializer = false; + InClassInitStyle HasInClassInit = ICIS_NoInit; if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) { if (BitfieldSize.get()) { Diag(Tok, diag::err_bitfield_member_init); SkipUntil(tok::comma, true, true); } else { HasInitializer = true; - HasDeferredInitializer = !DeclaratorInfo.isDeclarationOfFunction() && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() - != DeclSpec::SCS_static && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() - != DeclSpec::SCS_typedef; + if (!DeclaratorInfo.isDeclarationOfFunction() && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_static && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_typedef) + HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit; } } @@ -1990,7 +2058,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DeclaratorInfo, move(TemplateParams), BitfieldSize.release(), - VS, HasDeferredInitializer); + VS, HasInClassInit); if (AccessAttrs) Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs, false, true); @@ -2006,15 +2074,15 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, LateParsedAttrs.clear(); // Handle the initializer. - if (HasDeferredInitializer) { + if (HasInClassInit != ICIS_NoInit) { // The initializer was deferred; parse it and cache the tokens. Diag(Tok, getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_nonstatic_member_init : diag::ext_nonstatic_member_init); if (DeclaratorInfo.isArrayOfUnknownBound()) { - // C++0x [dcl.array]p3: An array bound may also be omitted when the - // declarator is followed by an initializer. + // C++11 [dcl.array]p3: An array bound may also be omitted when the + // declarator is followed by an initializer. // // A brace-or-equal-initializer for a member-declarator is not an // initializer in the grammar, so this is ill-formed. @@ -2266,10 +2334,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { - Diag(Tok, diag::ext_extra_struct_semi) - << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) - << FixItHint::CreateRemoval(Tok.getLocation()); - ConsumeToken(); + ConsumeExtraSemi(InsideStruct, TagType); continue; } @@ -2779,7 +2844,7 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf); if (std::isalpha(Spelling[0])) { Loc = ConsumeToken(); - return &PP.getIdentifierTable().get(Spelling.data()); + return &PP.getIdentifierTable().get(Spelling); } return 0; } @@ -2870,28 +2935,31 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, } bool AttrParsed = false; - // No scoped names are supported; ideally we could put all non-standard - // attributes into namespaces. - if (!ScopeName) { - switch (AttributeList::getKind(AttrName)) { - // No arguments - case AttributeList::AT_carries_dependency: - case AttributeList::AT_noreturn: { - if (Tok.is(tok::l_paren)) { - Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments) - << AttrName->getName(); - break; - } - - attrs.addNew(AttrName, AttrLoc, 0, AttrLoc, 0, - SourceLocation(), 0, 0, false, true); - AttrParsed = true; + switch (AttributeList::getKind(AttrName, ScopeName, + AttributeList::AS_CXX11)) { + // No arguments + case AttributeList::AT_CarriesDependency: + // FIXME: implement generic support of attributes with C++11 syntax + // see Parse/ParseDecl.cpp: ParseGNUAttributes + case AttributeList::AT_FallThrough: + case AttributeList::AT_NoReturn: { + if (Tok.is(tok::l_paren)) { + Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments) + << AttrName->getName(); break; } - // Silence warnings - default: break; - } + attrs.addNew(AttrName, + SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, + AttrLoc), + ScopeName, ScopeLoc, 0, + SourceLocation(), 0, 0, AttributeList::AS_CXX11); + AttrParsed = true; + break; + } + + // Silence warnings + default: break; } // Skip the entire parameter clause, if any @@ -2917,7 +2985,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, SkipUntil(tok::r_square, false); } -/// ParseCXX11Attributes - Parse a C++0x attribute-specifier-seq. +/// ParseCXX11Attributes - Parse a C++11 attribute-specifier-seq. /// /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier @@ -2991,10 +3059,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { - Diag(Tok, diag::ext_extra_struct_semi) - << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) - << FixItHint::CreateRemoval(Tok.getLocation()); - ConsumeToken(); + ConsumeExtraSemi(InsideStruct, TagType); continue; } |