Process and handle attributes on conditions and for loop variables. Process and

diagnose attributes on alias declarations, using directives, and attribute
declarations.

llvm-svn: 175649
This commit is contained in:
Richard Smith 2013-02-20 19:22:51 +00:00
parent 5cdb345883
commit 54ecd9863f
11 changed files with 86 additions and 35 deletions

View File

@ -1908,6 +1908,8 @@ def warn_attribute_not_on_decl : Warning<
"%0 attribute ignored when parsing type">, InGroup<IgnoredAttributes>;
def err_base_specifier_attribute : Error<
"%0 attribute cannot be applied to a base specifier">;
def err_attribute_declaration : Error<
"%0 attribute cannot be used in an attribute declaration">;
// Availability attribute
def warn_availability_unknown_platform : Warning<

View File

@ -1800,7 +1800,8 @@ public:
Declarator::TheContext Context
= Declarator::TypeNameContext,
AccessSpecifier AS = AS_none,
Decl **OwnedType = 0);
Decl **OwnedType = 0,
ParsedAttributes *Attrs = 0);
private:
void ParseBlockId(SourceLocation CaretLoc);

View File

@ -1447,6 +1447,9 @@ public:
SourceLocation AsmLoc,
SourceLocation RParenLoc);
/// \brief Handle a C++11 attribute-declaration.
void ActOnAttributeDeclaration(AttributeList *AttrList);
/// \brief The parser has processed a module import declaration.
///
/// \param AtLoc The location of the '@' symbol, if any.
@ -3429,6 +3432,7 @@ public:
MultiTemplateParamsArg TemplateParams,
SourceLocation UsingLoc,
UnqualifiedId &Name,
AttributeList *AttrList,
TypeResult Type);
/// BuildCXXConstructExpr - Creates a complete call to a constructor,

View File

@ -38,13 +38,16 @@ using namespace clang;
TypeResult Parser::ParseTypeName(SourceRange *Range,
Declarator::TheContext Context,
AccessSpecifier AS,
Decl **OwnedType) {
Decl **OwnedType,
ParsedAttributes *Attrs) {
DeclSpecContext DSC = getDeclSpecContextFromDeclaratorContext(Context);
if (DSC == DSC_normal)
DSC = DSC_type_specifier;
// Parse the common declaration-specifiers piece.
DeclSpec DS(AttrFactory);
if (Attrs)
DS.addAttributes(Attrs->getList());
ParseSpecifierQualifierList(DS, AS, DSC);
if (OwnedType)
*OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;

View File

@ -451,24 +451,21 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
Decl **OwnedType) {
CXXScopeSpec SS;
SourceLocation TypenameLoc;
bool IsTypeName;
ParsedAttributesWithRange attrs(AttrFactory);
bool IsTypeName = false;
ParsedAttributesWithRange Attrs(AttrFactory);
// FIXME: Simply skip the attributes and diagnose, don't bother parsing them.
MaybeParseCXX11Attributes(attrs);
ProhibitAttributes(attrs);
attrs.clear();
attrs.Range = SourceRange();
MaybeParseCXX11Attributes(Attrs);
ProhibitAttributes(Attrs);
Attrs.clear();
Attrs.Range = SourceRange();
// Ignore optional 'typename'.
// FIXME: This is wrong; we should parse this as a typename-specifier.
if (Tok.is(tok::kw_typename)) {
TypenameLoc = Tok.getLocation();
ConsumeToken();
TypenameLoc = ConsumeToken();
IsTypeName = true;
}
else
IsTypeName = false;
// Parse nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
@ -495,14 +492,13 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
return 0;
}
MaybeParseCXX11Attributes(attrs);
MaybeParseCXX11Attributes(Attrs);
// Maybe this is an alias-declaration.
bool IsAliasDecl = Tok.is(tok::equal);
TypeResult TypeAlias;
if (IsAliasDecl) {
// TODO: Attribute support. C++0x attributes may appear before the equals.
// Where can GNU attributes appear?
// TODO: Can GNU attributes appear here?
ConsumeToken();
Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
@ -547,20 +543,21 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
TypeAlias = ParseTypeName(0, TemplateInfo.Kind ?
Declarator::AliasTemplateContext :
Declarator::AliasDeclContext, AS, OwnedType);
Declarator::AliasDeclContext, AS, OwnedType,
&Attrs);
} else {
// C++11 attributes are not allowed on a using-declaration, but GNU ones
// are.
ProhibitAttributes(attrs);
ProhibitAttributes(Attrs);
// Parse (optional) attributes (most likely GNU strong-using extension).
MaybeParseGNUAttributes(attrs);
MaybeParseGNUAttributes(Attrs);
}
// Eat ';'.
DeclEnd = Tok.getLocation();
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
!attrs.empty() ? "attributes list" :
!Attrs.empty() ? "attributes list" :
IsAliasDecl ? "alias declaration" : "using declaration",
tok::semi);
@ -592,13 +589,13 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
MultiTemplateParamsArg TemplateParamsArg(
TemplateParams ? TemplateParams->data() : 0,
TemplateParams ? TemplateParams->size() : 0);
// FIXME: Propagate attributes.
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
UsingLoc, Name, TypeAlias);
UsingLoc, Name, Attrs.getList(),
TypeAlias);
}
return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS,
Name, attrs.getList(),
Name, Attrs.getList(),
IsTypeName, TypenameLoc);
}

View File

@ -1383,6 +1383,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
// type-specifier-seq
DeclSpec DS(AttrFactory);
DS.takeAttributesFrom(attrs);
ParseSpecifierQualifierList(DS);
// declarator

View File

@ -1385,9 +1385,6 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode?
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
// In C++0x, "for (T NS:a" might not be a typo for ::
bool MightBeForRangeStmt = getLangOpts().CPlusPlus;
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);

View File

@ -566,7 +566,6 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
/// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl]
/// function-definition
/// declaration
/// [C++0x] empty-declaration
/// [GNU] asm-definition
/// [GNU] __extension__ external-declaration
/// [OBJC] objc-class-definition
@ -578,8 +577,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
/// [C++] linkage-specification
/// [GNU] asm-definition:
/// simple-asm-expr ';'
/// [C++11] empty-declaration
/// [C++11] attribute-declaration
///
/// [C++0x] empty-declaration:
/// [C++11] empty-declaration:
/// ';'
///
/// [C++0x/GNU] 'extern' 'template' declaration
@ -624,6 +625,13 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
HandlePragmaOpenCLExtension();
return DeclGroupPtrTy();
case tok::semi:
// Either a C++11 empty-declaration or attribute-declaration.
if (attrs.Range.isValid()) {
// FIXME: Add an AST representation for this.
Actions.ActOnAttributeDeclaration(attrs.getList());
return DeclGroupPtrTy();
}
ConsumeExtraSemi(OutsideFunction);
// TODO: Invoke action for top-level semicolon.
return DeclGroupPtrTy();

View File

@ -6456,7 +6456,9 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
}
// FIXME: We ignore attributes for now.
if (UDir)
ProcessDeclAttributeList(S, UDir, AttrList);
return UDir;
}
@ -7172,6 +7174,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
MultiTemplateParamsArg TemplateParamLists,
SourceLocation UsingLoc,
UnqualifiedId &Name,
AttributeList *AttrList,
TypeResult Type) {
// Skip up to the relevant declaration scope.
while (S->getFlags() & Scope::TemplateParamScope)
@ -7218,6 +7221,8 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (Invalid)
NewTD->setInvalidDecl();
ProcessDeclAttributeList(S, NewTD, AttrList);
CheckTypedefForVariablyModifiedType(S, NewTD);
Invalid |= NewTD->isInvalidDecl();
@ -10080,6 +10085,25 @@ Decl *Sema::ActOnFinishLinkageSpecification(Scope *S,
return LinkageSpec;
}
/// \brief Perform semantic checks on a C++11 attribute-declaration.
void Sema::ActOnAttributeDeclaration(AttributeList *AttrList) {
// FIXME: Build an AST node for an attribute declaration and return it.
// Since we do not support any attributes which can be used in an attribute
// declaration, just diagnose standard and unknown attributes appropriately.
for (/**/; AttrList; AttrList = AttrList->getNext()) {
if (AttrList->getKind() == AttributeList::IgnoredAttribute ||
AttrList->isInvalid())
continue;
Diag(AttrList->getLoc(),
AttrList->getKind() == AttributeList::UnknownAttribute
? diag::warn_unknown_attribute_ignored
: diag::err_attribute_declaration)
<< AttrList->getName();
}
}
/// \brief Perform semantic analysis for the variable declaration that
/// occurs within a C++ catch clause, returning the newly-created
/// variable.

View File

@ -3497,7 +3497,11 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
// Make sure there are no unused decl attributes on the declarator.
// We don't want to do this for ObjC parameters because we're going
// to apply them to the actual parameter declaration.
if (D.getContext() != Declarator::ObjCParameterContext)
// Likewise, we don't want to do this for alias declarations, because
// we are actually going to build a declaration from this eventually.
if (D.getContext() != Declarator::ObjCParameterContext &&
D.getContext() != Declarator::AliasDeclContext &&
D.getContext() != Declarator::AliasTemplateContext)
checkUnusedDeclAttributes(D);
if (getLangOpts().CPlusPlus) {

View File

@ -41,6 +41,8 @@ const [[]] int between_attr_2 = 0; // expected-error {{an attribute list cannot
int after_attr [[]];
int * [[]] ptr_attr;
int & [[]] ref_attr = after_attr;
int & [[unknown]] ref_attr_2 = after_attr; // expected-warning {{unknown attribute 'unknown' ignored}}
int & [[noreturn]] ref_attr_3 = after_attr; // expected-error {{'noreturn' attribute cannot be applied to types}}
int && [[]] rref_attr = 0;
int array_attr [1] [[]];
alignas(8) int aligned_attr;
@ -112,13 +114,18 @@ extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
[[]] asm(""); // expected-error {{an attribute list cannot appear here}}
[[]] using ns::i; // expected-error {{an attribute list cannot appear here}}
[[]] using namespace ns;
[[unknown]] using namespace ns; // expected-warning {{unknown attribute 'unknown' ignored}}
[[noreturn]] using namespace ns; // expected-error {{'noreturn' attribute only applies to functions and methods}}
[[]] using T = int; // expected-error {{an attribute list cannot appear here}}
using T [[]] = int; // ok
template<typename T> using U [[]] = T;
using ns::i [[]]; // expected-error {{an attribute list cannot appear here}}
using [[]] ns::i; // expected-error {{an attribute list cannot appear here}}
using T [[unknown]] = int; // expected-warning {{unknown attribute 'unknown' ignored}}
using T [[noreturn]] = int; // expected-error {{'noreturn' attribute only applies to functions and methods}}
using V = int; // expected-note {{previous}}
using V [[gnu::vector_size(16)]] = int; // expected-error {{redefinition with different types}}
auto trailing() -> [[]] const int; // expected-error {{an attribute list cannot appear here}}
auto trailing() -> const [[]] int; // expected-error {{an attribute list cannot appear here}}
@ -220,10 +227,10 @@ void bar () {
// Condition tests
void baz () {
if ([[]] bool b = true) {
switch ([[]] int n { 42 }) {
if ([[unknown]] bool b = true) { // expected-warning {{unknown attribute 'unknown' ignored}}
switch ([[unknown]] int n { 42 }) { // expected-warning {{unknown attribute 'unknown' ignored}}
default:
for ([[]] int n = 0; [[]] char b = n < 5; ++b) {
for ([[unknown]] int n = 0; [[unknown]] char b = n < 5; ++b) { // expected-warning 2{{unknown attribute 'unknown' ignored}}
}
}
}
@ -240,7 +247,7 @@ void baz () {
do {
} while ([[]] false); // expected-error {{an attribute list cannot appear here}}
for ([[]] int n : { 1, 2, 3 }) {
for ([[unknown]] int n : { 1, 2, 3 }) { // expected-warning {{unknown attribute 'unknown' ignored}}
}
}
@ -251,7 +258,7 @@ enum class [[]] EvenMoreSecrets {};
namespace arguments {
void f[[gnu::format(printf, 1, 2)]](const char*, ...);
void g() [[unknown::foo(currently arguments of attributes from unknown namespace other than 'gnu' namespace are ignored... blah...)]]; // expected-warning {{unknown attribute 'foo' ignored}}
void g() [[unknown::foo(arguments of attributes from unknown namespace other than 'gnu' namespace are ignored... blah...)]]; // expected-warning {{unknown attribute 'foo' ignored}}
}
// Forbid attributes on decl specifiers.
@ -265,3 +272,6 @@ int [[carries_dependency]] foo(int [[carries_dependency]] x); // expected-error
int *[[gnu::unused]] v3; // expected-warning {{attribute 'unused' ignored}}
int v4[2][[gnu::unused]]; // expected-warning {{attribute 'unused' ignored}}
int v5()[[gnu::unused]]; // expected-warning {{attribute 'unused' ignored}}
[[attribute_declaration]]; // expected-warning {{unknown attribute 'attribute_declaration' ignored}}
[[noreturn]]; // expected-error {{'noreturn' attribute cannot be used in an attribute declaration}}