Skip to content

Commit e7c6ad6

Browse files
committed
[Clang] Add template argument support for {con,de}structor attributes.
Fixes: #67154
1 parent 9b4a44d commit e7c6ad6

File tree

7 files changed

+92
-18
lines changed

7 files changed

+92
-18
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,9 +1463,13 @@ def ConstInit : InheritableAttr {
14631463

14641464
def Constructor : InheritableAttr {
14651465
let Spellings = [GCC<"constructor">];
1466-
let Args = [DefaultIntArgument<"Priority", 65535>];
1466+
let Args = [ExprArgument<"Priority", 1>];
14671467
let Subjects = SubjectList<[Function]>;
1468+
let TemplateDependent = 1;
14681469
let Documentation = [CtorDtorDocs];
1470+
let AdditionalMembers = [{
1471+
static constexpr unsigned int DefaultPriority = 65535;
1472+
}];
14691473
}
14701474

14711475
def CPUSpecific : InheritableAttr {
@@ -1797,9 +1801,13 @@ def Deprecated : InheritableAttr {
17971801

17981802
def Destructor : InheritableAttr {
17991803
let Spellings = [GCC<"destructor">];
1800-
let Args = [DefaultIntArgument<"Priority", 65535>];
1804+
let Args = [ExprArgument<"Priority", 1>];
18011805
let Subjects = SubjectList<[Function]>;
1806+
let TemplateDependent = 1;
18021807
let Documentation = [CtorDtorDocs];
1808+
let AdditionalMembers = [{
1809+
static constexpr unsigned int DefaultPriority = 65535;
1810+
}];
18031811
}
18041812

18051813
def EmptyBases : InheritableAttr, TargetSpecificAttr<TargetMicrosoftRecordLayout> {

clang/lib/CodeGen/CodeGenModule.cpp

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

63256325
SetLLVMFunctionAttributesForDefinition(D, Fn);
63266326

6327+
auto getPriority = [this](auto *Attr) -> int {
6328+
int priority = Attr->DefaultPriority;
6329+
Expr *E = Attr->getPriority();
6330+
if (E) {
6331+
if (auto CE = E->getIntegerConstantExpr(this->getContext()))
6332+
priority = CE->getExtValue();
6333+
}
6334+
return priority;
6335+
};
6336+
63276337
if (const ConstructorAttr *CA = D->getAttr<ConstructorAttr>())
6328-
AddGlobalCtor(Fn, CA->getPriority());
6338+
AddGlobalCtor(Fn, getPriority(CA));
63296339
if (const DestructorAttr *DA = D->getAttr<DestructorAttr>())
6330-
AddGlobalDtor(Fn, DA->getPriority(), true);
6340+
AddGlobalDtor(Fn, getPriority(DA), true);
63316341
if (getLangOpts().OpenMP && D->hasAttr<OMPDeclareTargetDeclAttr>())
63326342
getOpenMPRuntime().emitDeclareTargetFunction(D, GV);
63336343
}

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2152,29 +2152,44 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
21522152
D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
21532153
}
21542154

2155+
static std::optional<Expr *> sharedGetConstructorDestructorAttrExpr(Sema &S, const ParsedAttr &AL) {
2156+
Expr *E = nullptr;
2157+
if (AL.getNumArgs() == 1) {
2158+
E = AL.getArgAsExpr(0);
2159+
if (E->isValueDependent()) {
2160+
if (!E->isTypeDependent() && !E->getType()->isIntegerType()) {
2161+
S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
2162+
<< AL << AANT_ArgumentIntegerConstant << E->getSourceRange();
2163+
return std::nullopt;
2164+
}
2165+
} else {
2166+
uint32_t priority;
2167+
if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) {
2168+
return std::nullopt;
2169+
}
2170+
}
2171+
}
2172+
return E;
2173+
}
2174+
21552175
static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2156-
uint32_t priority = ConstructorAttr::DefaultPriority;
21572176
if (S.getLangOpts().HLSL && AL.getNumArgs()) {
21582177
S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported);
21592178
return;
21602179
}
2161-
if (AL.getNumArgs() &&
2162-
!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority))
2180+
auto E = sharedGetConstructorDestructorAttrExpr(S, AL);
2181+
if (!E.has_value())
21632182
return;
2164-
S.Diag(D->getLocation(), diag::warn_global_constructor)
2165-
<< D->getSourceRange();
2166-
2167-
D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
2183+
S.Diag(D->getLocation(), diag::warn_global_constructor) << D->getSourceRange();
2184+
D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, E.value()));
21682185
}
21692186

21702187
static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2171-
uint32_t priority = DestructorAttr::DefaultPriority;
2172-
if (AL.getNumArgs() &&
2173-
!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority))
2188+
auto E = sharedGetConstructorDestructorAttrExpr(S, AL);
2189+
if (!E.has_value())
21742190
return;
21752191
S.Diag(D->getLocation(), diag::warn_global_destructor) << D->getSourceRange();
2176-
2177-
D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
2192+
D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, E.value()));
21782193
}
21792194

21802195
template <typename AttrTy>

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ __attribute__((pointer_with_type_tag(unsigned1,1,2)));
8888

8989
void TestInt(void) __attribute__((constructor(123)));
9090
// CHECK: FunctionDecl{{.*}}TestInt
91-
// CHECK-NEXT: ConstructorAttr{{.*}} 123
91+
// CHECK-NEXT: ConstructorAttr
92+
// CHECK-NEXT: IntegerLiteral{{.*}} 123
9293

9394
static int TestString __attribute__((alias("alias1")));
9495
// CHECK: VarDecl{{.*}}TestString

clang/test/CodeGenCXX/constructor-attr.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
22

33
// CHECK: @llvm.global_ctors
4+
// CHECK-SAME: i32 65535, ptr @_ZN3Foo3fooEv
5+
// CHECK-SAME: i32 101, ptr @_Z22template_dependent_cxxILi101EEvv
6+
// CHECK-SAME: i32 102, ptr @_Z22template_dependent_gnuILi102EEvv
7+
// CHECK-SAME: i32 104, ptr @_Z23template_dependent_nttpIiLi104EEvv
48

59
// PR6521
610
void bar();
@@ -10,3 +14,14 @@ struct Foo {
1014
bar();
1115
}
1216
};
17+
18+
template <int P>
19+
[[gnu::constructor(P)]] void template_dependent_cxx() {}
20+
template <int P>
21+
__attribute__((constructor(P))) void template_dependent_gnu() {}
22+
template <typename T, int P = sizeof(T) * 26>
23+
[[gnu::constructor(P)]] void template_dependent_nttp() {}
24+
25+
template void template_dependent_cxx<101>();
26+
template void template_dependent_gnu<102>();
27+
template void template_dependent_nttp<int>();
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
2+
3+
// CHECK: @llvm.global_dtors
4+
// CHECK-SAME: i32 65535, ptr @_ZN3Foo3fooEv
5+
// CHECK-SAME: i32 101, ptr @_Z22template_dependent_cxxILi101EEvv
6+
// CHECK-SAME: i32 104, ptr @_Z23template_dependent_nttpIiLi104EEvv
7+
8+
// PR6521
9+
void bar();
10+
struct Foo {
11+
// CHECK-LABEL: define linkonce_odr {{.*}}void @_ZN3Foo3fooEv
12+
static void foo() __attribute__((destructor)) {
13+
bar();
14+
}
15+
};
16+
17+
template <int P>
18+
[[gnu::destructor(P)]] void template_dependent_cxx() {}
19+
template <typename T, int P = sizeof(T) * 26>
20+
[[gnu::destructor(P)]] void template_dependent_nttp() {}
21+
22+
template void template_dependent_cxx<101>();
23+
template void template_dependent_nttp<int>();

clang/test/Sema/constructor-attribute.c renamed to clang/test/Sema/constructor-attribute.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ int f(void) __attribute__((constructor(1)));
66
int f(void) __attribute__((constructor(1,2))); // expected-error {{'constructor' attribute takes no more than 1 argument}}
77
int f(void) __attribute__((constructor(1.0))); // expected-error {{'constructor' attribute requires an integer constant}}
88
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}}
910

10-
int x __attribute__((destructor)); // expected-warning {{'destructor' attribute only applies to functions}}
11+
int y __attribute__((destructor)); // expected-warning {{'destructor' attribute only applies to functions}}
1112
int f(void) __attribute__((destructor));
1213
int f(void) __attribute__((destructor(1)));
1314
int f(void) __attribute__((destructor(1,2))); // expected-error {{'destructor' attribute takes no more than 1 argument}}
1415
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}}
1517

1618
void knr() __attribute__((constructor));

0 commit comments

Comments
 (0)