[clang] [Clang] disallow attributes on void parameters (PR #124920)
Oleksandr T. via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 30 13:54:42 PST 2025
https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/124920
>From bd731e4be65fc9c1746aa6a8f63d206eb54bb2be Mon Sep 17 00:00:00 2001
From: Oleksandr T <oleksandr.tarasiuk at outlook.com>
Date: Wed, 29 Jan 2025 15:17:06 +0200
Subject: [PATCH 1/4] [Clang] disallow attributes on void parameters
---
clang/docs/ReleaseNotes.rst | 2 ++
clang/lib/Parse/ParseDecl.cpp | 7 +++++++
clang/test/Parser/cxx0x-attributes.cpp | 9 +++++++++
3 files changed, 18 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7fafe2807bd388..0c87e52007d546 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -100,6 +100,8 @@ Removed Compiler Flags
Attribute Changes in Clang
--------------------------
+- Clang now disallows the use of attributes on void parameters. (#GH108819)
+
Improvements to Clang's diagnostics
-----------------------------------
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index f136d5007e8a5f..0b88dd4449b1e2 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7986,6 +7986,13 @@ void Parser::ParseParameterDeclarationClause(
if (getLangOpts().HLSL)
MaybeParseHLSLAnnotations(DS.getAttributes());
+ if (ParmDeclarator.getIdentifier() == nullptr &&
+ ParmDeclarator.getDeclarationAttributes().size() &&
+ ParmDeclarator.getDeclSpec().getTypeSpecType() == DeclSpec::TST_void) {
+ SourceRange AttrRange = ParmDeclarator.getDeclarationAttributes().Range;
+ Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed) << AttrRange;
+ }
+
if (Tok.is(tok::kw_requires)) {
// User tried to define a requires clause in a parameter declaration,
// which is surely not a function declaration.
diff --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp
index fad3010c98b9c2..13fcdd142fa841 100644
--- a/clang/test/Parser/cxx0x-attributes.cpp
+++ b/clang/test/Parser/cxx0x-attributes.cpp
@@ -453,3 +453,12 @@ namespace P2361 {
}
alignas(int) struct AlignAsAttribute {}; // expected-error {{misplaced attributes; expected attributes here}}
+
+namespace GH108819 {
+void a([[maybe_unused]] void) {} // expected-error {{an attribute list cannot appear here}} \
+ // expected-warning {{use of the 'maybe_unused' attribute is a C++17 extension}}
+void b([[deprecated]] void) {} // expected-error {{an attribute list cannot appear here}} \
+ // expected-warning {{use of the 'deprecated' attribute is a C++14 extension}}
+void c([[clang::lifetimebound]] void) {} // expected-error {{an attribute list cannot appear here}}
+void d([[clang::annotate("a", "b", 1)]] void) {} // expected-error {{an attribute list cannot appear here}}
+}
>From 063f76730ebfd289f5340d0d8477a43a5ea965c2 Mon Sep 17 00:00:00 2001
From: Oleksandr T <oleksandr.tarasiuk at outlook.com>
Date: Wed, 29 Jan 2025 15:54:48 +0200
Subject: [PATCH 2/4] remove unnecessary name check
---
clang/lib/Parse/ParseDecl.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 0b88dd4449b1e2..934c16c9591520 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7986,8 +7986,7 @@ void Parser::ParseParameterDeclarationClause(
if (getLangOpts().HLSL)
MaybeParseHLSLAnnotations(DS.getAttributes());
- if (ParmDeclarator.getIdentifier() == nullptr &&
- ParmDeclarator.getDeclarationAttributes().size() &&
+ if (ParmDeclarator.getDeclarationAttributes().size() &&
ParmDeclarator.getDeclSpec().getTypeSpecType() == DeclSpec::TST_void) {
SourceRange AttrRange = ParmDeclarator.getDeclarationAttributes().Range;
Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed) << AttrRange;
>From 3f3431513ad59111794953d27e64608b3ce2e6e1 Mon Sep 17 00:00:00 2001
From: Oleksandr T <oleksandr.tarasiuk at outlook.com>
Date: Wed, 29 Jan 2025 16:07:18 +0200
Subject: [PATCH 3/4] use empty instead of size
---
clang/lib/Parse/ParseDecl.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 934c16c9591520..963b59565953d4 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7986,7 +7986,7 @@ void Parser::ParseParameterDeclarationClause(
if (getLangOpts().HLSL)
MaybeParseHLSLAnnotations(DS.getAttributes());
- if (ParmDeclarator.getDeclarationAttributes().size() &&
+ if (!ParmDeclarator.getDeclarationAttributes().empty() &&
ParmDeclarator.getDeclSpec().getTypeSpecType() == DeclSpec::TST_void) {
SourceRange AttrRange = ParmDeclarator.getDeclarationAttributes().Range;
Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed) << AttrRange;
>From 9919006df9ec32023b2bf179b72f9ebaf977bd08 Mon Sep 17 00:00:00 2001
From: Oleksandr T <oleksandr.tarasiuk at outlook.com>
Date: Thu, 30 Jan 2025 22:35:16 +0200
Subject: [PATCH 4/4] move handling of void parameter attributes to sema decl
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 ++
clang/lib/Parse/ParseDecl.cpp | 6 ------
clang/lib/Sema/SemaDecl.cpp | 9 +++++++++
.../test/Misc/pragma-attribute-strict-subjects.c | 16 ++++++++--------
clang/test/Parser/cxx0x-attributes.cpp | 9 ---------
clang/test/SemaCXX/attr-cxx0x.cpp | 11 +++++++++++
6 files changed, 30 insertions(+), 23 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index db911ed121e951..59bc932e9f2203 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3830,6 +3830,8 @@ def warn_type_attribute_wrong_type : Warning<
"'%0' only applies to %select{function|pointer|"
"Objective-C object or block pointer}1 types; type here is %2">,
InGroup<IgnoredAttributes>;
+def warn_attribute_on_void_param: Warning<
+ "attribute %0 cannot be applied to a 'void' parameter">, InGroup<IgnoredAttributes>;
def err_type_attribute_wrong_type : Error<
warn_type_attribute_wrong_type.Summary>;
def warn_incomplete_encoded_type : Warning<
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 963b59565953d4..f136d5007e8a5f 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7986,12 +7986,6 @@ void Parser::ParseParameterDeclarationClause(
if (getLangOpts().HLSL)
MaybeParseHLSLAnnotations(DS.getAttributes());
- if (!ParmDeclarator.getDeclarationAttributes().empty() &&
- ParmDeclarator.getDeclSpec().getTypeSpecType() == DeclSpec::TST_void) {
- SourceRange AttrRange = ParmDeclarator.getDeclarationAttributes().Range;
- Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed) << AttrRange;
- }
-
if (Tok.is(tok::kw_requires)) {
// User tried to define a requires clause in a parameter declaration,
// which is surely not a function declaration.
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 3cad9827fdab69..ac5aab92b03ae2 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10326,6 +10326,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ if (FTIHasSingleVoidParameter(FTI)) {
+ ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[0].Param);
+ if (Param->hasAttrs()) {
+ for (const auto *A : Param->attrs())
+ Diag(A->getLoc(), diag::warn_attribute_on_void_param)
+ << A << A->getRange();
+ }
+ }
+
if (!getLangOpts().CPlusPlus) {
// In C, find all the tag declarations from the prototype and move them
// into the function DeclContext. Remove them from the surrounding tag
diff --git a/clang/test/Misc/pragma-attribute-strict-subjects.c b/clang/test/Misc/pragma-attribute-strict-subjects.c
index 807977fb252aa6..3f8b553fb5011f 100644
--- a/clang/test/Misc/pragma-attribute-strict-subjects.c
+++ b/clang/test/Misc/pragma-attribute-strict-subjects.c
@@ -50,8 +50,8 @@ struct testRecoverStrictnessStruct { };
#pragma clang attribute pop
-#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, record(unless(is_union)), variable, enum))
-// expected-error at -1 {{attribute 'abi_tag' cannot be applied to 'enum'}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, record(unless(is_union)), variable, enum)) // expected-warning {{attribute 'abi_tag' cannot be applied to a 'void' parameter}}
+ // expected-error at -1 {{attribute 'abi_tag' cannot be applied to 'enum'}}
int testRecoverExtraVar = 0;
// CHECK-LABEL: VarDecl{{.*}} testRecoverExtraVar
@@ -90,7 +90,7 @@ struct testSubset1Struct { };
#pragma clang attribute pop
-#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = variable)
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = variable) // expected-warning {{attribute 'abi_tag' cannot be applied to a 'void' parameter}}
int testSubset2Var;
// CHECK-LABEL: VarDecl{{.*}} testSubset2Var
@@ -122,7 +122,7 @@ struct testSubset3Struct { };
#pragma clang attribute pop
-#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, variable))
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, variable)) // expected-warning {{attribute 'abi_tag' cannot be applied to a 'void' parameter}}
int testSubset4Var;
// CHECK-LABEL: VarDecl{{.*}} testSubset4Var
@@ -138,7 +138,7 @@ struct testSubset4Struct { };
#pragma clang attribute pop
-#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(variable, record(unless(is_union))))
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(variable, record(unless(is_union)))) // expected-warning {{attribute 'abi_tag' cannot be applied to a 'void' parameter}}
int testSubset5Var;
// CHECK-LABEL: VarDecl{{.*}} testSubset5Var
@@ -170,7 +170,7 @@ struct testSubset6Struct { };
#pragma clang attribute pop
-#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable))
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable)) // expected-warning {{attribute 'abi_tag' cannot be applied to a 'void' parameter}}
int testSubset7Var;
// CHECK-LABEL: VarDecl{{.*}} testSubset7Var
@@ -187,8 +187,8 @@ struct testSubset7Struct { };
#pragma clang attribute pop
-#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable, enum, enum_constant))
-// expected-error at -1 {{attribute 'abi_tag' cannot be applied to 'enum_constant', and 'enum'}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable, enum, enum_constant)) // expected-warning {{attribute 'abi_tag' cannot be applied to a 'void' parameter}}
+ // expected-error at -1 {{attribute 'abi_tag' cannot be applied to 'enum_constant', and 'enum'}}
int testSubsetRecoverVar;
// CHECK-LABEL: VarDecl{{.*}} testSubsetRecoverVar
diff --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp
index 13fcdd142fa841..fad3010c98b9c2 100644
--- a/clang/test/Parser/cxx0x-attributes.cpp
+++ b/clang/test/Parser/cxx0x-attributes.cpp
@@ -453,12 +453,3 @@ namespace P2361 {
}
alignas(int) struct AlignAsAttribute {}; // expected-error {{misplaced attributes; expected attributes here}}
-
-namespace GH108819 {
-void a([[maybe_unused]] void) {} // expected-error {{an attribute list cannot appear here}} \
- // expected-warning {{use of the 'maybe_unused' attribute is a C++17 extension}}
-void b([[deprecated]] void) {} // expected-error {{an attribute list cannot appear here}} \
- // expected-warning {{use of the 'deprecated' attribute is a C++14 extension}}
-void c([[clang::lifetimebound]] void) {} // expected-error {{an attribute list cannot appear here}}
-void d([[clang::annotate("a", "b", 1)]] void) {} // expected-error {{an attribute list cannot appear here}}
-}
diff --git a/clang/test/SemaCXX/attr-cxx0x.cpp b/clang/test/SemaCXX/attr-cxx0x.cpp
index 4d64d2b0cd8c63..5c2e9f7553389e 100644
--- a/clang/test/SemaCXX/attr-cxx0x.cpp
+++ b/clang/test/SemaCXX/attr-cxx0x.cpp
@@ -53,3 +53,14 @@ alignas(4) auto PR19252 = 0;
// Check the diagnostic message
class alignas(void) AlignasVoid {}; // expected-error {{invalid application of 'alignas' to an incomplete type 'void'}}
+
+namespace GH108819 {
+void a([[maybe_unused]] void) {} // expected-warning {{attribute 'maybe_unused' cannot be applied to a 'void' parameter}}\
+ // expected-warning {{use of the 'maybe_unused' attribute is a C++17 extension}}
+void b([[deprecated, maybe_unused]] void) {} // expected-warning {{attribute 'deprecated' cannot be applied to a 'void' parameter}} \
+ // expected-warning {{attribute 'maybe_unused' cannot be applied to a 'void' parameter}} \
+ // expected-warning {{use of the 'deprecated' attribute is a C++14 extension}} \
+ // expected-warning {{use of the 'maybe_unused' attribute is a C++17 extension}}
+void c([[clang::lifetimebound]] void) {} // expected-warning {{attribute 'lifetimebound' cannot be applied to a 'void' parameter}}
+void d([[clang::annotate("a", "b", 1)]] void) {} // expected-warning {{attribute 'annotate' cannot be applied to a 'void' parameter}}
+}
More information about the cfe-commits
mailing list