[C] Fix parsing of [[clang::assume]] (#141747)
The assumption attribute is exposed with a Clang spelling, which means we support __attribute__((assume)) as well as [[clang::assume]] as spellings for the attribute. In C++, the [[clang::assume]] spelling worked as expected. In C, that spelling would emit an "unknown attribute ignored" diagnostic. This was happening because we were failing to pass in the scope name and source location when creating the attribute. In C++, this worked by chance because [[assume]] is a known attribute in C++. But in C, where there is thankfully no [[assume]] standard attribute, the lack of a scope meant we would set the attribute kind to "unknown".
This commit is contained in:
@@ -226,6 +226,9 @@ C Language Changes
|
||||
- Added the existing ``-Wduplicate-decl-specifier`` diagnostic, which is on by
|
||||
default, to ``-Wc++-compat`` because duplicated declaration specifiers are
|
||||
not valid in C++.
|
||||
- The ``[[clang::assume()]]`` attribute is now correctly recognized in C. The
|
||||
``__attribute__((assume()))`` form has always been supported, so the fix is
|
||||
specific to the attribute syntax used.
|
||||
|
||||
C2y Feature Support
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -3037,11 +3037,11 @@ private:
|
||||
|
||||
/// Parse the argument to C++23's [[assume()]] attribute. Returns true on
|
||||
/// error.
|
||||
bool ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs,
|
||||
IdentifierInfo *AttrName,
|
||||
SourceLocation AttrNameLoc,
|
||||
SourceLocation *EndLoc,
|
||||
ParsedAttr::Form Form);
|
||||
bool
|
||||
ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs, IdentifierInfo *AttrName,
|
||||
SourceLocation AttrNameLoc,
|
||||
IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
|
||||
SourceLocation *EndLoc, ParsedAttr::Form Form);
|
||||
|
||||
/// Try to parse an 'identifier' which appears within an attribute-token.
|
||||
///
|
||||
|
||||
@@ -676,7 +676,8 @@ void Parser::ParseGNUAttributeArgs(
|
||||
Form);
|
||||
return;
|
||||
} else if (AttrKind == ParsedAttr::AT_CXXAssume) {
|
||||
ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form);
|
||||
ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, ScopeName,
|
||||
ScopeLoc, EndLoc, Form);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -734,7 +735,8 @@ unsigned Parser::ParseClangAttributeArgs(
|
||||
break;
|
||||
|
||||
case ParsedAttr::AT_CXXAssume:
|
||||
ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form);
|
||||
ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, ScopeName,
|
||||
ScopeLoc, EndLoc, Form);
|
||||
break;
|
||||
}
|
||||
return !Attrs.empty() ? Attrs.begin()->getNumArgs() : 0;
|
||||
|
||||
@@ -4452,11 +4452,10 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
|
||||
}
|
||||
}
|
||||
|
||||
bool Parser::ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs,
|
||||
IdentifierInfo *AttrName,
|
||||
SourceLocation AttrNameLoc,
|
||||
SourceLocation *EndLoc,
|
||||
ParsedAttr::Form Form) {
|
||||
bool Parser::ParseCXXAssumeAttributeArg(
|
||||
ParsedAttributes &Attrs, IdentifierInfo *AttrName,
|
||||
SourceLocation AttrNameLoc, IdentifierInfo *ScopeName,
|
||||
SourceLocation ScopeLoc, SourceLocation *EndLoc, ParsedAttr::Form Form) {
|
||||
assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list");
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
T.consumeOpen();
|
||||
@@ -4498,8 +4497,8 @@ bool Parser::ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs,
|
||||
ArgsUnion Assumption = Res.get();
|
||||
auto RParen = Tok.getLocation();
|
||||
T.consumeClose();
|
||||
Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), nullptr,
|
||||
SourceLocation(), &Assumption, 1, Form);
|
||||
Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), ScopeName, ScopeLoc,
|
||||
&Assumption, 1, Form);
|
||||
|
||||
if (EndLoc)
|
||||
*EndLoc = RParen;
|
||||
@@ -4565,7 +4564,8 @@ bool Parser::ParseCXX11AttributeArgs(
|
||||
ScopeName, ScopeLoc, Form);
|
||||
// So does C++23's assume() attribute.
|
||||
else if (!ScopeName && AttrName->isStr("assume")) {
|
||||
if (ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form))
|
||||
if (ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, nullptr,
|
||||
SourceLocation{}, EndLoc, Form))
|
||||
return true;
|
||||
NumArgs = 1;
|
||||
} else
|
||||
|
||||
25
clang/test/Sema/assume.c
Normal file
25
clang/test/Sema/assume.c
Normal file
@@ -0,0 +1,25 @@
|
||||
// RUN: %clang_cc1 -std=c23 %s -verify
|
||||
|
||||
// Validate that the attribute works in C.
|
||||
static_assert(!__has_c_attribute(assume));
|
||||
static_assert(__has_c_attribute(clang::assume));
|
||||
static_assert(__has_attribute(assume));
|
||||
|
||||
void test(int n) {
|
||||
// Smoke test.
|
||||
__attribute__((assume(true)));
|
||||
[[clang::assume(true)]];
|
||||
|
||||
// Test diagnostics
|
||||
__attribute__((assume)); // expected-error {{'assume' attribute takes one argument}}
|
||||
__attribute__((assume())); // expected-error {{expected expression}}
|
||||
[[clang::assume]]; // expected-error {{'assume' attribute takes one argument}}
|
||||
[[clang::assume()]]; // expected-error {{expected expression}}
|
||||
|
||||
__attribute__((assume(n++))); // expected-warning {{assumption is ignored because it contains (potential) side-effects}}
|
||||
[[clang::assume(n++)]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}}
|
||||
|
||||
[[clang::assume(true)]] int x; // expected-error {{'assume' attribute cannot be applied to a declaration}}
|
||||
__attribute__((assume(true))) int y; // expected-error {{'assume' attribute cannot be applied to a declaration}}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user