summaryrefslogtreecommitdiffstats
path: root/lib/Parse/ParseDeclCXX.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-03-12 07:56:15 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-03-12 07:56:15 +0000
commit69730c115c2d0fec2f20609d905d920a5a41b29b (patch)
treee55b4541891864011b04424697b3619e3a5799ca /lib/Parse/ParseDeclCXX.cpp
parent0be8fb5bdfe7e07a57f07a740649ec8bfb690284 (diff)
Fix parsing of type-specifier-seq's. Types are syntactically allowed to be
defined here, but not semantically, so new struct S {}; is always ill-formed, even if there is a struct S in scope. We also had a couple of bugs in ParseOptionalTypeSpecifier caused by it being under-loved (due to it only being used in a few places) so merge it into ParseDeclarationSpecifiers with a new DeclSpecContext. To avoid regressing, this required improving ParseDeclarationSpecifiers' diagnostics in some cases. This also required teaching ParseSpecifierQualifierList about constexpr... which incidentally fixes an issue where we'd allow the constexpr specifier in other bad places. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152549 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseDeclCXX.cpp')
-rw-r--r--lib/Parse/ParseDeclCXX.cpp26
1 files changed, 12 insertions, 14 deletions
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 5b68c7a784..391db1987a 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -903,7 +903,7 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
/// 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
-/// cannot start a definition. If SuppressDeclarations is true, we do know.
+/// cannot start a definition.
///
/// class-specifier: [C++ class]
/// class-head '{' member-specification[opt] '}'
@@ -944,8 +944,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SourceLocation StartLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS,
- bool EnteringContext,
- bool SuppressDeclarations){
+ bool EnteringContext, DeclSpecContext DSC) {
DeclSpec::TST TagType;
if (TagTokKind == tok::kw_struct)
TagType = DeclSpec::TST_struct;
@@ -1120,18 +1119,17 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// 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.
- // However, in some contexts, things look like declarations but are just
- // references, e.g.
- // new struct s;
+ // 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, SuppressDeclarations is true.
+ // &T::operator struct s;
+ // For these, DSC is DSC_type_specifier.
Sema::TagUseKind TUK;
- if (SuppressDeclarations)
- TUK = Sema::TUK_Reference;
- else if (Tok.is(tok::l_brace) ||
- (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
- isCXX0XFinalKeyword()) {
+ 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 (DS.isFriendSpecified()) {
// C++ [class.friend]p2:
// A class shall not be defined in a friend declaration.
@@ -1146,7 +1144,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Okay, this is a class definition.
TUK = Sema::TUK_Definition;
}
- } else if (Tok.is(tok::semi))
+ } else if (Tok.is(tok::semi) && DSC != DSC_type_specifier)
TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration;
else
TUK = Sema::TUK_Reference;