diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 530dbe55fcb13..2d918967e7f0b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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: `_) -- 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 ----------------------------------- diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index eb4ccc6fb9389..8d928dcc146b2 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -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 diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index e017ca45aeeeb..0b09c00219184 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -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", diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index cce4601770a7e..c1a6e3831127e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2870,8 +2870,6 @@ def warn_cxx11_compat_constexpr_body_multiple_return : Warning< InGroup, 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, InGroup; -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, 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< diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 964fcd6c6b15f..ed0b4d29b0563 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -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(); - 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()) && - (PT = Qs.strip(PT->getPointeeType())->getAs()) && - 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 -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 (AL.getNumArgs() && + !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) + 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()); - } + D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority)); +} - // 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(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(); - return; - } - if (FD->getType()->castAs()->getCallConv() != - CallingConv::CC_C) { - S.Diag(AL.getLoc(), diag::err_ctor_dtor_calling_conv) - << AL << FD->getSourceRange(); - return; - } - if (const auto *MD = dyn_cast(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(); +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(CtorDtorAttr::Create(S.Context, Priority, AL)); + D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority)); } template @@ -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(S, D, AL); + handleConstructorAttr(S, D, AL); break; case ParsedAttr::AT_Deprecated: handleDeprecatedAttr(S, D, AL); break; case ParsedAttr::AT_Destructor: - handleCtorDtorAttr(S, D, AL); + handleDestructorAttr(S, D, AL); break; case ParsedAttr::AT_EnableIf: handleEnableIfAttr(S, D, AL); diff --git a/clang/test/CodeGen/PowerPC/aix-destructor-attribute.c b/clang/test/CodeGen/PowerPC/aix-destructor-attribute.c index f0d83d161be50..cfb1fd7b0171a 100644 --- a/clang/test/CodeGen/PowerPC/aix-destructor-attribute.c +++ b/clang/test/CodeGen/PowerPC/aix-destructor-attribute.c @@ -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; +} + +// 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: @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 }] +// 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_101() [[ATTR:#[0-9]+]] { +// 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 diff --git a/clang/test/CodeGenCXX/aix-destructor-attribute.cpp b/clang/test/CodeGenCXX/aix-destructor-attribute.cpp index 2cdf147af8d07..5ebea7a997c9d 100644 --- a/clang/test/CodeGenCXX/aix-destructor-attribute.cpp +++ b/clang/test/CodeGenCXX/aix-destructor-attribute.cpp @@ -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 diff --git a/clang/test/Sema/constructor-attribute-diag-group.c b/clang/test/Sema/constructor-attribute-diag-group.c deleted file mode 100644 index e1828d62d28b7..0000000000000 --- a/clang/test/Sema/constructor-attribute-diag-group.c +++ /dev/null @@ -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}} diff --git a/clang/test/Sema/constructor-attribute.c b/clang/test/Sema/constructor-attribute.c index d29be13f68f89..2317c7735bda5 100644 --- a/clang/test/Sema/constructor-attribute.c +++ b/clang/test/Sema/constructor-attribute.c @@ -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 - -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 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))); - -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 +// RUN: %clang_cc1 -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}} + +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 knr() __attribute__((constructor)); diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt index 2e4b2c7070bb9..1a46f5b334806 100644 --- a/compiler-rt/CMakeLists.txt +++ b/compiler-rt/CMakeLists.txt @@ -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) diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake index 9ec08f8e99ea2..a8e078f1ebc98 100644 --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -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) diff --git a/compiler-rt/test/profile/Posix/gcov-destructor.c b/compiler-rt/test/profile/Posix/gcov-destructor.c index ed4360636c1fc..bd1e0d2dde079 100644 --- a/compiler-rt/test/profile/Posix/gcov-destructor.c +++ b/compiler-rt/test/profile/Posix/gcov-destructor.c @@ -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 diff --git a/compiler-rt/test/ubsan/TestCases/Misc/Linux/sigaction.cpp b/compiler-rt/test/ubsan/TestCases/Misc/Linux/sigaction.cpp index f89c14acca98d..0ab65bd30d92c 100644 --- a/compiler-rt/test/ubsan/TestCases/Misc/Linux/sigaction.cpp +++ b/compiler-rt/test/ubsan/TestCases/Misc/Linux/sigaction.cpp @@ -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.