summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp327
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;
}
OpenPOWER on IntegriCloud