Revert "Diagnose problematic uses of constructor/destructor attribute (#67673)"
This reverts commit 27ecb63c26.
Still fails compiler-rt:
https://lab.llvm.org/buildbot/#/builders/109/builds/75364
This commit is contained in:
@@ -217,11 +217,6 @@ Attribute Changes in Clang
|
||||
automatic diagnostic to use parameters of types that the format style
|
||||
supports but that are never the result of default argument promotion, such as
|
||||
``float``. (`#59824: <https://github.com/llvm/llvm-project/issues/59824>`_)
|
||||
- The ``constructor`` and ``destructor`` attributes now diagnose when:
|
||||
- the priority is not between 101 and 65535, inclusive,
|
||||
- the function it is applied to accepts arguments or has a non-void return
|
||||
type, or
|
||||
- the function it is applied to is a non-static member function (C++).
|
||||
|
||||
Improvements to Clang's diagnostics
|
||||
-----------------------------------
|
||||
|
||||
@@ -7255,14 +7255,8 @@ after returning from ``main()`` or when the ``exit()`` function has been
|
||||
called. Note, ``quick_exit()``, ``_Exit()``, and ``abort()`` prevent a function
|
||||
marked ``destructor`` from being called.
|
||||
|
||||
In general, the constructor or destructor function must use the C calling
|
||||
convention, cannot accept any arguments, and its return type should be
|
||||
``void``, ``int``, or ``unsigned int``. The latter two types are supported for
|
||||
historical reasons. On targets with a GNU environment (one which uses glibc),
|
||||
the signature of the function can also be the same as that of ``main()``.
|
||||
|
||||
In C++ language modes, the function cannot be marked ``consteval``, nor can it
|
||||
be a non-static member function.
|
||||
The constructor or destructor function should not accept any arguments and its
|
||||
return type should be ``void``.
|
||||
|
||||
The attributes accept an optional argument used to specify the priority order
|
||||
in which to execute constructor and destructor functions. The priority is
|
||||
|
||||
@@ -105,10 +105,6 @@ def EnumConversion : DiagGroup<"enum-conversion",
|
||||
[EnumEnumConversion,
|
||||
EnumFloatConversion,
|
||||
EnumCompareConditional]>;
|
||||
def InvalidPriority : DiagGroup<"priority-ctor-dtor">;
|
||||
// For compatibility with GCC.
|
||||
def : DiagGroup<"prio-ctor-dtor", [InvalidPriority]>;
|
||||
|
||||
def ObjCSignedCharBoolImplicitIntConversion :
|
||||
DiagGroup<"objc-signed-char-bool-implicit-int-conversion">;
|
||||
def ImplicitIntConversion : DiagGroup<"implicit-int-conversion",
|
||||
|
||||
@@ -2870,8 +2870,6 @@ def warn_cxx11_compat_constexpr_body_multiple_return : Warning<
|
||||
InGroup<CXXPre14Compat>, DefaultIgnore;
|
||||
def note_constexpr_body_previous_return : Note<
|
||||
"previous return statement is here">;
|
||||
def err_ctordtor_attr_consteval : Error<
|
||||
"%0 attribute cannot be applied to a 'consteval' function">;
|
||||
|
||||
// C++20 function try blocks in constexpr
|
||||
def ext_constexpr_function_try_block_cxx20 : ExtWarn<
|
||||
@@ -3184,13 +3182,6 @@ def err_alignas_underaligned : Error<
|
||||
"requested alignment is less than minimum alignment of %1 for type %0">;
|
||||
def warn_aligned_attr_underaligned : Warning<err_alignas_underaligned.Summary>,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def err_ctor_dtor_attr_on_non_void_func : Error<
|
||||
"%0 attribute can only be applied to a function which accepts no arguments "
|
||||
"and has a 'void' or 'int' return type">;
|
||||
def err_ctor_dtor_member_func : Error<
|
||||
"%0 attribute cannot be applied to a member function">;
|
||||
def err_ctor_dtor_calling_conv : Error<
|
||||
"%0 attribute must be applied to a function with the C calling convention">;
|
||||
def err_attribute_sizeless_type : Error<
|
||||
"%0 attribute cannot be applied to sizeless type %1">;
|
||||
def err_attribute_argument_n_type : Error<
|
||||
@@ -3204,9 +3195,6 @@ def err_attribute_argument_out_of_range : Error<
|
||||
def err_init_priority_object_attr : Error<
|
||||
"can only use 'init_priority' attribute on file-scope definitions "
|
||||
"of objects of class type">;
|
||||
def warn_priority_out_of_range : Warning<
|
||||
err_attribute_argument_out_of_range.Summary>,
|
||||
InGroup<InvalidPriority>, DefaultError;
|
||||
def err_attribute_argument_out_of_bounds : Error<
|
||||
"%0 attribute parameter %1 is out of bounds">;
|
||||
def err_attribute_only_once_per_parameter : Error<
|
||||
|
||||
@@ -2352,126 +2352,26 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
|
||||
}
|
||||
|
||||
static void diagnoseInvalidPriority(Sema &S, uint32_t Priority,
|
||||
const ParsedAttr &A,
|
||||
SourceLocation PriorityLoc) {
|
||||
constexpr uint32_t ReservedPriorityLower = 101, ReservedPriorityUpper = 65535;
|
||||
|
||||
// Only perform the priority check if the attribute is outside of a system
|
||||
// header. Values <= 100 are reserved for the implementation, and libc++
|
||||
// benefits from being able to specify values in that range. Values > 65535
|
||||
// are reserved for historical reasons.
|
||||
if ((Priority < ReservedPriorityLower || Priority > ReservedPriorityUpper) &&
|
||||
!S.getSourceManager().isInSystemHeader(A.getLoc())) {
|
||||
S.Diag(A.getLoc(), diag::warn_priority_out_of_range)
|
||||
<< PriorityLoc << A << ReservedPriorityLower << ReservedPriorityUpper;
|
||||
}
|
||||
}
|
||||
|
||||
static bool FunctionParamsAreMainLike(ASTContext &Context,
|
||||
const FunctionDecl *FD) {
|
||||
assert(FD->hasPrototype() && "expected the function to have a prototype");
|
||||
const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
|
||||
QualType CharPP =
|
||||
Context.getPointerType(Context.getPointerType(Context.CharTy));
|
||||
QualType Expected[] = {Context.IntTy, CharPP, CharPP, CharPP};
|
||||
for (unsigned I = 0;
|
||||
I < sizeof(Expected) / sizeof(QualType) && I < FPT->getNumParams();
|
||||
++I) {
|
||||
QualType AT = FPT->getParamType(I);
|
||||
|
||||
if (!Context.hasSameUnqualifiedType(AT, Expected[I])) {
|
||||
if (Expected[I] == CharPP) {
|
||||
// As an extension, the following forms are okay:
|
||||
// char const **
|
||||
// char const * const *
|
||||
// char * const *
|
||||
|
||||
QualifierCollector Qs;
|
||||
const PointerType *PT;
|
||||
if ((PT = Qs.strip(AT)->getAs<PointerType>()) &&
|
||||
(PT = Qs.strip(PT->getPointeeType())->getAs<PointerType>()) &&
|
||||
Context.hasSameType(QualType(Qs.strip(PT->getPointeeType()), 0),
|
||||
Context.CharTy)) {
|
||||
Qs.removeConst();
|
||||
if (!Qs.empty())
|
||||
return false;
|
||||
continue; // Accepted as an extension.
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename CtorDtorAttr>
|
||||
static void handleCtorDtorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
uint32_t Priority = CtorDtorAttr::DefaultPriority;
|
||||
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 we're given an argument for the priority, check that it's valid.
|
||||
if (AL.getNumArgs()) {
|
||||
if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Priority))
|
||||
return;
|
||||
|
||||
// Diagnose an invalid priority, but continue to process the attribute.
|
||||
diagnoseInvalidPriority(S, Priority, AL, AL.getArgAsExpr(0)->getExprLoc());
|
||||
}
|
||||
|
||||
// Ensure the function we're attaching to is something that is sensible to
|
||||
// automatically call before or after main(); it should accept no arguments.
|
||||
// In theory, a void return type is the only truly safe return type (consider
|
||||
// that calling conventions may place returned values in a hidden pointer
|
||||
// argument passed to the function that will not be present when called
|
||||
// automatically). However, there is a significant amount of existing code
|
||||
// which uses an int return type. So we will accept void, int, and
|
||||
// unsigned int return types. Any other return type, or a non-void parameter
|
||||
// list is treated as an error because it's a form of type system
|
||||
// incompatibility. The function also cannot be a member function. We allow
|
||||
// K&R C functions because that's a difficult edge case where it depends on
|
||||
// how the function is defined as to whether it does or does not expect
|
||||
// arguments.
|
||||
//
|
||||
// However! glibc on ELF will pass the same arguments to a constructor
|
||||
// function as are given to main(), so we will allow `int, char *[]` and
|
||||
// `int, char *[], char *[]` (or qualified versions thereof), but only if
|
||||
// the target is explicitly for glibc.
|
||||
const auto *FD = cast<FunctionDecl>(D);
|
||||
QualType RetTy = FD->getReturnType();
|
||||
bool IsGlibC = S.Context.getTargetInfo().getTriple().isGNUEnvironment();
|
||||
if (!(RetTy->isVoidType() ||
|
||||
RetTy->isSpecificBuiltinType(BuiltinType::UInt) ||
|
||||
RetTy->isSpecificBuiltinType(BuiltinType::Int)) ||
|
||||
FD->isVariadic() ||
|
||||
(FD->hasPrototype() &&
|
||||
((!IsGlibC && FD->getNumParams() != 0) ||
|
||||
(IsGlibC && !FunctionParamsAreMainLike(S.Context, FD))))) {
|
||||
S.Diag(AL.getLoc(), diag::err_ctor_dtor_attr_on_non_void_func)
|
||||
<< AL << FD->getSourceRange();
|
||||
if (AL.getNumArgs() &&
|
||||
!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
|
||||
return;
|
||||
}
|
||||
if (FD->getType()->castAs<FunctionType>()->getCallConv() !=
|
||||
CallingConv::CC_C) {
|
||||
S.Diag(AL.getLoc(), diag::err_ctor_dtor_calling_conv)
|
||||
<< AL << FD->getSourceRange();
|
||||
return;
|
||||
}
|
||||
if (const auto *MD = dyn_cast<CXXMethodDecl>(FD); MD && MD->isInstance()) {
|
||||
S.Diag(AL.getLoc(), diag::err_ctor_dtor_member_func)
|
||||
<< AL << FD->getSourceRange();
|
||||
return;
|
||||
}
|
||||
if (FD->isConsteval()) {
|
||||
S.Diag(AL.getLoc(), diag::err_ctordtor_attr_consteval)
|
||||
<< AL << FD->getSourceRange();
|
||||
return;
|
||||
}
|
||||
|
||||
D->addAttr(CtorDtorAttr::Create(S.Context, Priority, AL));
|
||||
D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
|
||||
}
|
||||
|
||||
static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
uint32_t priority = DestructorAttr::DefaultPriority;
|
||||
if (AL.getNumArgs() &&
|
||||
!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
|
||||
return;
|
||||
|
||||
D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
|
||||
}
|
||||
|
||||
template <typename AttrTy>
|
||||
@@ -3988,9 +3888,16 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Diagnose an invalid priority, but continue to process the attribute.
|
||||
diagnoseInvalidPriority(S, prioritynum, AL, E->getExprLoc());
|
||||
|
||||
// Only perform the priority check if the attribute is outside of a system
|
||||
// header. Values <= 100 are reserved for the implementation, and libc++
|
||||
// benefits from being able to specify values in that range.
|
||||
if ((prioritynum < 101 || prioritynum > 65535) &&
|
||||
!S.getSourceManager().isInSystemHeader(AL.getLoc())) {
|
||||
S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range)
|
||||
<< E->getSourceRange() << AL << 101 << 65535;
|
||||
AL.setInvalid();
|
||||
return;
|
||||
}
|
||||
D->addAttr(::new (S.Context) InitPriorityAttr(S.Context, AL, prioritynum));
|
||||
}
|
||||
|
||||
@@ -9052,13 +8959,13 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
|
||||
handlePassObjectSizeAttr(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_Constructor:
|
||||
handleCtorDtorAttr<ConstructorAttr>(S, D, AL);
|
||||
handleConstructorAttr(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_Deprecated:
|
||||
handleDeprecatedAttr(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_Destructor:
|
||||
handleCtorDtorAttr<DestructorAttr>(S, D, AL);
|
||||
handleDestructorAttr(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_EnableIf:
|
||||
handleEnableIfAttr(S, D, AL);
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
// RUN: -fno-use-cxa-atexit -fregister-global-dtors-with-atexit < %s | \
|
||||
// RUN: FileCheck --check-prefix=REGISTER %s
|
||||
|
||||
int bar(void) __attribute__((destructor(101)));
|
||||
int bar(void) __attribute__((destructor(100)));
|
||||
int bar2(void) __attribute__((destructor(65535)));
|
||||
int bar3(int) __attribute__((destructor(65535)));
|
||||
|
||||
int bar(void) {
|
||||
return 1;
|
||||
@@ -23,12 +24,16 @@ int bar2(void) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// NO-REGISTER: @llvm.global_dtors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 101, ptr @bar, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @bar2, ptr null }]
|
||||
int bar3(int a) {
|
||||
return a;
|
||||
}
|
||||
|
||||
// REGISTER: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 101, ptr @__GLOBAL_init_101, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__GLOBAL_init_65535, ptr null }]
|
||||
// REGISTER: @llvm.global_dtors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 101, ptr @__GLOBAL_cleanup_101, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__GLOBAL_cleanup_65535, ptr null }]
|
||||
// NO-REGISTER: @llvm.global_dtors = appending global [3 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 100, ptr @bar, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @bar2, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @bar3, ptr null }]
|
||||
|
||||
// REGISTER: define internal void @__GLOBAL_init_101() [[ATTR:#[0-9]+]] {
|
||||
// REGISTER: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 100, ptr @__GLOBAL_init_100, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__GLOBAL_init_65535, ptr null }]
|
||||
// REGISTER: @llvm.global_dtors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 100, ptr @__GLOBAL_cleanup_100, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__GLOBAL_cleanup_65535, ptr null }]
|
||||
|
||||
// REGISTER: define internal void @__GLOBAL_init_100() [[ATTR:#[0-9]+]] {
|
||||
// REGISTER: entry:
|
||||
// REGISTER: %0 = call i32 @atexit(ptr @bar)
|
||||
// REGISTER: ret void
|
||||
@@ -37,10 +42,11 @@ int bar2(void) {
|
||||
// REGISTER: define internal void @__GLOBAL_init_65535() [[ATTR:#[0-9]+]] {
|
||||
// REGISTER: entry:
|
||||
// REGISTER: %0 = call i32 @atexit(ptr @bar2)
|
||||
// REGISTER: %1 = call i32 @atexit(ptr @bar3)
|
||||
// REGISTER: ret void
|
||||
// REGISTER: }
|
||||
|
||||
// REGISTER: define internal void @__GLOBAL_cleanup_101() [[ATTR:#[0-9]+]] {
|
||||
// REGISTER: define internal void @__GLOBAL_cleanup_100() [[ATTR:#[0-9]+]] {
|
||||
// REGISTER: entry:
|
||||
// REGISTER: %0 = call i32 @unatexit(ptr @bar)
|
||||
// REGISTER: %needs_destruct = icmp eq i32 %0, 0
|
||||
@@ -56,11 +62,20 @@ int bar2(void) {
|
||||
|
||||
// REGISTER: define internal void @__GLOBAL_cleanup_65535() [[ATTR:#[0-9]+]] {
|
||||
// REGISTER: entry:
|
||||
// REGISTER: %0 = call i32 @unatexit(ptr @bar2)
|
||||
// REGISTER: %0 = call i32 @unatexit(ptr @bar3)
|
||||
// REGISTER: %needs_destruct = icmp eq i32 %0, 0
|
||||
// REGISTER: br i1 %needs_destruct, label %destruct.call, label %destruct.end
|
||||
// REGISTER: br i1 %needs_destruct, label %destruct.call, label %unatexit.call
|
||||
|
||||
// REGISTER: destruct.call:
|
||||
// REGISTER: call void @bar3()
|
||||
// REGISTER: br label %unatexit.call
|
||||
|
||||
// REGISTER: unatexit.call:
|
||||
// REGISTER: %1 = call i32 @unatexit(ptr @bar2)
|
||||
// REGISTER: %needs_destruct1 = icmp eq i32 %1, 0
|
||||
// REGISTER: br i1 %needs_destruct1, label %destruct.call2, label %destruct.end
|
||||
|
||||
// REGISTER: destruct.call2:
|
||||
// REGISTER: call void @bar2()
|
||||
// REGISTER: br label %destruct.end
|
||||
|
||||
|
||||
@@ -17,8 +17,9 @@ struct test {
|
||||
~test();
|
||||
} t;
|
||||
|
||||
int bar() __attribute__((destructor(101)));
|
||||
int bar() __attribute__((destructor(100)));
|
||||
int bar2() __attribute__((destructor(65535)));
|
||||
int bar3(int) __attribute__((destructor(65535)));
|
||||
|
||||
int bar() {
|
||||
return 1;
|
||||
@@ -28,13 +29,17 @@ int bar2() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
int bar3(int a) {
|
||||
return a;
|
||||
}
|
||||
|
||||
// NO-REGISTER: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I__, ptr null }]
|
||||
// NO-REGISTER: @llvm.global_dtors = appending global [3 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 101, ptr @_Z3barv, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @_Z4bar2v, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__D_a, ptr null }]
|
||||
// NO-REGISTER: @llvm.global_dtors = appending global [4 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 100, ptr @_Z3barv, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @_Z4bar2v, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @_Z4bar3i, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__D_a, ptr null }]
|
||||
|
||||
// REGISTER: @llvm.global_ctors = appending global [3 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I__, ptr null }, { i32, ptr, ptr } { i32 101, ptr @__GLOBAL_init_101, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__GLOBAL_init_65535, ptr null }]
|
||||
// REGISTER: @llvm.global_dtors = appending global [3 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__D_a, ptr null }, { i32, ptr, ptr } { i32 101, ptr @__GLOBAL_cleanup_101, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__GLOBAL_cleanup_65535, ptr null }]
|
||||
// REGISTER: @llvm.global_ctors = appending global [3 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I__, ptr null }, { i32, ptr, ptr } { i32 100, ptr @__GLOBAL_init_100, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__GLOBAL_init_65535, ptr null }]
|
||||
// REGISTER: @llvm.global_dtors = appending global [3 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__D_a, ptr null }, { i32, ptr, ptr } { i32 100, ptr @__GLOBAL_cleanup_100, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__GLOBAL_cleanup_65535, ptr null }]
|
||||
|
||||
// REGISTER: define internal void @__GLOBAL_init_101() [[ATTR:#[0-9]+]] {
|
||||
// REGISTER: define internal void @__GLOBAL_init_100() [[ATTR:#[0-9]+]] {
|
||||
// REGISTER: entry:
|
||||
// REGISTER: %0 = call i32 @atexit(ptr @_Z3barv)
|
||||
// REGISTER: ret void
|
||||
@@ -43,10 +48,11 @@ int bar2() {
|
||||
// REGISTER: define internal void @__GLOBAL_init_65535() [[ATTR:#[0-9]+]] {
|
||||
// REGISTER: entry:
|
||||
// REGISTER: %0 = call i32 @atexit(ptr @_Z4bar2v)
|
||||
// REGISTER: %1 = call i32 @atexit(ptr @_Z4bar3i)
|
||||
// REGISTER: ret void
|
||||
// REGISTER: }
|
||||
|
||||
// REGISTER: define internal void @__GLOBAL_cleanup_101() [[ATTR:#[0-9]+]] {
|
||||
// REGISTER: define internal void @__GLOBAL_cleanup_100() [[ATTR:#[0-9]+]] {
|
||||
// REGISTER: entry:
|
||||
// REGISTER: %0 = call i32 @unatexit(ptr @_Z3barv)
|
||||
// REGISTER: %needs_destruct = icmp eq i32 %0, 0
|
||||
@@ -62,11 +68,20 @@ int bar2() {
|
||||
|
||||
// REGISTER: define internal void @__GLOBAL_cleanup_65535() [[ATTR:#[0-9]+]] {
|
||||
// REGISTER: entry:
|
||||
// REGISTER: %0 = call i32 @unatexit(ptr @_Z4bar2v)
|
||||
// REGISTER: %0 = call i32 @unatexit(ptr @_Z4bar3i)
|
||||
// REGISTER: %needs_destruct = icmp eq i32 %0, 0
|
||||
// REGISTER: br i1 %needs_destruct, label %destruct.call, label %destruct.end
|
||||
// REGISTER: br i1 %needs_destruct, label %destruct.call, label %unatexit.call
|
||||
|
||||
// REGISTER: destruct.call:
|
||||
// REGISTER: call void @_Z4bar3i()
|
||||
// REGISTER: br label %unatexit.call
|
||||
|
||||
// REGISTER: unatexit.call:
|
||||
// REGISTER: %1 = call i32 @unatexit(ptr @_Z4bar2v)
|
||||
// REGISTER: %needs_destruct1 = icmp eq i32 %1, 0
|
||||
// REGISTER: br i1 %needs_destruct1, label %destruct.call2, label %destruct.end
|
||||
|
||||
// REGISTER: destruct.call2:
|
||||
// REGISTER: call void @_Z4bar2v()
|
||||
// REGISTER: br label %destruct.end
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=err %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=warn -Wno-error=priority-ctor-dtor %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=okay -Wno-priority-ctor-dtor %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=okay -Wno-prio-ctor-dtor %s
|
||||
// okay-no-diagnostics
|
||||
|
||||
void f(void) __attribute__((constructor(1))); // warn-warning {{'constructor' attribute requires integer constant between 101 and 65535 inclusive}} \
|
||||
err-error {{'constructor' attribute requires integer constant between 101 and 65535 inclusive}}
|
||||
void f(void) __attribute__((destructor(1))); // warn-warning {{'destructor' attribute requires integer constant between 101 and 65535 inclusive}} \
|
||||
err-error {{'destructor' attribute requires integer constant between 101 and 65535 inclusive}}
|
||||
@@ -1,75 +1,16 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-musl -fsyntax-only -verify=expected,nonglibc -Wno-strict-prototypes %s
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -verify -Wno-strict-prototypes %s
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-musl -fsyntax-only -verify=expected,nonglibc -x c++ -std=c++20 %s
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -verify -x c++ -std=c++20 %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-strict-prototypes %s
|
||||
|
||||
int x1 __attribute__((constructor)); // expected-warning {{'constructor' attribute only applies to functions}}
|
||||
void f(void) __attribute__((constructor));
|
||||
void f(void) __attribute__((constructor(1))); // expected-error {{'constructor' attribute requires integer constant between 101 and 65535 inclusive}}
|
||||
void f(void) __attribute__((constructor(1,2))); // expected-error {{'constructor' attribute takes no more than 1 argument}}
|
||||
void f(void) __attribute__((constructor(1.0))); // expected-error {{'constructor' attribute requires an integer constant}}
|
||||
void 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 f(void) __attribute__((constructor(101)));
|
||||
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}}
|
||||
|
||||
int x2 __attribute__((destructor)); // expected-warning {{'destructor' attribute only applies to functions}}
|
||||
void f(void) __attribute__((destructor));
|
||||
void f(void) __attribute__((destructor(1))); // expected-error {{'destructor' attribute requires integer constant between 101 and 65535 inclusive}}
|
||||
void f(void) __attribute__((destructor(1,2))); // expected-error {{'destructor' attribute takes no more than 1 argument}}
|
||||
void f(void) __attribute__((destructor(1.0))); // expected-error {{'destructor' attribute requires an integer constant}}
|
||||
void f(void) __attribute__((destructor(101)));
|
||||
int x __attribute__((destructor)); // expected-warning {{'destructor' attribute only applies to functions}}
|
||||
int f(void) __attribute__((destructor));
|
||||
int f(void) __attribute__((destructor(1)));
|
||||
int f(void) __attribute__((destructor(1,2))); // expected-error {{'destructor' attribute takes no more than 1 argument}}
|
||||
int f(void) __attribute__((destructor(1.0))); // expected-error {{'destructor' attribute requires an integer constant}}
|
||||
|
||||
void knr1() __attribute__((constructor));
|
||||
void knr2() __attribute__((destructor));
|
||||
|
||||
// Require a void or (unsigned) int return type
|
||||
int g0(void) __attribute__((constructor));
|
||||
signed int g1(void) __attribute__((constructor));
|
||||
float g2(void) __attribute__((constructor)); // expected-error {{'constructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
int h0(void) __attribute__((destructor));
|
||||
unsigned int h1(void) __attribute__((destructor));
|
||||
float h2(void) __attribute__((destructor)); // expected-error {{'destructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
|
||||
// In glibc environments, allow main-like signatures, but otherwise disallow
|
||||
// any parameters.
|
||||
void i1(int v) __attribute__((constructor)); // nonglibc-error {{'constructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
void j1(int v) __attribute__((destructor)); // nonglibc-error {{'destructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
void i2(int argc, char *argv[]) __attribute__((constructor)); // nonglibc-error {{'constructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
void j2(int argc, char *argv[]) __attribute__((destructor)); // nonglibc-error {{'destructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
void i3(int argc, char *const argv[], char *environ[]) __attribute__((constructor)); // nonglibc-error {{'constructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
void j3(int argc, const char *argv[], char *environ[]) __attribute__((destructor)); // nonglibc-error {{'destructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
void i4(int argc, float f) __attribute__((constructor)); // expected-error {{'constructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
void j4(int argc, float f) __attribute__((destructor)); // expected-error {{'destructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
|
||||
// Disallow calling conventions other than the C calling convention
|
||||
__attribute__((regcall, constructor)) void k(void); // expected-error {{'constructor' attribute must be applied to a function with the C calling convention}}
|
||||
|
||||
#ifdef __cplusplus
|
||||
// Disallow variadic functions.
|
||||
__attribute__((constructor)) void g1(...); // expected-error {{'constructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
__attribute__((destructor)) void g2(...); // expected-error {{'destructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
|
||||
struct S {
|
||||
// Not allowed on a nonstatic member function, but is allowed on a static
|
||||
// member function so long as it has no args/void return type.
|
||||
void mem1() __attribute__((constructor)); // expected-error {{'constructor' attribute cannot be applied to a member function}}
|
||||
void mem2() __attribute__((destructor)); // expected-error {{'destructor' attribute cannot be applied to a member function}}
|
||||
|
||||
static signed nonmem1() __attribute__((constructor));
|
||||
static unsigned nonmem2() __attribute__((destructor));
|
||||
|
||||
static _BitInt(32) nonmem3() __attribute__((constructor)); // expected-error {{'constructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
static char nonmem4() __attribute__((destructor)); // expected-error {{'destructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
|
||||
static void nonmem5(int) __attribute__((constructor)); // nonglibc-error {{'constructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
static void nonmem6(int) __attribute__((destructor)); // nonglibc-error {{'destructor' attribute can only be applied to a function which accepts no arguments and has a 'void' or 'int' return type}}
|
||||
};
|
||||
|
||||
consteval void consteval_func1() __attribute__((constructor)); // expected-error {{'constructor' attribute cannot be applied to a 'consteval' function}}
|
||||
consteval void consteval_func2() __attribute__((destructor)); // expected-error {{'destructor' attribute cannot be applied to a 'consteval' function}}
|
||||
#endif // __cplusplus
|
||||
|
||||
# 1 "source.c" 1 3
|
||||
// Can use reserved priorities within a system header
|
||||
void f(void) __attribute__((constructor(1)));
|
||||
void f(void) __attribute__((destructor(1)));
|
||||
# 1 "source.c" 2
|
||||
void knr() __attribute__((constructor));
|
||||
|
||||
@@ -480,7 +480,6 @@ endif()
|
||||
append_list_if(COMPILER_RT_HAS_WGNU_FLAG -Wno-gnu SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WC99_EXTENSIONS_FLAG -Wno-c99-extensions SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WPRIO_CTOR_DTOR_FLAG -Wno-prio-ctor-dtor SANITIZER_COMMON_CFLAGS)
|
||||
# format-pedantic warns about passing T* for %p, which is not useful.
|
||||
append_list_if(COMPILER_RT_HAS_WD4146_FLAG /wd4146 SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WD4291_FLAG /wd4291 SANITIZER_COMMON_CFLAGS)
|
||||
|
||||
@@ -137,7 +137,7 @@ check_cxx_compiler_flag("-Werror -Wthread-safety-beta" COMPILER_RT_HAS_WTHREAD_S
|
||||
check_cxx_compiler_flag(-Wno-pedantic COMPILER_RT_HAS_WNO_PEDANTIC)
|
||||
check_cxx_compiler_flag(-Wno-format COMPILER_RT_HAS_WNO_FORMAT)
|
||||
check_cxx_compiler_flag(-Wno-format-pedantic COMPILER_RT_HAS_WNO_FORMAT_PEDANTIC)
|
||||
check_cxx_compiler_flag(-Wno-prio-ctor-dtor COMPILER_RT_HAS_WPRIO_CTOR_DTOR_FLAG)
|
||||
|
||||
check_cxx_compiler_flag("/experimental:external /external:W0" COMPILER_RT_HAS_EXTERNAL_FLAG)
|
||||
|
||||
check_cxx_compiler_flag(/W4 COMPILER_RT_HAS_W4_FLAG)
|
||||
|
||||
@@ -754,10 +754,6 @@ else ()
|
||||
|
||||
append_list_if(COMPILER_RT_HAS_STD_C11_FLAG -std=c11 BUILTIN_CFLAGS)
|
||||
|
||||
# Disable diagnostics about use of reserved priority values (we are the
|
||||
# implementation, so we're allowed to use those reserved values).
|
||||
append_list_if(COMPILER_RT_HAS_WPRIO_CTOR_DTOR_FLAG -Wno-prio-ctor-dtor BUILTIN_CFLAGS)
|
||||
|
||||
# These flags would normally be added to CMAKE_C_FLAGS by the llvm
|
||||
# cmake step. Add them manually if this is a standalone build.
|
||||
if(COMPILER_RT_STANDALONE_BUILD)
|
||||
@@ -912,7 +908,6 @@ if (COMPILER_RT_BUILD_CRT)
|
||||
append_list_if(COMPILER_RT_CRT_USE_EH_FRAME_REGISTRY -DEH_USE_FRAME_REGISTRY CRT_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC CRT_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WNO_PEDANTIC -Wno-pedantic CRT_CFLAGS)
|
||||
|
||||
if (COMPILER_RT_HAS_FCF_PROTECTION_FLAG)
|
||||
append_list_if(COMPILER_RT_ENABLE_CET -fcf-protection=full CRT_CFLAGS)
|
||||
endif()
|
||||
|
||||
@@ -124,10 +124,6 @@ append_list_if(COMPILER_RT_HAS_WD4221_FLAG /wd4221 EXTRA_FLAGS)
|
||||
# Disable 'nonstandard extension used: translation unit is empty'.
|
||||
append_list_if(COMPILER_RT_HAS_WD4206_FLAG /wd4206 EXTRA_FLAGS)
|
||||
|
||||
# Disable diagnostics about use of reserved priority values (we are the
|
||||
# implementation, so we're allowed to use those reserved values).
|
||||
append_list_if(COMPILER_RT_HAS_WPRIO_CTOR_DTOR_FLAG -Wno-prio-ctor-dtor EXTRA_FLAGS)
|
||||
|
||||
if(APPLE)
|
||||
add_compiler_rt_runtime(clang_rt.profile
|
||||
STATIC
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// Test that destructors and destructors whose priorities are greater than 100 are tracked.
|
||||
// RUN: mkdir -p %t.dir && cd %t.dir
|
||||
// RUN: %clang -Wno-prio-ctor-dtor --coverage %s -o %t -dumpdir ./
|
||||
// RUN: %clang --coverage %s -o %t -dumpdir ./
|
||||
// RUN: rm -f gcov-destructor.gcda && %run %t
|
||||
// RUN: llvm-cov gcov -t gcov-destructor.gcda | FileCheck %s
|
||||
// UNSUPPORTED: darwin
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// RUN: %clangxx -fsanitize=undefined -Wno-prio-ctor-dtor -shared-libsan %s -o %t && %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx -fsanitize=undefined -shared-libsan %s -o %t && %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// Ensure ubsan runtime/interceptors are lazily initialized if called early.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user