Properly diagnose standard C++ attributes which have optional argument lists when the arguments are elided. eg)

[[deprecated()]] // error
[[deprecated]] // OK
[[deprecated("")]] // OK
[[gnu::deprecated()]] // OK

llvm-svn: 206186
This commit is contained in:
Aaron Ballman 2014-04-14 16:03:22 +00:00
parent 1d3ae27f01
commit 35f9421c55
6 changed files with 51 additions and 21 deletions

View File

@ -526,7 +526,9 @@ def warn_cxx98_compat_attribute : Warning<
"C++11 attribute syntax is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_cxx11_attribute_forbids_arguments : Error<
"attribute '%0' cannot have an argument list">;
"attribute %0 cannot have an argument list">;
def err_attribute_requires_arguements : Error<
"attribute %0 requires a nonempty argument list">;
def err_cxx11_attribute_forbids_ellipsis : Error<
"attribute '%0' cannot be used as an attribute pack">;
def err_cxx11_attribute_repeated : Error<

View File

@ -2012,13 +2012,13 @@ private:
/// \brief Parses syntax-generic attribute arguments for attributes which are
/// known to the implementation, and adds them to the given ParsedAttributes
/// list with the given attribute syntax.
void ParseAttributeArgsCommon(IdentifierInfo *AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs, SourceLocation *EndLoc,
IdentifierInfo *ScopeName,
SourceLocation ScopeLoc,
AttributeList::Syntax Syntax);
/// list with the given attribute syntax. Returns the number of arguments
/// parsed for the attribute.
unsigned
ParseAttributeArgsCommon(IdentifierInfo *AttrName, SourceLocation AttrNameLoc,
ParsedAttributes &Attrs, SourceLocation *EndLoc,
IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
AttributeList::Syntax Syntax);
void MaybeParseGNUAttributes(Declarator &D,
LateParsedAttrList *LateAttrs = 0) {

View File

@ -261,7 +261,7 @@ void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
0, AttrNameLoc, 0, 0, AttributeList::AS_GNU);
}
void Parser::ParseAttributeArgsCommon(
unsigned Parser::ParseAttributeArgsCommon(
IdentifierInfo *AttrName, SourceLocation AttrNameLoc,
ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName,
SourceLocation ScopeLoc, AttributeList::Syntax Syntax) {
@ -302,7 +302,7 @@ void Parser::ParseAttributeArgsCommon(
ExprResult ArgExpr(ParseAssignmentExpression());
if (ArgExpr.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
return;
return 0;
}
ArgExprs.push_back(ArgExpr.release());
// Eat the comma, move to the next argument
@ -318,6 +318,8 @@ void Parser::ParseAttributeArgsCommon(
if (EndLoc)
*EndLoc = RParen;
return static_cast<unsigned>(ArgExprs.size());
}
/// Parse the arguments to a parameterized GNU attribute or

View File

@ -3194,6 +3194,7 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
switch (AttributeList::getKind(AttrName, ScopeName,
AttributeList::AS_CXX11)) {
case AttributeList::AT_CarriesDependency:
case AttributeList::AT_Deprecated:
case AttributeList::AT_FallThrough:
case AttributeList::AT_CXX11NoReturn: {
return true;
@ -3225,6 +3226,7 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
IdentifierInfo *ScopeName,
SourceLocation ScopeLoc) {
assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list");
SourceLocation LParenLoc = Tok.getLocation();
// If the attribute isn't known, we will not attempt to parse any
// arguments.
@ -3241,9 +3243,32 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
// behaviors.
ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
ScopeLoc, AttributeList::AS_CXX11, 0);
else
ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
ScopeLoc, AttributeList::AS_CXX11);
else {
unsigned NumArgs =
ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc,
ScopeName, ScopeLoc, AttributeList::AS_CXX11);
const AttributeList *Attr = Attrs.getList();
if (Attr && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) {
// If the attribute is a standard or built-in attribute and we are
// parsing an argument list, we need to determine whether this attribute
// was allowed to have an argument list (such as [[deprecated]]), and how
// many arguments were parsed (so we can diagnose on [[deprecated()]]).
if (Attr->getMaxArgs() && !NumArgs) {
// The attribute was allowed to have arguments, but none were provided
// even though the attribute parsed successfully. This is an error.
Diag(LParenLoc, diag::err_attribute_requires_arguements) << AttrName;
return false;
} else if (!Attr->getMaxArgs()) {
// The attribute parsed successfully, but was not allowed to have any
// arguments. It doesn't matter whether any were provided -- the
// presence of the argument list (even if empty) is diagnosed.
Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments)
<< AttrName;
return false;
}
}
}
return true;
}
@ -3324,14 +3349,9 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
<< AttrName << SourceRange(SeenAttrs[AttrName]);
// Parse attribute arguments
if (Tok.is(tok::l_paren)) {
if (StandardAttr)
Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments)
<< AttrName->getName();
if (Tok.is(tok::l_paren))
AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, attrs, endLoc,
ScopeName, ScopeLoc);
}
if (!AttrParsed)
attrs.addNew(AttrName,

View File

@ -94,5 +94,4 @@ void testFundef5() __attribute__(()) { }
__attribute__((pure)) int testFundef6(int a) { return a; }
void deprecatedTestFun(void) __attribute__((deprecated()));

View File

@ -322,3 +322,10 @@ namespace GccASan {
[[gnu::no_address_safety_analysis]] void f3();
[[gnu::no_sanitize_address]] void f4();
}
namespace {
[[deprecated]] void bar();
[[deprecated("hello")]] void baz();
[[deprecated()]] void foo(); // expected-error {{attribute 'deprecated' requires a nonempty argument list}}
[[gnu::deprecated()]] void quux();
}