Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1454,9 +1454,13 @@ def ConstInit : InheritableAttr {

def Constructor : InheritableAttr {
let Spellings = [GCC<"constructor">];
let Args = [DefaultIntArgument<"Priority", 65535>];
let Args = [ExprArgument<"Priority", 1>];
let Subjects = SubjectList<[Function]>;
let TemplateDependent = 1;
let Documentation = [CtorDtorDocs];
let AdditionalMembers = [{
static constexpr unsigned DefaultPriority = 65535;
}];
}

def CPUSpecific : InheritableAttr {
Expand Down Expand Up @@ -1795,9 +1799,13 @@ def Deprecated : InheritableAttr {

def Destructor : InheritableAttr {
let Spellings = [GCC<"destructor">];
let Args = [DefaultIntArgument<"Priority", 65535>];
let Args = [ExprArgument<"Priority", 1>];
let Subjects = SubjectList<[Function]>;
let TemplateDependent = 1;
let Documentation = [CtorDtorDocs];
let AdditionalMembers = [{
static constexpr unsigned int DefaultPriority = 65535;
}];
}

def EmptyBases : InheritableAttr, TargetSpecificAttr<TargetMicrosoftRecordLayout> {
Expand Down
12 changes: 10 additions & 2 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6376,10 +6376,18 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,

SetLLVMFunctionAttributesForDefinition(D, Fn);

auto GetPriority = [this](const auto *Attr) -> int {
Expr *E = Attr->getPriority();
if (E) {
return E->EvaluateKnownConstInt(this->getContext()).getExtValue();
}
return Attr->DefaultPriority;
};

if (const ConstructorAttr *CA = D->getAttr<ConstructorAttr>())
AddGlobalCtor(Fn, CA->getPriority());
AddGlobalCtor(Fn, GetPriority(CA));
if (const DestructorAttr *DA = D->getAttr<DestructorAttr>())
AddGlobalDtor(Fn, DA->getPriority(), true);
AddGlobalDtor(Fn, GetPriority(DA), true);
if (getLangOpts().OpenMP && D->hasAttr<OMPDeclareTargetDeclAttr>())
getOpenMPRuntime().emitDeclareTargetFunction(D, GV);
}
Expand Down
44 changes: 34 additions & 10 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//

#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
Expand Down Expand Up @@ -58,6 +59,7 @@
#include "clang/Sema/SemaSwift.h"
#include "clang/Sema/SemaWasm.h"
#include "clang/Sema/SemaX86.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Demangle/Demangle.h"
Expand Down Expand Up @@ -2156,29 +2158,51 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
}

static ExprResult sharedGetConstructorDestructorAttrExpr(Sema &S,
const ParsedAttr &AL) {
// If no Expr node exists on the attribute, return a nullptr result (default
// priority to be used). If Expr node exists but is not valid, return an
// invalid result. Otherwise, return the Expr.
Expr *E = nullptr;
if (AL.getNumArgs() == 1) {
E = AL.getArgAsExpr(0);
if (E->isValueDependent()) {
if (!E->isTypeDependent() && !E->getType()->isIntegerType()) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIntegerConstant << E->getSourceRange();
return ExprError();
}
} else {
uint32_t priority;
if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) {
return ExprError();
}
return ConstantExpr::Create(S.Context, E,
APValue(llvm::APSInt::getUnsigned(priority)));
}
}
return E;
}

static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
uint32_t priority = ConstructorAttr::DefaultPriority;
if (S.getLangOpts().HLSL && AL.getNumArgs()) {
S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported);
return;
}
if (AL.getNumArgs() &&
!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority))
ExprResult E = sharedGetConstructorDestructorAttrExpr(S, AL);
if (E.isInvalid())
return;
S.Diag(D->getLocation(), diag::warn_global_constructor)
<< D->getSourceRange();

D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
D->addAttr(ConstructorAttr::Create(S.Context, E.get(), AL));
}

static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
uint32_t priority = DestructorAttr::DefaultPriority;
if (AL.getNumArgs() &&
!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority))
ExprResult E = sharedGetConstructorDestructorAttrExpr(S, AL);
if (E.isInvalid())
return;
S.Diag(D->getLocation(), diag::warn_global_destructor) << D->getSourceRange();

D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
D->addAttr(DestructorAttr::Create(S.Context, E.get(), AL));
}

template <typename AttrTy>
Expand Down
38 changes: 38 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,32 @@ static void instantiateDependentAnnotationAttr(
}
}

template <typename Attr>
static void sharedInstantiateConstructorDestructorAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const Attr *A,
Decl *New, ASTContext &C) {
Expr *tempInstPriority = nullptr;
{
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::Unevaluated);
ExprResult Result = S.SubstExpr(A->getPriority(), TemplateArgs);
if (Result.isInvalid())
return;
tempInstPriority = Result.get();
if (std::optional<llvm::APSInt> CE =
tempInstPriority->getIntegerConstantExpr(C)) {
// Consistent with non-templated priority arguments, which must fit in a
// 32-bit unsigned integer.
if (!CE->isIntN(32)) {
S.Diag(tempInstPriority->getExprLoc(), diag::err_ice_too_large)
<< toString(*CE, 10, false) << /*Size=*/32 << /*Unsigned=*/1;
return;
}
}
}
New->addAttr(Attr::Create(C, tempInstPriority, *A));
}

static Expr *instantiateDependentFunctionAttrCondition(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const Attr *A, Expr *OldCond, const Decl *Tmpl, FunctionDecl *New) {
Expand Down Expand Up @@ -825,6 +851,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}

if (auto *Constructor = dyn_cast<ConstructorAttr>(TmplAttr)) {
sharedInstantiateConstructorDestructorAttr(*this, TemplateArgs,
Constructor, New, Context);
continue;
}

if (auto *Destructor = dyn_cast<DestructorAttr>(TmplAttr)) {
sharedInstantiateConstructorDestructorAttr(*this, TemplateArgs,
Destructor, New, Context);
continue;
}

if (const auto *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr)) {
instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl,
cast<FunctionDecl>(New));
Expand Down
5 changes: 4 additions & 1 deletion clang/test/AST/ast-dump-attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@ __attribute__((pointer_with_type_tag(unsigned1,1,2)));

void TestInt(void) __attribute__((constructor(123)));
// CHECK: FunctionDecl{{.*}}TestInt
// CHECK-NEXT: ConstructorAttr{{.*}} 123
// CHECK-NEXT: ConstructorAttr
// CHECK-NEXT: ConstantExpr
// CHECK-NEXT: value: Int 123
// CHECK-NEXT: IntegerLiteral{{.*}} 123

static int TestString __attribute__((alias("alias1")));
// CHECK: VarDecl{{.*}}TestString
Expand Down
18 changes: 18 additions & 0 deletions clang/test/CodeGenCXX/constructor-attr.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s

// CHECK: @llvm.global_ctors
// CHECK-SAME: i32 65535, ptr @_ZN3Foo3fooEv
// CHECK-SAME: i32 101, ptr @_Z22template_dependent_cxxILi101EEvv
// CHECK-SAME: i32 102, ptr @_Z22template_dependent_gnuILi102EEvv
// CHECK-SAME: i32 103, ptr @_Z1fv
// CHECK-SAME: i32 104, ptr @_Z23template_dependent_nttpIiLi104EEvv

// PR6521
void bar();
Expand All @@ -10,3 +15,16 @@ struct Foo {
bar();
}
};


template <int P>
[[gnu::constructor(P)]] void template_dependent_cxx() {}
template <int P>
__attribute__((constructor(P))) void template_dependent_gnu() {}
template <typename T, int P = sizeof(T) * 26>
[[gnu::constructor(P)]] void template_dependent_nttp() {}

template void template_dependent_cxx<101>();
template void template_dependent_gnu<102>();
[[gnu::constructor(103)]] void f() {}
template void template_dependent_nttp<int>();
23 changes: 23 additions & 0 deletions clang/test/CodeGenCXX/destructor-attr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s

// CHECK: @llvm.global_dtors
// CHECK-SAME: i32 65535, ptr @_ZN3Foo3fooEv
// CHECK-SAME: i32 101, ptr @_Z22template_dependent_cxxILi101EEvv
// CHECK-SAME: i32 104, ptr @_Z23template_dependent_nttpIiLi104EEvv

// PR6521
void bar();
struct Foo {
// CHECK-LABEL: define linkonce_odr {{.*}}void @_ZN3Foo3fooEv
static void foo() __attribute__((destructor)) {
bar();
}
};

template <int P>
[[gnu::destructor(P)]] void template_dependent_cxx() {}
template <typename T, int P = sizeof(T) * 26>
[[gnu::destructor(P)]] void template_dependent_nttp() {}

template void template_dependent_cxx<101>();
template void template_dependent_nttp<int>();
16 changes: 0 additions & 16 deletions clang/test/Sema/constructor-attribute.c

This file was deleted.

74 changes: 74 additions & 0 deletions clang/test/Sema/constructor-attribute.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify -Wno-strict-prototypes %s
// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wno-strict-prototypes %s

int x __attribute__((constructor)); // expected-warning {{'constructor' attribute only applies to functions}}
int f(void) __attribute__((constructor));
int f(void) __attribute__((constructor(1)));
int f(void) __attribute__((constructor(1,2))); // expected-error {{'constructor' attribute takes no more than 1 argument}}
int f(void) __attribute__((constructor(1.0))); // expected-error {{'constructor' attribute requires an integer constant}}
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}}
void knr() __attribute__((constructor));

#ifdef __cplusplus
template <float P> [[gnu::constructor(P)]] void f(); // expected-error {{'gnu::constructor' attribute requires an integer constant}}
template <double P> [[gnu::constructor(P)]] void f(); // expected-error {{'gnu::constructor' attribute requires an integer constant}}
template <int *P> [[gnu::constructor(P)]] void f(); // expected-error {{'gnu::constructor' attribute requires an integer constant}}

template <long long P> [[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}}
template void f<1LL<<32>(); // expected-note {{in instantiation of function template specialization 'f<4294967296LL>' requested here}}
template void f<101>();

template <typename T> [[gnu::constructor(static_cast<T>(1LL<<32))]] void f() {} // expected-error {{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}}
template void f<long long>(); // expected-note {{in instantiation of function template specialization 'f<long long>' requested here}}
template void f<int>();

template <typename T>
[[gnu::constructor(static_cast<T>(101))]] void g() {}
template void g<int>();
template void g<long long>();

template <typename T>
[[gnu::constructor(static_cast<T>(T{101}))]] void h() {}
template void h<int>();
template void h<long long>();

template <typename T>
[[gnu::constructor(static_cast<T>(sizeof(T[101])))]] void a() {}
template void a<int>();
template void a<long long>();
#endif

int yd __attribute__((destructor)); // expected-warning {{'destructor' attribute only applies to functions}}
int fd(void) __attribute__((destructor));
int fd(void) __attribute__((destructor(1)));
int fd(void) __attribute__((destructor(1,2))); // expected-error {{'destructor' attribute takes no more than 1 argument}}
int fd(void) __attribute__((destructor(1.0))); // expected-error {{'destructor' attribute requires an integer constant}}

#ifdef __cplusplus
template <float P> [[gnu::destructor(P)]] void fd(); // expected-error {{'gnu::destructor' attribute requires an integer constant}}
template <double P> [[gnu::destructor(P)]] void fd(); // expected-error {{'gnu::destructor' attribute requires an integer constant}}
template <int *P> [[gnu::destructor(P)]] void fd(); // expected-error {{'gnu::destructor' attribute requires an integer constant}}

template <long long P> [[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}}
template void fd<1LL<<32>(); // expected-note {{in instantiation of function template specialization 'fd<4294967296LL>' requested here}}
template void fd<101>();

template <typename T> [[gnu::destructor(static_cast<T>(1LL<<32))]] void fd() {} // expected-error {{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}}
template void fd<long long>(); // expected-note {{in instantiation of function template specialization 'fd<long long>' requested here}}
template void fd<int>();

template <typename T>
[[gnu::destructor(static_cast<T>(101))]] void gd() {}
template void gd<int>();
template void gd<long long>();

template <typename T>
[[gnu::destructor(static_cast<T>(T{101}))]] void hd() {}
template void hd<int>();
template void hd<long long>();

template <typename T>
[[gnu::destructor(static_cast<T>(sizeof(T[101])))]] void ad() {}
template void ad<int>();
template void ad<long long>();
#endif