Skip to content

Commit d3a1e1f

Browse files
committed
[Clang] Add template argument support for {con,de}structor attributes.
Address PR comments.
1 parent e7c6ad6 commit d3a1e1f

File tree

6 files changed

+107
-14
lines changed

6 files changed

+107
-14
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1468,7 +1468,7 @@ def Constructor : InheritableAttr {
14681468
let TemplateDependent = 1;
14691469
let Documentation = [CtorDtorDocs];
14701470
let AdditionalMembers = [{
1471-
static constexpr unsigned int DefaultPriority = 65535;
1471+
static constexpr unsigned DefaultPriority = 65535;
14721472
}];
14731473
}
14741474

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6324,20 +6324,18 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
63246324

63256325
SetLLVMFunctionAttributesForDefinition(D, Fn);
63266326

6327-
auto getPriority = [this](auto *Attr) -> int {
6328-
int priority = Attr->DefaultPriority;
6327+
auto GetPriority = [this](const auto *Attr) -> int {
63296328
Expr *E = Attr->getPriority();
63306329
if (E) {
6331-
if (auto CE = E->getIntegerConstantExpr(this->getContext()))
6332-
priority = CE->getExtValue();
6330+
return E->EvaluateKnownConstInt(this->getContext()).getExtValue();
63336331
}
6334-
return priority;
6332+
return Attr->DefaultPriority;
63356333
};
63366334

63376335
if (const ConstructorAttr *CA = D->getAttr<ConstructorAttr>())
6338-
AddGlobalCtor(Fn, getPriority(CA));
6336+
AddGlobalCtor(Fn, GetPriority(CA));
63396337
if (const DestructorAttr *DA = D->getAttr<DestructorAttr>())
6340-
AddGlobalDtor(Fn, getPriority(DA), true);
6338+
AddGlobalDtor(Fn, GetPriority(DA), true);
63416339
if (getLangOpts().OpenMP && D->hasAttr<OMPDeclareTargetDeclAttr>())
63426340
getOpenMPRuntime().emitDeclareTargetFunction(D, GV);
63436341
}

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "clang/AST/APValue.h"
1314
#include "clang/AST/ASTConsumer.h"
1415
#include "clang/AST/ASTContext.h"
1516
#include "clang/AST/ASTMutationListener.h"
@@ -58,6 +59,7 @@
5859
#include "clang/Sema/SemaSwift.h"
5960
#include "clang/Sema/SemaWasm.h"
6061
#include "clang/Sema/SemaX86.h"
62+
#include "llvm/ADT/APSInt.h"
6163
#include "llvm/ADT/STLExtras.h"
6264
#include "llvm/ADT/StringExtras.h"
6365
#include "llvm/Demangle/Demangle.h"
@@ -2152,7 +2154,11 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
21522154
D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
21532155
}
21542156

2155-
static std::optional<Expr *> sharedGetConstructorDestructorAttrExpr(Sema &S, const ParsedAttr &AL) {
2157+
static std::optional<Expr *>
2158+
sharedGetConstructorDestructorAttrExpr(Sema &S, const ParsedAttr &AL) {
2159+
// If no Expr node exists on the attribute, return a nullptr (default priority
2160+
// to be used). If Expr node exists but is not valid, return a nullopt.
2161+
// Otherwise, return the Expr.
21562162
Expr *E = nullptr;
21572163
if (AL.getNumArgs() == 1) {
21582164
E = AL.getArgAsExpr(0);
@@ -2167,8 +2173,10 @@ static std::optional<Expr *> sharedGetConstructorDestructorAttrExpr(Sema &S, con
21672173
if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) {
21682174
return std::nullopt;
21692175
}
2176+
return ConstantExpr::Create(S.Context, E,
2177+
APValue(llvm::APSInt::getUnsigned(priority)));
21702178
}
2171-
}
2179+
}
21722180
return E;
21732181
}
21742182

@@ -2180,7 +2188,8 @@ static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
21802188
auto E = sharedGetConstructorDestructorAttrExpr(S, AL);
21812189
if (!E.has_value())
21822190
return;
2183-
S.Diag(D->getLocation(), diag::warn_global_constructor) << D->getSourceRange();
2191+
S.Diag(D->getLocation(), diag::warn_global_constructor)
2192+
<< D->getSourceRange();
21842193
D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, E.value()));
21852194
}
21862195

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,33 @@ static void instantiateDependentAnnotationAttr(
233233
}
234234
}
235235

236+
template <typename Attr>
237+
static void sharedInstantiateConstructorDestructorAttr(
238+
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const Attr *A,
239+
Decl *New, ASTContext &C) {
240+
Expr *tempInstPriority = nullptr;
241+
{
242+
EnterExpressionEvaluationContext Unevaluated(
243+
S, Sema::ExpressionEvaluationContext::Unevaluated);
244+
ExprResult Result = S.SubstExpr(A->getPriority(), TemplateArgs);
245+
if (Result.isInvalid())
246+
return;
247+
tempInstPriority = Result.get();
248+
if (auto CE = tempInstPriority->getIntegerConstantExpr(C)) {
249+
// Consistent with non-templated priority arguments, which must fit in a
250+
// 32-bit unsigned integer.
251+
if (!CE->isIntN(32)) {
252+
S.Diag(tempInstPriority->getExprLoc(), diag::err_ice_too_large)
253+
<< toString(*CE, 10, false) << 32 << 1;
254+
return;
255+
}
256+
}
257+
}
258+
Attr *NewAttr = new (C) Attr(C, *A, tempInstPriority);
259+
if (NewAttr)
260+
New->addAttr(NewAttr);
261+
}
262+
236263
static Expr *instantiateDependentFunctionAttrCondition(
237264
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
238265
const Attr *A, Expr *OldCond, const Decl *Tmpl, FunctionDecl *New) {
@@ -824,6 +851,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
824851
continue;
825852
}
826853

854+
if (auto *Constructor = dyn_cast<ConstructorAttr>(TmplAttr)) {
855+
sharedInstantiateConstructorDestructorAttr(*this, TemplateArgs,
856+
Constructor, New, Context);
857+
continue;
858+
}
859+
860+
if (auto *Destructor = dyn_cast<DestructorAttr>(TmplAttr)) {
861+
sharedInstantiateConstructorDestructorAttr(*this, TemplateArgs,
862+
Destructor, New, Context);
863+
continue;
864+
}
865+
827866
if (const auto *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr)) {
828867
instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl,
829868
cast<FunctionDecl>(New));

clang/test/CodeGenCXX/constructor-attr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// CHECK-SAME: i32 65535, ptr @_ZN3Foo3fooEv
55
// CHECK-SAME: i32 101, ptr @_Z22template_dependent_cxxILi101EEvv
66
// CHECK-SAME: i32 102, ptr @_Z22template_dependent_gnuILi102EEvv
7+
// CHECK-SAME: i32 103, ptr @_Z1fv
78
// CHECK-SAME: i32 104, ptr @_Z23template_dependent_nttpIiLi104EEvv
89

910
// PR6521
@@ -15,6 +16,7 @@ struct Foo {
1516
}
1617
};
1718

19+
1820
template <int P>
1921
[[gnu::constructor(P)]] void template_dependent_cxx() {}
2022
template <int P>
@@ -24,4 +26,5 @@ template <typename T, int P = sizeof(T) * 26>
2426

2527
template void template_dependent_cxx<101>();
2628
template void template_dependent_gnu<102>();
29+
[[gnu::constructor(103)]] void f() {}
2730
template void template_dependent_nttp<int>();
Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,62 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-strict-prototypes %s
2+
// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wno-strict-prototypes %s
23

34
int x __attribute__((constructor)); // expected-warning {{'constructor' attribute only applies to functions}}
45
int f(void) __attribute__((constructor));
56
int f(void) __attribute__((constructor(1)));
67
int f(void) __attribute__((constructor(1,2))); // expected-error {{'constructor' attribute takes no more than 1 argument}}
78
int f(void) __attribute__((constructor(1.0))); // expected-error {{'constructor' attribute requires an integer constant}}
89
int f(void) __attribute__((constructor(0x100000000))); // expected-error {{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}}
9-
template <int *I> [[gnu::constructor(I)]] void f(); // expected-error {{'gnu::constructor' attribute requires an integer constant}}
10+
void knr() __attribute__((constructor));
11+
12+
#ifdef __cplusplus
13+
template <int *P>
14+
[[gnu::constructor(P)]] void f(); // expected-error {{'gnu::constructor' attribute requires an integer constant}}
15+
16+
template <long long P>
17+
[[gnu::constructor(P)]] void f() {} // expected-error {{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}}
18+
template void f<1LL<<32>(); // expected-note {{in instantiation of function template specialization 'f<4294967296LL>' requested here}}
19+
template void f<101>();
20+
21+
template <typename T>
22+
[[gnu::constructor(static_cast<T>(101))]] void f() {}
23+
template void f<int>();
24+
template void f<long long>();
25+
26+
template <typename T>
27+
[[gnu::constructor(static_cast<T>(1LL<<32))]] void g() {}
28+
template void g<int>();
29+
30+
template <typename T>
31+
[[gnu::constructor(static_cast<T>(1LL<<32))]] void h() {} // expected-error {{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}}
32+
template void h<long long>(); // expected-note {{in instantiation of function template specialization 'h<long long>' requested here}}
33+
#endif
1034

1135
int y __attribute__((destructor)); // expected-warning {{'destructor' attribute only applies to functions}}
1236
int f(void) __attribute__((destructor));
1337
int f(void) __attribute__((destructor(1)));
1438
int f(void) __attribute__((destructor(1,2))); // expected-error {{'destructor' attribute takes no more than 1 argument}}
1539
int f(void) __attribute__((destructor(1.0))); // expected-error {{'destructor' attribute requires an integer constant}}
16-
template <int *I> [[gnu::destructor(I)]] void f(); // expected-error {{'gnu::destructor' attribute requires an integer constant}}
1740

18-
void knr() __attribute__((constructor));
41+
#ifdef __cplusplus
42+
template <int *I>
43+
[[gnu::destructor(I)]] void f(); // expected-error {{'gnu::destructor' attribute requires an integer constant}}
44+
45+
template <long long P>
46+
[[gnu::destructor(P)]] void fd() {} // expected-error {{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}}
47+
template void fd<1LL<<32>(); // expected-note {{in instantiation of function template specialization 'fd<4294967296LL>' requested here}}
48+
template void fd<101>();
49+
50+
template <typename T>
51+
[[gnu::destructor(static_cast<T>(101))]] void fd() {}
52+
template void fd<int>();
53+
template void fd<long long>();
54+
55+
template <typename T>
56+
[[gnu::destructor(static_cast<T>(1LL<<32))]] void gd() {}
57+
template void gd<int>();
58+
59+
template <typename T>
60+
[[gnu::destructor(static_cast<T>(1LL<<32))]] void hd() {} // expected-error {{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}}
61+
template void hd<long long>(); // expected-note {{in instantiation of function template specialization 'hd<long long>' requested here}}
62+
#endif

0 commit comments

Comments
 (0)