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
This commit is contained in:
Richard Smith 2012-03-12 07:56:15 +00:00
Родитель 0be8fb5bdf
Коммит 69730c115c
17 изменённых файлов: 113 добавлений и 385 удалений

Просмотреть файл

@ -280,9 +280,11 @@ def err_typename_invalid_storageclass : Error<
"type name does not allow storage class to be specified">;
def err_typename_invalid_functionspec : Error<
"type name does not allow function specifier to be specified">;
def err_typename_invalid_constexpr : Error<
"type name does not allow constexpr specifier to be specified">;
def err_typename_identifiers_only : Error<
"typename is allowed for identifiers only">;
def err_invalid_decl_spec_combination : Error<
"cannot combine with previous '%0' declaration specifier">;
def err_invalid_vector_decl_spec_combination : Error<

Просмотреть файл

@ -1621,6 +1621,7 @@ private:
enum DeclSpecContext {
DSC_normal, // normal context
DSC_class, // class context, enables 'friend'
DSC_type_specifier, // C++ type-specifier-seq
DSC_top_level // top-level/namespace declaration context
};
@ -1663,27 +1664,23 @@ private:
bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS);
AccessSpecifier AS, DeclSpecContext DSC);
DeclSpecContext getDeclSpecContextFromDeclaratorContext(unsigned Context);
void ParseDeclarationSpecifiers(DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
AccessSpecifier AS = AS_none,
DeclSpecContext DSC = DSC_normal,
LateParsedAttrList *LateAttrs = 0);
bool ParseOptionalTypeSpecifier(DeclSpec &DS, bool &isInvalid,
const char *&PrevSpec,
unsigned &DiagID,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
bool SuppressDeclarations = false);
void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none);
void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none,
DeclSpecContext DSC = DSC_normal);
void ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
Declarator::TheContext Context);
void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
AccessSpecifier AS = AS_none);
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS, DeclSpecContext DSC);
void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl);
void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType,
Decl *TagDecl);
@ -2060,11 +2057,9 @@ private:
//===--------------------------------------------------------------------===//
// C++ 9: classes [class] and C structs/unions.
void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc,
DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
AccessSpecifier AS = AS_none,
bool EnteringContext = false,
bool SuppressDeclarations = false);
DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS, bool EnteringContext,
DeclSpecContext DSC);
void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
Decl *TagDecl);
ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction,

Просмотреть файл

@ -614,6 +614,11 @@ public:
bool isConstexprSpecified() const { return Constexpr_specified; }
SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; }
void ClearConstexprSpec() {
Constexpr_specified = false;
ConstexprLoc = SourceLocation();
}
AttributePool &getAttributePool() const {
return Attrs.getPool();
}

Просмотреть файл

@ -1424,17 +1424,24 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
/// type-qualifier specifier-qualifier-list[opt]
/// [GNU] attributes specifier-qualifier-list[opt]
///
void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS) {
void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
DeclSpecContext DSC) {
/// specifier-qualifier-list is a subset of declaration-specifiers. Just
/// parse declaration-specifiers and complain about extra stuff.
/// TODO: diagnose attribute-specifiers and alignment-specifiers.
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC);
// Validate declspec for type-name.
unsigned Specs = DS.getParsedSpecifiers();
if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
!DS.hasAttributes())
if (DSC == DSC_type_specifier && !DS.hasTypeSpecifier()) {
Diag(Tok, diag::err_expected_type);
DS.SetTypeSpecError();
} else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
!DS.hasAttributes()) {
Diag(Tok, diag::err_typename_requires_specqual);
if (!DS.hasTypeSpecifier())
DS.SetTypeSpecError();
}
// Issue diagnostic and remove storage class if present.
if (Specs & DeclSpec::PQ_StorageClassSpecifier) {
@ -1455,6 +1462,12 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS) {
Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
DS.ClearFunctionSpecs();
}
// Issue diagnostic and remove constexpr specfier if present.
if (DS.isConstexprSpecified()) {
Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
DS.ClearConstexprSpec();
}
}
/// isValidAfterIdentifierInDeclaratorAfterDeclSpec - Return true if the
@ -1493,7 +1506,7 @@ static bool isValidAfterIdentifierInDeclarator(const Token &T) {
///
bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS) {
AccessSpecifier AS, DeclSpecContext DSC) {
assert(Tok.is(tok::identifier) && "should have identifier");
SourceLocation Loc = Tok.getLocation();
@ -1512,8 +1525,13 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
assert(!DS.hasTypeSpecifier() && "Type specifier checked above");
// Since we know that this either implicit int (which is rare) or an
// error, we'd do lookahead to try to do better recovery.
if (isValidAfterIdentifierInDeclarator(NextToken())) {
// error, do lookahead to try to do better recovery. This never applies within
// a type specifier.
// FIXME: Don't bail out here in languages with no implicit int (like
// C++ with no -fms-extensions). This is much more likely to be an undeclared
// type or typo than a use of implicit int.
if (DSC != DSC_type_specifier &&
isValidAfterIdentifierInDeclarator(NextToken())) {
// If this token is valid for implicit int, e.g. "static x = 4", then
// we just avoid eating the identifier, so it will be parsed as the
// identifier in the declarator.
@ -1549,9 +1567,10 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// Parse this as a tag as if the missing tag were present.
if (TagKind == tok::kw_enum)
ParseEnumSpecifier(Loc, DS, TemplateInfo, AS);
ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSC_normal);
else
ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS);
ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS,
/*EnteringContext*/ false, DSC_normal);
return true;
}
}
@ -1585,9 +1604,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
}
// Mark this as an error.
const char *PrevSpec;
unsigned DiagID;
DS.SetTypeSpecType(DeclSpec::TST_error, Loc, PrevSpec, DiagID);
DS.SetTypeSpecError();
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken();
@ -1895,7 +1912,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// typename.
if (TypeRep == 0) {
ConsumeToken(); // Eat the scope spec so the identifier is current.
if (ParseImplicitInt(DS, &SS, TemplateInfo, AS)) continue;
if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext)) continue;
goto DoneWithDeclSpec;
}
@ -1979,7 +1996,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
break;
// It has to be available as a typedef too!
ParsedType TypeRep =
Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), getCurScope());
@ -1987,7 +2003,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If this is not a typedef name, don't parse it as part of the declspec,
// it must be an implicit int or an error.
if (!TypeRep) {
if (ParseImplicitInt(DS, 0, TemplateInfo, AS)) continue;
if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext)) continue;
goto DoneWithDeclSpec;
}
@ -2276,14 +2292,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw_union: {
tok::TokenKind Kind = Tok.getKind();
ConsumeToken();
ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS, EnteringContext);
ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS,
EnteringContext, DSContext);
continue;
}
// enum-specifier:
case tok::kw_enum:
ConsumeToken();
ParseEnumSpecifier(Loc, DS, TemplateInfo, AS);
ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSContext);
continue;
// cv-qualifier:
@ -2375,301 +2392,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
}
/// ParseOptionalTypeSpecifier - Try to parse a single type-specifier. We
/// primarily follow the C++ grammar with additions for C99 and GNU,
/// which together subsume the C grammar. Note that the C++
/// type-specifier also includes the C type-qualifier (for const,
/// volatile, and C99 restrict). Returns true if a type-specifier was
/// found (and parsed), false otherwise.
///
/// type-specifier: [C++ 7.1.5]
/// simple-type-specifier
/// class-specifier
/// enum-specifier
/// elaborated-type-specifier [TODO]
/// cv-qualifier
///
/// cv-qualifier: [C++ 7.1.5.1]
/// 'const'
/// 'volatile'
/// [C99] 'restrict'
///
/// simple-type-specifier: [ C++ 7.1.5.2]
/// '::'[opt] nested-name-specifier[opt] type-name [TODO]
/// '::'[opt] nested-name-specifier 'template' template-id [TODO]
/// 'char'
/// 'wchar_t'
/// 'bool'
/// 'short'
/// 'int'
/// 'long'
/// 'signed'
/// 'unsigned'
/// 'float'
/// 'double'
/// 'void'
/// [C99] '_Bool'
/// [C99] '_Complex'
/// [C99] '_Imaginary' // Removed in TC2?
/// [GNU] '_Decimal32'
/// [GNU] '_Decimal64'
/// [GNU] '_Decimal128'
/// [GNU] typeof-specifier
/// [OBJC] class-name objc-protocol-refs[opt] [TODO]
/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO]
/// [C++0x] 'decltype' ( expression )
/// [AltiVec] '__vector'
bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
const char *&PrevSpec,
unsigned &DiagID,
const ParsedTemplateInfo &TemplateInfo,
bool SuppressDeclarations) {
SourceLocation Loc = Tok.getLocation();
switch (Tok.getKind()) {
case tok::identifier: // foo::bar
// If we already have a type specifier, this identifier is not a type.
if (DS.getTypeSpecType() != DeclSpec::TST_unspecified ||
DS.getTypeSpecWidth() != DeclSpec::TSW_unspecified ||
DS.getTypeSpecSign() != DeclSpec::TSS_unspecified)
return false;
// Check for need to substitute AltiVec keyword tokens.
if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
break;
// Fall through.
case tok::kw_decltype:
case tok::kw_typename: // typename foo::bar
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken(/*EnteringContext=*/false,
/*NeedType=*/true))
return true;
if (Tok.is(tok::identifier))
return false;
return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
TemplateInfo, SuppressDeclarations);
case tok::coloncolon: // ::foo::bar
if (NextToken().is(tok::kw_new) || // ::new
NextToken().is(tok::kw_delete)) // ::delete
return false;
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken(/*EnteringContext=*/false,
/*NeedType=*/true))
return true;
return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
TemplateInfo, SuppressDeclarations);
// simple-type-specifier:
case tok::annot_typename: {
if (ParsedType T = getTypeAnnotation(Tok)) {
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
Tok.getAnnotationEndLoc(), PrevSpec,
DiagID, T);
} else
DS.SetTypeSpecError();
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeToken(); // The typename
// Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
// is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
// Objective-C interface. If we don't have Objective-C or a '<', this is
// just a normal reference to a typedef name.
if (Tok.is(tok::less) && getLangOpts().ObjC1)
ParseObjCProtocolQualifiers(DS);
return true;
}
case tok::kw_short:
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID);
break;
case tok::kw_long:
if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec,
DiagID);
else
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
DiagID);
break;
case tok::kw___int64:
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
DiagID);
break;
case tok::kw_signed:
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID);
break;
case tok::kw_unsigned:
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec,
DiagID);
break;
case tok::kw__Complex:
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec,
DiagID);
break;
case tok::kw__Imaginary:
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec,
DiagID);
break;
case tok::kw_void:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID);
break;
case tok::kw_char:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID);
break;
case tok::kw_int:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID);
break;
case tok::kw_half:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID);
break;
case tok::kw_float:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID);
break;
case tok::kw_double:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID);
break;
case tok::kw_wchar_t:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID);
break;
case tok::kw_char16_t:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID);
break;
case tok::kw_char32_t:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID);
break;
case tok::kw_bool:
case tok::kw__Bool:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
break;
case tok::kw__Decimal32:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec,
DiagID);
break;
case tok::kw__Decimal64:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec,
DiagID);
break;
case tok::kw__Decimal128:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
DiagID);
break;
case tok::kw___vector:
isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
break;
case tok::kw___pixel:
isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
break;
// class-specifier:
case tok::kw_class:
case tok::kw_struct:
case tok::kw_union: {
tok::TokenKind Kind = Tok.getKind();
ConsumeToken();
ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS_none,
/*EnteringContext=*/false,
SuppressDeclarations);
return true;
}
// enum-specifier:
case tok::kw_enum:
ConsumeToken();
ParseEnumSpecifier(Loc, DS, TemplateInfo, AS_none);
return true;
// cv-qualifier:
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
DiagID, getLangOpts());
break;
case tok::kw_volatile:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
DiagID, getLangOpts());
break;
case tok::kw_restrict:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
DiagID, getLangOpts());
break;
// GNU typeof support.
case tok::kw_typeof:
ParseTypeofSpecifier(DS);
return true;
// C++0x decltype support.
case tok::annot_decltype:
ParseDecltypeSpecifier(DS);
return true;
// C++0x type traits support.
case tok::kw___underlying_type:
ParseUnderlyingTypeSpecifier(DS);
return true;
case tok::kw__Atomic:
ParseAtomicSpecifier(DS);
return true;
// OpenCL qualifiers:
case tok::kw_private:
if (!getLangOpts().OpenCL)
return false;
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
case tok::kw___constant:
case tok::kw___read_only:
case tok::kw___write_only:
case tok::kw___read_write:
ParseOpenCLQualifiers(DS);
break;
// C++0x auto support.
case tok::kw_auto:
// This is only called in situations where a storage-class specifier is
// illegal, so we can assume an auto type specifier was intended even in
// C++98. In C++98 mode, DeclSpec::Finish will produce an appropriate
// extension diagnostic.
if (!getLangOpts().CPlusPlus)
return false;
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID);
break;
case tok::kw___ptr64:
case tok::kw___ptr32:
case tok::kw___w64:
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
case tok::kw___unaligned:
ParseMicrosoftTypeAttributes(DS.getAttributes());
return true;
case tok::kw___pascal:
ParseBorlandTypeAttributes(DS.getAttributes());
return true;
default:
// Not a type-specifier; do nothing.
return false;
}
// If the specifier combination wasn't legal, issue a diagnostic.
if (isInvalid) {
assert(PrevSpec && "Method did not return previous specifier!");
// Pick between error or extwarn.
Diag(Tok, DiagID) << PrevSpec;
}
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken(); // whatever we parsed above.
return true;
}
/// ParseStructDeclaration - Parse a struct declaration without the terminating
/// semicolon.
///
@ -2905,7 +2627,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
///
void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS) {
AccessSpecifier AS, DeclSpecContext DSC) {
// Parse the tag portion of this.
if (Tok.is(tok::code_completion)) {
// Code completion for an enum name.
@ -3065,7 +2787,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
TUK = Sema::TUK_Friend;
else if (Tok.is(tok::l_brace))
TUK = Sema::TUK_Definition;
else if (Tok.is(tok::semi))
else if (Tok.is(tok::semi) && DSC != DSC_type_specifier)
TUK = Sema::TUK_Declaration;
else
TUK = Sema::TUK_Reference;

Просмотреть файл

@ -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;

Просмотреть файл

@ -1551,22 +1551,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
/// type-specifier type-specifier-seq[opt]
///
bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
DS.SetRangeStart(Tok.getLocation());
const char *PrevSpec = 0;
unsigned DiagID;
bool isInvalid = 0;
// Parse one or more of the type specifiers.
if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
ParsedTemplateInfo(), /*SuppressDeclarations*/true)) {
Diag(Tok, diag::err_expected_type);
return true;
}
while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
ParsedTemplateInfo(), /*SuppressDeclarations*/true))
{}
ParseSpecifierQualifierList(DS, AS_none, DSC_type_specifier);
DS.Finish(Diags, PP);
return false;
}

Просмотреть файл

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -fcxx-exceptions
using X = struct { // ok
};
@ -7,21 +7,21 @@ template<typename T> using Y = struct { // expected-error {{can not be defined i
class K {
virtual ~K();
// FIXME: Diagnostic could use some work
operator struct S {} (); // expected-error{{'operator S' cannot be the name of a variable or data member}} \
// expected-error{{expected ';' at end of declaration list}}
operator struct S {} (); // expected-error{{'K::S' can not be defined in a type specifier}}
};
struct A {};
void f() {
int arr[3] = {1,2,3};
for (struct S { S(int) {} } s : arr) { // expected-error {{types may not be defined in a for range declaration}}
}
new struct T {}; // expected-error {{allocation of incomplete type}} expected-note {{forward declaration}}
new struct T {}; // expected-error {{'T' can not be defined in a type specifier}}
new struct A {}; // expected-error {{'A' can not be defined in a type specifier}}
// FIXME: the diagnostic here isn't very good
try {} catch (struct U {}); // expected-error 3{{}} expected-note 2{{}}
try {} catch (struct U {}) {} // expected-error {{'U' can not be defined in a type specifier}}
(void)(struct V { V(int); })0; // expected-error {{'V' can not be defined in a type specifier}}

Просмотреть файл

@ -17,9 +17,10 @@ namespace IllegalTypeIds {
using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
using F = void(*)(int n) &&; // expected-error {{pointer to function type cannot have '&&' qualifier}}
using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
using H = constexpr int; // expected-error {{type name does not allow constexpr specifier}}
using H = void(int n); // ok
using I = void(int n) &&; // ok
using Y = void(int n); // ok
using Z = void(int n) &&; // ok
}
namespace IllegalSyntax {
@ -123,9 +124,8 @@ namespace TagName {
}
namespace CWG1044 {
// FIXME: this is terrible. one error is plenty.
// FIXME: this diagnostic isn't ideal. one diagnostic is enough.
using T = T; // expected-error {{type name requires a specifier}} \
expected-error {{C++ requires a type specifier}} \
expected-error {{expected ';' after alias declaration}}
}

Просмотреть файл

@ -2,15 +2,19 @@
namespace pr6200 {
struct v {};
enum E { e };
struct s {
int i;
operator struct v() { return v(); };
operator enum E() { return e; }
};
void f()
{
// Neither of these is a declaration.
// None of these is a declaration.
(void)new struct s;
(void)new enum E;
(void)&s::operator struct v;
(void)&s::operator enum E;
}
}

Просмотреть файл

@ -0,0 +1,20 @@
// RUN: %clang_cc1 -verify %s -std=c++11 -fcxx-exceptions
// Tests for parsing of type-specifier-seq
struct S {
operator constexpr int(); // expected-error{{type name does not allow constexpr}}
};
enum E { e };
void f() {
try {
(void) new constexpr int; // expected-error{{type name does not allow constexpr}}
} catch (constexpr int) { // expected-error{{type name does not allow constexpr}}
}
// These parse as type definitions, not as type references with braced
// initializers. Sad but true...
(void) new struct S {}; // expected-error{{'S' can not be defined in a type specifier}}
(void) new enum E { e }; // expected-error{{'E' can not be defined in a type specifier}}
}

Просмотреть файл

@ -3,8 +3,6 @@
typedef struct _zend_module_entry zend_module_entry;
struct _zend_module_entry {
_efree((p)); // expected-error{{type name requires a specifier or qualifier}} \
expected-error{{field '_efree' declared as a function}} \
expected-warning {{type specifier missing, defaults to 'int'}} \
expected-warning {{type specifier missing, defaults to 'int'}}
};

Просмотреть файл

@ -14,9 +14,10 @@ namespace IllegalTypeIds {
template<typename U> using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
template<typename U> using F = void(*)(int n) &&; // expected-error {{pointer to function type cannot have '&&' qualifier}}
template<typename U> using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
template<typename U> using H = constexpr int; // expected-error {{type name does not allow constexpr specifier}}
template<typename U> using H = void(int n); // ok
template<typename U> using I = void(int n) &&; // ok
template<typename U> using Y = void(int n); // ok
template<typename U> using Z = void(int n) &&; // ok
}
namespace IllegalSyntax {

Просмотреть файл

@ -8,7 +8,7 @@ void test() {
x.int; // expected-error{{expected unqualified-id}}
x.~int(); // expected-error{{expected a class name}}
x.operator; // expected-error{{expected a type}}
x.operator typedef; // expected-error{{expected a type}}
x.operator typedef; // expected-error{{expected a type}} expected-error{{type name does not allow storage class}}
}
void test2() {
@ -17,7 +17,7 @@ void test2() {
x->int; // expected-error{{expected unqualified-id}}
x->~int(); // expected-error{{expected a class name}}
x->operator; // expected-error{{expected a type}}
x->operator typedef; // expected-error{{expected a type}}
x->operator typedef; // expected-error{{expected a type}} expected-error{{type name does not allow storage class}}
}
// PR6327

Просмотреть файл

@ -4,7 +4,7 @@ namespace fizbin { class Foobar {}; } // expected-note 2 {{'fizbin::Foobar' decl
// expected-note {{'Foobar' declared here}}
Foobar *my_bar // expected-error{{unknown type name 'Foobar'; did you mean 'fizbin::Foobar'?}}
= new Foobar; // expected-error{{unknown type name 'Foobar'; did you mean 'fizbin::Foobar'?}}
fizbin::Foobar *my_foo = new fizbin::FooBar; // expected-error{{unknown type name 'FooBar'; did you mean 'Foobar'?}}
fizbin::Foobar *my_foo = new fizbin::FooBar; // expected-error{{no type named 'FooBar' in namespace 'fizbin'; did you mean 'Foobar'?}}
namespace barstool { int toFoobar() { return 1; } } // expected-note 3 {{'barstool::toFoobar' declared here}}
int Double(int x) { return x + x; }
@ -64,14 +64,13 @@ void f() {
// Test case from http://llvm.org/bugs/show_bug.cgi?id=10318
namespace llvm {
template <typename T> class GraphWriter {}; // expected-note {{'llvm::GraphWriter' declared here}} \
// expected-note {{'GraphWriter' declared here}}
template <typename T> class GraphWriter {}; // expected-note 3{{declared here}}
}
struct S {};
void bar() {
GraphWriter<S> x; //expected-error{{no template named 'GraphWriter'; did you mean 'llvm::GraphWriter'?}}
(void)new llvm::GraphWriter; // expected-error {{expected a type}}
(void)new llvm::GraphWriter; // expected-error {{use of class template llvm::GraphWriter requires template arguments}}
(void)new llvm::Graphwriter<S>; // expected-error {{no template named 'Graphwriter' in namespace 'llvm'; did you mean 'GraphWriter'?}}
}

Просмотреть файл

@ -387,7 +387,7 @@ namespace PairedDelete {
namespace PR7702 {
void test1() {
new DoesNotExist; // expected-error {{expected a type}}
new DoesNotExist; // expected-error {{unknown type name 'DoesNotExist'}}
}
}

Просмотреть файл

@ -44,8 +44,7 @@ typedef signed char BOOL;
}
@property (readonly) int; // expected-warning {{declaration does not declare anything}}
@property (readonly) ; // expected-error {{type name requires a specifier or qualifier}} \
expected-warning {{declaration does not declare anything}}
@property (readonly) ; // expected-error {{type name requires a specifier or qualifier}}
@property (readonly) int : 4; // expected-error {{property requires fields to be named}}

Просмотреть файл

@ -2,7 +2,7 @@
// Note that the error count below doesn't matter. We just want to
// make sure that the parser doesn't crash.
// CHECK: 14 errors
// CHECK: 13 errors
// PR7511
template<a>