summaryrefslogtreecommitdiffstats
path: root/clang/lib/Parse/ParseDeclCXX.cpp
diff options
context:
space:
mode:
authorMichael Han <Michael.Han@autodesk.com>2012-11-26 22:54:45 +0000
committerMichael Han <Michael.Han@autodesk.com>2012-11-26 22:54:45 +0000
commit9407e50b041301bbd7ba458bc910db94b94d5da3 (patch)
tree21113ab926f92a1ee4eabec5e214c84351708a7d /clang/lib/Parse/ParseDeclCXX.cpp
parent9fb21e57e557e1f3166cd3ab1b9ff05c09165b71 (diff)
downloadbcm5719-llvm-9407e50b041301bbd7ba458bc910db94b94d5da3.tar.gz
bcm5719-llvm-9407e50b041301bbd7ba458bc910db94b94d5da3.zip
Improve diagnostic on C++11 attribute specifiers that appear at wrong syntactic locations around class specifiers.
This change list implemented logic that explicitly detects several combinations of locations where C++11 attribute specifiers might be incorrectly placed within a class specifier. Previously we emit generic diagnostics like "expected identifier" for such cases; now we emit specific diagnostic against the misplaced attributes, this also fixed a bug in old code where attributes appear at legitimate locations were incorrectly rejected. Thanks to Richard Smith for reviewing! llvm-svn: 168626
Diffstat (limited to 'clang/lib/Parse/ParseDeclCXX.cpp')
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp59
1 files changed, 58 insertions, 1 deletions
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index b8ebd9b6a7e..700cf4e4afd 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1052,7 +1052,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SourceLocation StartLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS,
- bool EnteringContext, DeclSpecContext DSC) {
+ bool EnteringContext, DeclSpecContext DSC,
+ ParsedAttributesWithRange &Attributes) {
DeclSpec::TST TagType;
if (TagTokKind == tok::kw_struct)
TagType = DeclSpec::TST_struct;
@@ -1234,12 +1235,24 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// - 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.
+ //
+ // We also detect these erroneous cases to provide better diagnostic for
+ // C++11 attributes parsing.
+ // - attributes follow class name:
+ // struct foo [[]] {};
+ // - attributes appear before or after 'final':
+ // struct foo [[]] final [[]] {};
+ //
// However, in type-specifier-seq's, things look like declarations but are
// just references, e.g.
// new struct s;
// or
// &T::operator struct s;
// For these, DSC is DSC_type_specifier.
+
+ // If there are attributes after class name, parse them.
+ MaybeParseCXX0XAttributes(Attributes);
+
Sema::TagUseKind TUK;
if (DSC == DSC_trailing)
TUK = Sema::TUK_Reference;
@@ -1261,6 +1274,39 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Okay, this is a class definition.
TUK = Sema::TUK_Definition;
}
+ } else if (isCXX0XFinalKeyword() && (NextToken().is(tok::l_square) ||
+ NextToken().is(tok::kw_alignas) ||
+ NextToken().is(tok::kw__Alignas))) {
+ // We can't tell if this is a definition or reference
+ // until we skipped the 'final' and C++11 attribute specifiers.
+ TentativeParsingAction PA(*this);
+
+ // Skip the 'final' keyword.
+ ConsumeToken();
+
+ // Skip C++11 attribute specifiers.
+ while (true) {
+ if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) {
+ ConsumeBracket();
+ if (!SkipUntil(tok::r_square))
+ break;
+ } else if ((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) &&
+ NextToken().is(tok::l_paren)) {
+ ConsumeToken();
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ break;
+ } else {
+ break;
+ }
+ }
+
+ if (Tok.is(tok::l_brace) || Tok.is(tok::colon))
+ TUK = Sema::TUK_Definition;
+ else
+ TUK = Sema::TUK_Reference;
+
+ PA.Revert();
} else if (DSC != DSC_type_specifier &&
(Tok.is(tok::semi) ||
(Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(false)))) {
@@ -1275,6 +1321,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} else
TUK = Sema::TUK_Reference;
+ // Forbid misplaced attributes. In cases of a reference, we pass attributes
+ // to caller to handle.
+ // FIXME: provide fix-it hints if we can.
+ if (TUK != Sema::TUK_Reference)
+ ProhibitAttributes(Attributes);
+
// If this is an elaborated type specifier, and we delayed
// diagnostics before, just merge them into the current pool.
if (shouldDelayDiagsInTag) {
@@ -2326,6 +2378,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
diag::warn_cxx98_compat_override_control_keyword :
diag::ext_override_control_keyword) << "final";
}
+
+ // Forbid C++11 attributes that appear here.
+ ParsedAttributesWithRange Attrs(AttrFactory);
+ MaybeParseCXX0XAttributes(Attrs);
+ ProhibitAttributes(Attrs);
}
if (Tok.is(tok::colon)) {
OpenPOWER on IntegriCloud