Skip to content

Commit bc7cc20

Browse files
committed
Fix an accepts-invalid issue with [[]] attributes in the type position in C
A user reported an issue to me via email that Clang was accepting some code that GCC was rejecting. After investigation, it turned out to be a general problem of us failing to properly reject attributes written in the type position in C when they don't apply to types. The root cause was a terminology issue -- we sometimes use "CXX11Attr" to mean [[]] in C++11 mode and sometimes [[]] in general -- and this came back to bite us because in this particular case, it really meant [[]] in C++ mode. I fixed the issue by introducing a new function AttributeCommonInfo::isStandardAttributeSyntax() to represent [[]] in either C or C++ mode. This fix pointed out that we've had the issue in some of our existing tests, which have all been corrected. This resolves https://bugs.llvm.org/show_bug.cgi?id=50954.
1 parent bef9464 commit bc7cc20

11 files changed

+49
-39
lines changed

clang/include/clang/Basic/AttributeCommonInfo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ class AttributeCommonInfo {
155155

156156
bool isC2xAttribute() const { return SyntaxUsed == AS_C2x; }
157157

158+
/// The attribute is spelled [[]] in either C or C++ mode, including standard
159+
/// attributes spelled with a keyword, like alignas.
160+
bool isStandardAttributeSyntax() const {
161+
return isCXX11Attribute() || isC2xAttribute();
162+
}
163+
158164
bool isKeywordAttribute() const {
159165
return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
160166
}

clang/lib/Parse/Parser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1214,7 +1214,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
12141214
// a definition. Late parsed attributes are checked at the end.
12151215
if (Tok.isNot(tok::equal)) {
12161216
for (const ParsedAttr &AL : D.getAttributes())
1217-
if (AL.isKnownToGCC() && !AL.isCXX11Attribute())
1217+
if (AL.isKnownToGCC() && !AL.isStandardAttributeSyntax())
12181218
Diag(AL.getLoc(), diag::warn_attribute_on_function_definition) << AL;
12191219
}
12201220

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,7 +2093,7 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
20932093
ValueDecl *VD = dyn_cast<ValueDecl>(D);
20942094
if (!VD || (!VD->getType()->isBlockPointerType() &&
20952095
!VD->getType()->isFunctionPointerType())) {
2096-
S.Diag(AL.getLoc(), AL.isCXX11Attribute()
2096+
S.Diag(AL.getLoc(), AL.isStandardAttributeSyntax()
20972097
? diag::err_attribute_wrong_decl_type
20982098
: diag::warn_attribute_wrong_decl_type)
20992099
<< AL << ExpectedFunctionMethodOrBlock;
@@ -2863,7 +2863,7 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
28632863
}
28642864

28652865
StringRef Str;
2866-
if ((AL.isCXX11Attribute() || AL.isC2xAttribute()) && !AL.getScopeName()) {
2866+
if (AL.isStandardAttributeSyntax() && !AL.getScopeName()) {
28672867
// The standard attribute cannot be applied to variable declarations such
28682868
// as a function pointer.
28692869
if (isa<VarDecl>(D))
@@ -7280,8 +7280,8 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
72807280
!S.checkStringLiteralArgumentAttr(AL, 0, Str))
72817281
return;
72827282

7283-
// Only support a single optional message for Declspec and CXX11.
7284-
if (AL.isDeclspecAttribute() || AL.isCXX11Attribute())
7283+
// Support a single optional message only for Declspec and [[]] spellings.
7284+
if (AL.isDeclspecAttribute() || AL.isStandardAttributeSyntax())
72857285
AL.checkAtMostNumArgs(S, 1);
72867286
else if (AL.isArgExpr(1) && AL.getArgAsExpr(1) &&
72877287
!S.checkStringLiteralArgumentAttr(AL, 1, Replacement))
@@ -7348,7 +7348,7 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D,
73487348
// getSpelling() or prettyPrint() on the resulting semantic attribute object
73497349
// without failing assertions.
73507350
unsigned TranslatedSpellingIndex = 0;
7351-
if (AL.isC2xAttribute() || AL.isCXX11Attribute())
7351+
if (AL.isStandardAttributeSyntax())
73527352
TranslatedSpellingIndex = 1;
73537353

73547354
AttributeCommonInfo Info = AL;

clang/lib/Sema/SemaType.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state,
634634
// C++11 attributes before the decl specifiers actually appertain to
635635
// the declarators. Move them straight there. We don't support the
636636
// 'put them wherever you like' semantics we allow for GNU attributes.
637-
if (attr.isCXX11Attribute()) {
637+
if (attr.isStandardAttributeSyntax()) {
638638
moveAttrFromListToList(attr, state.getCurrentAttributes(),
639639
state.getDeclarator().getAttributes());
640640
return;
@@ -687,9 +687,9 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
687687
// non-owning copy and iterate over that.
688688
ParsedAttributesView AttrsCopy{state.getDeclarator().getAttributes()};
689689
for (ParsedAttr &attr : AttrsCopy) {
690-
// Do not distribute C++11 attributes. They have strict rules for what
690+
// Do not distribute [[]] attributes. They have strict rules for what
691691
// they appertain to.
692-
if (attr.isCXX11Attribute())
692+
if (attr.isStandardAttributeSyntax())
693693
continue;
694694

695695
switch (attr.getKind()) {
@@ -8058,7 +8058,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
80588058
if (attr.isInvalid())
80598059
continue;
80608060

8061-
if (attr.isCXX11Attribute()) {
8061+
if (attr.isStandardAttributeSyntax()) {
80628062
// [[gnu::...]] attributes are treated as declaration attributes, so may
80638063
// not appertain to a DeclaratorChunk. If we handle them as type
80648064
// attributes, accept them in that position and diagnose the GCC
@@ -8087,16 +8087,16 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
80878087
// otherwise, add it to the FnAttrs list for rechaining.
80888088
switch (attr.getKind()) {
80898089
default:
8090-
// A C++11 attribute on a declarator chunk must appertain to a type.
8091-
if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk) {
8090+
// A [[]] attribute on a declarator chunk must appertain to a type.
8091+
if (attr.isStandardAttributeSyntax() && TAL == TAL_DeclChunk) {
80928092
state.getSema().Diag(attr.getLoc(), diag::err_attribute_not_type_attr)
80938093
<< attr;
80948094
attr.setUsedAsTypeAttr();
80958095
}
80968096
break;
80978097

80988098
case ParsedAttr::UnknownAttribute:
8099-
if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk)
8099+
if (attr.isStandardAttributeSyntax() && TAL == TAL_DeclChunk)
81008100
state.getSema().Diag(attr.getLoc(),
81018101
diag::warn_unknown_attribute_ignored)
81028102
<< attr << attr.getRange();

clang/test/AST/ast-dump-c-attr.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,3 @@ struct [[deprecated]] Test8;
5252
void Test11 [[deprecated]](void);
5353
// CHECK: FunctionDecl{{.*}}Test11
5454
// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:15> "" ""
55-
56-
void Test12(void) [[deprecated]] {}
57-
// CHECK: FunctionDecl{{.*}}Test12
58-
// CHECK-NEXT: CompoundStmt
59-
// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:21> "" ""

clang/test/Sema/attr-availability-square-brackets.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
22

3-
void f0() [[clang::availability(macosx,introduced=10.4,deprecated=10.2)]]; // expected-warning{{feature cannot be deprecated in macOS version 10.2 before it was introduced in version 10.4; attribute ignored}}
4-
void f1() [[clang::availability(ios,obsoleted=2.1,deprecated=3.0)]]; // expected-warning{{feature cannot be obsoleted in iOS version 2.1 before it was deprecated in version 3.0; attribute ignored}}
5-
void f2() [[clang::availability(ios,introduced=2.1,deprecated=2.1)]];
3+
[[clang::availability(macosx,introduced=10.4,deprecated=10.2)]] void f0(); // expected-warning{{feature cannot be deprecated in macOS version 10.2 before it was introduced in version 10.4; attribute ignored}}
4+
[[clang::availability(ios,obsoleted=2.1,deprecated=3.0)]] void f1(); // expected-warning{{feature cannot be obsoleted in iOS version 2.1 before it was deprecated in version 3.0; attribute ignored}}
5+
[[clang::availability(ios,introduced=2.1,deprecated=2.1)]] void f2();
66

7+
[[clang::availability(macosx,introduced=8.0,deprecated=9.0, message="use CTFontCopyFullName")]]
78
extern void
8-
ATSFontGetName(const char *oName) [[clang::availability(macosx,introduced=8.0,deprecated=9.0, message="use CTFontCopyFullName")]]; // expected-note {{'ATSFontGetName' has been explicitly marked deprecated here}}
9+
ATSFontGetName(const char *oName); // expected-note {{'ATSFontGetName' has been explicitly marked deprecated here}}
910

1011
void test_10095131() {
1112
ATSFontGetName("Hello"); // expected-warning {{'ATSFontGetName' is deprecated: first deprecated in macOS 9.0 - use CTFontCopyFullName}}

clang/test/Sema/attr-c2x.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ enum [[clang::flag_enum]] EnumFlag {
1111
D0 = 1, D1 = 8
1212
};
1313

14-
void foo(void *c) [[clang::overloadable]];
15-
void foo(char *c) [[clang::overloadable]];
14+
[[clang::overloadable]] void foo(void *c);
15+
[[clang::overloadable]] void foo(char *c);
1616

1717
void context_okay(void *context [[clang::swift_context]]) [[clang::swiftcall]];
1818
void context_okay2(void *context [[clang::swift_context]], void *selfType, char **selfWitnessTable) [[clang::swiftcall]];
1919

20-
void *f1(void) [[clang::ownership_returns(foo)]];
21-
void *f2() [[clang::ownership_returns(foo)]]; // expected-warning {{'ownership_returns' attribute only applies to non-K&R-style functions}}
20+
[[clang::ownership_returns(foo)]] void *f1(void);
21+
[[clang::ownership_returns(foo)]] void *f2(); // expected-warning {{'ownership_returns' attribute only applies to non-K&R-style functions}}
2222

23-
void foo2(void) [[clang::unavailable("not available - replaced")]]; // expected-note {{'foo2' has been explicitly marked unavailable here}}
23+
[[clang::unavailable("not available - replaced")]] void foo2(void); // expected-note {{'foo2' has been explicitly marked unavailable here}}
2424
void bar(void) {
2525
foo2(); // expected-error {{'foo2' is unavailable: not available - replaced}}
2626
}

clang/test/Sema/attr-deprecated-c2x.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
// RUN: %clang_cc1 %s -verify -fsyntax-only --std=c2x
1+
// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c2x
22

3-
int f() [[deprecated]]; // expected-note 2 {{'f' has been explicitly marked deprecated here}}
4-
void g() [[deprecated]];// expected-note {{'g' has been explicitly marked deprecated here}}
3+
[[deprecated]] int f(); // expected-note 2 {{'f' has been explicitly marked deprecated here}}
4+
[[deprecated]] void g();// expected-note {{'g' has been explicitly marked deprecated here}}
55
void g();
66

77
extern int var [[deprecated]]; // expected-note 2 {{'var' has been explicitly marked deprecated here}}
@@ -22,7 +22,7 @@ int w() {
2222
return var; // expected-warning {{'var' is deprecated}}
2323
}
2424

25-
int old_fn() [[deprecated]];// expected-note {{'old_fn' has been explicitly marked deprecated here}}
25+
[[deprecated]] int old_fn();// expected-note {{'old_fn' has been explicitly marked deprecated here}}
2626
int old_fn();
2727
int (*fn_ptr)() = old_fn; // expected-warning {{'old_fn' is deprecated}}
2828

@@ -52,3 +52,7 @@ struct bar_dep *test3; // expected-warning {{'bar_dep' is deprecated}}
5252
void test4(void) {
5353
i = 12; // expected-warning {{'i' is deprecated: this is the message}}
5454
}
55+
56+
// Ensure that deprecated only accepts one argument, not the replacement
57+
// argument supported as a GNU extension.
58+
[[deprecated("message", "replacement not supported")]] void test5(void); // expected-error {{'deprecated' attribute takes no more than 1 argument}}

clang/test/Sema/attr-external-source-symbol.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ void namedDeclsOnly() {
1818
};
1919
}
2020

21-
void threeClauses2() [[clang::external_source_symbol(language="Swift", defined_in="module", generated_declaration)]];
21+
[[clang::external_source_symbol(language="Swift", defined_in="module", generated_declaration)]] void threeClauses2();
2222

23-
void twoClauses2() [[clang::external_source_symbol(language="Swift", defined_in="module")]];
23+
[[clang::external_source_symbol(language="Swift", defined_in="module")]] void twoClauses2();
2424

25-
void fourClauses2()
26-
[[clang::external_source_symbol(language="Swift", defined_in="module", generated_declaration, generated_declaration)]]; // expected-error {{duplicate 'generated_declaration' clause in an 'external_source_symbol' attribute}}
25+
[[clang::external_source_symbol(language="Swift", defined_in="module", generated_declaration, generated_declaration)]] // expected-error {{duplicate 'generated_declaration' clause in an 'external_source_symbol' attribute}}
26+
void fourClauses2();
2727

28-
void oneClause2() [[clang::external_source_symbol(generated_declaration)]];
28+
[[clang::external_source_symbol(generated_declaration)]] void oneClause2();
2929

30-
void noArguments2()
31-
[[clang::external_source_symbol]]; // expected-error {{'external_source_symbol' attribute takes at least 1 argument}}
30+
[[clang::external_source_symbol]] // expected-error {{'external_source_symbol' attribute takes at least 1 argument}}
31+
void noArguments2();

clang/test/Sema/c2x-maybe_unused-errors.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ struct [[maybe_unused("Wrong")]] S3 { // expected-error {{'maybe_unused' cannot
1010
int a;
1111
};
1212

13+
void func(void) {
14+
int a[10] [[maybe_unused]]; // expected-error {{'maybe_unused' attribute cannot be applied to types}}
15+
}

clang/test/Sema/overloadable.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
// RUN: %clang_cc1 -fsyntax-only -verify %s -Wincompatible-pointer-types
1+
// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify %s -Wincompatible-pointer-types
22

33
int var __attribute__((overloadable)); // expected-error{{'overloadable' attribute only applies to functions}}
4+
void bad_attr_target(int) [[clang::overloadable]]; // expected-error{{'overloadable' attribute cannot be applied to types}}
45
void params(void) __attribute__((overloadable(12))); // expected-error {{'overloadable' attribute takes no arguments}}
56

67
int *f(int) __attribute__((overloadable)); // expected-note{{previous overload of function is here}}

0 commit comments

Comments
 (0)