diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 33f653d8f931..71aa38a15571 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1065,7 +1065,8 @@ private: bool ParseOptionalTypeSpecifier(DeclSpec &DS, bool &isInvalid, const char *&PrevSpec, unsigned &DiagID, - const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + bool SuppressDeclarations = false); void ParseSpecifierQualifierList(DeclSpec &DS); @@ -1311,7 +1312,8 @@ private: void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), - AccessSpecifier AS = AS_none); + AccessSpecifier AS = AS_none, + bool SuppressDeclarations = false); void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType, DeclPtrTy TagDecl); void ParseCXXClassMemberDeclaration(AccessSpecifier AS, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 5a5f5092db7f..996023830007 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1398,7 +1398,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, const char *&PrevSpec, unsigned &DiagID, - const ParsedTemplateInfo &TemplateInfo) { + const ParsedTemplateInfo &TemplateInfo, + bool SuppressDeclarations) { SourceLocation Loc = Tok.getLocation(); switch (Tok.getKind()) { @@ -1408,7 +1409,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, - TemplateInfo); + TemplateInfo, SuppressDeclarations); // Otherwise, not a type specifier. return false; case tok::coloncolon: // ::foo::bar @@ -1420,7 +1421,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, - TemplateInfo); + TemplateInfo, SuppressDeclarations); // Otherwise, not a type specifier. return false; @@ -1526,7 +1527,8 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); ConsumeToken(); - ParseClassSpecifier(Kind, Loc, DS, TemplateInfo); + ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS_none, + SuppressDeclarations); return true; } diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index f95fedc4e3a2..07bae1c7a4b7 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -547,7 +547,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, /// 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. +/// cannot start a definition. If SuppressDeclarations is true, we do know. /// /// class-specifier: [C++ class] /// class-head '{' member-specification[opt] '}' @@ -587,7 +587,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation StartLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, - AccessSpecifier AS) { + AccessSpecifier AS, bool SuppressDeclarations){ DeclSpec::TST TagType; if (TagTokKind == tok::kw_struct) TagType = DeclSpec::TST_struct; @@ -733,8 +733,16 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // have to be treated differently. If we have 'struct foo {...' or // 'struct foo :...' 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; + // or + // &T::operator struct s; + // For these, SuppressDeclarations is true. Action::TagUseKind TUK; - if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))) { + if (SuppressDeclarations) + TUK = Action::TUK_Reference; + else if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))){ if (DS.isFriendSpecified()) { // C++ [class.friend]p2: // A class shall not be defined in a friend declaration. diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index ca50ef400092..0dbe1ea83890 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -763,12 +763,15 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { bool isInvalid = 0; // Parse one or more of the type specifiers. - if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID)) { + if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, + ParsedTemplateInfo(), /*SuppressDeclarations*/true)) { Diag(Tok, diag::err_operator_missing_type_specifier); return true; } - while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID)) ; + while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, + ParsedTemplateInfo(), /*SuppressDeclarations*/true)) + {} return false; } diff --git a/clang/test/CXX/dcl.decl/dcl.name/p1.cpp b/clang/test/CXX/dcl.decl/dcl.name/p1.cpp new file mode 100644 index 000000000000..7586007cc7b3 --- /dev/null +++ b/clang/test/CXX/dcl.decl/dcl.name/p1.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +namespace pr6200 { + struct v {}; + struct s { + int i; + operator struct v() { return v(); }; + }; + + void f() + { + // Neither of these is a declaration. + (void)new struct s; + (void)&s::operator struct v; + } +}