Skip to content

Commit 9043bdb

Browse files
authored
[clang] Output an error when [[lifetimebound]] attribute is applied on a function parameter while the function returns void (#113460)
Fixes: #107556
1 parent b3703fa commit 9043bdb

File tree

4 files changed

+35
-3
lines changed

4 files changed

+35
-3
lines changed

clang/docs/ReleaseNotes.rst

+9
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,15 @@ C++ Specific Potentially Breaking Changes
133133
// Fixed version:
134134
unsigned operator""_udl_name(unsigned long long);
135135

136+
- Clang will now produce an error diagnostic when [[clang::lifetimebound]] is
137+
applied on a parameter of a function that returns void. This was previously
138+
ignored and had no effect. (#GH107556)
139+
140+
.. code-block:: c++
141+
142+
// Now diagnoses with an error.
143+
void f(int& i [[clang::lifetimebound]]);
144+
136145
ABI Changes in This Version
137146
---------------------------
138147

clang/include/clang/Basic/DiagnosticSemaKinds.td

+3
Original file line numberDiff line numberDiff line change
@@ -10097,6 +10097,9 @@ def err_lifetimebound_no_object_param : Error<
1009710097
def err_lifetimebound_ctor_dtor : Error<
1009810098
"'lifetimebound' attribute cannot be applied to a "
1009910099
"%select{constructor|destructor}0">;
10100+
def err_lifetimebound_void_return_type : Error<
10101+
"'lifetimebound' attribute cannot be applied to a parameter of a function "
10102+
"that returns void">;
1010010103

1010110104
// CHECK: returning address/reference of stack memory
1010210105
def warn_ret_stack_addr_ref : Warning<

clang/lib/Sema/SemaDecl.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -6940,7 +6940,7 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
69406940
}
69416941
}
69426942

6943-
// Check the attributes on the function type, if any.
6943+
// Check the attributes on the function type and function params, if any.
69446944
if (const auto *FD = dyn_cast<FunctionDecl>(&ND)) {
69456945
// Don't declare this variable in the second operand of the for-statement;
69466946
// GCC miscompiles that by ending its lifetime before evaluating the
@@ -6970,6 +6970,18 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
69706970
}
69716971
}
69726972
}
6973+
6974+
for (unsigned int I = 0; I < FD->getNumParams(); ++I) {
6975+
const ParmVarDecl *P = FD->getParamDecl(I);
6976+
6977+
// The [[lifetimebound]] attribute can be applied to a function parameter
6978+
// only if the function returns a value.
6979+
if (auto *A = P->getAttr<LifetimeBoundAttr>()) {
6980+
if (!isa<CXXConstructorDecl>(FD) && FD->getReturnType()->isVoidType()) {
6981+
S.Diag(A->getLocation(), diag::err_lifetimebound_void_return_type);
6982+
}
6983+
}
6984+
}
69736985
}
69746986
}
69756987

clang/test/SemaCXX/attr-lifetimebound.cpp

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
// RUN: %clang_cc1 -std=c++23 -verify %s
22

33
namespace usage_invalid {
4-
// FIXME: Should we diagnose a void return type?
5-
void voidreturn(int &param [[clang::lifetimebound]]);
4+
void void_return(int &param [[clang::lifetimebound]]); // expected-error {{'lifetimebound' attribute cannot be applied to a parameter of a function that returns void}}
65

76
int *not_class_member() [[clang::lifetimebound]]; // expected-error {{non-member function has no implicit object parameter}}
87
struct A {
@@ -12,6 +11,8 @@ namespace usage_invalid {
1211
int *explicit_object(this A&) [[clang::lifetimebound]]; // expected-error {{explicit object member function has no implicit object parameter}}
1312
int not_function [[clang::lifetimebound]]; // expected-error {{only applies to parameters and implicit object parameters}}
1413
int [[clang::lifetimebound]] also_not_function; // expected-error {{cannot be applied to types}}
14+
// FIXME: Should diagnose a void return type.
15+
void void_return_member() [[clang::lifetimebound]];
1516
};
1617
int *attr_with_param(int &param [[clang::lifetimebound(42)]]); // expected-error {{takes no arguments}}
1718
}
@@ -31,6 +32,13 @@ namespace usage_ok {
3132
return *(int*)param;
3233
}
3334

35+
template <class T, class R = void> R dependent_void(const T& t [[clang::lifetimebound]]);
36+
void dependent_void_instantiation() {
37+
dependent_void<int>(1); // OK: Returns void.
38+
int x = dependent_void<int, int>(1); // expected-warning {{temporary whose address is used as value of local variable 'x' will be destroyed at the end of the full-expression}}
39+
dependent_void<int, int>(1); // OK: Returns an unused value.
40+
}
41+
3442
struct A {
3543
A();
3644
A(int);

0 commit comments

Comments
 (0)