Skip to content

Commit ac27228

Browse files
committed
Revert "Diagnose problematic uses of constructor/destructor attribute (#67673)"
This reverts commit 27ecb63. Still fails compiler-rt: https://lab.llvm.org/buildbot/#/builders/109/builds/75364
1 parent 27ecb63 commit ac27228

File tree

15 files changed

+91
-260
lines changed

15 files changed

+91
-260
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,6 @@ Attribute Changes in Clang
217217
automatic diagnostic to use parameters of types that the format style
218218
supports but that are never the result of default argument promotion, such as
219219
``float``. (`#59824: <https://github.com/llvm/llvm-project/issues/59824>`_)
220-
- The ``constructor`` and ``destructor`` attributes now diagnose when:
221-
- the priority is not between 101 and 65535, inclusive,
222-
- the function it is applied to accepts arguments or has a non-void return
223-
type, or
224-
- the function it is applied to is a non-static member function (C++).
225220

226221
Improvements to Clang's diagnostics
227222
-----------------------------------

clang/include/clang/Basic/AttrDocs.td

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7255,14 +7255,8 @@ after returning from ``main()`` or when the ``exit()`` function has been
72557255
called. Note, ``quick_exit()``, ``_Exit()``, and ``abort()`` prevent a function
72567256
marked ``destructor`` from being called.
72577257

7258-
In general, the constructor or destructor function must use the C calling
7259-
convention, cannot accept any arguments, and its return type should be
7260-
``void``, ``int``, or ``unsigned int``. The latter two types are supported for
7261-
historical reasons. On targets with a GNU environment (one which uses glibc),
7262-
the signature of the function can also be the same as that of ``main()``.
7263-
7264-
In C++ language modes, the function cannot be marked ``consteval``, nor can it
7265-
be a non-static member function.
7258+
The constructor or destructor function should not accept any arguments and its
7259+
return type should be ``void``.
72667260

72677261
The attributes accept an optional argument used to specify the priority order
72687262
in which to execute constructor and destructor functions. The priority is

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,6 @@ def EnumConversion : DiagGroup<"enum-conversion",
105105
[EnumEnumConversion,
106106
EnumFloatConversion,
107107
EnumCompareConditional]>;
108-
def InvalidPriority : DiagGroup<"priority-ctor-dtor">;
109-
// For compatibility with GCC.
110-
def : DiagGroup<"prio-ctor-dtor", [InvalidPriority]>;
111-
112108
def ObjCSignedCharBoolImplicitIntConversion :
113109
DiagGroup<"objc-signed-char-bool-implicit-int-conversion">;
114110
def ImplicitIntConversion : DiagGroup<"implicit-int-conversion",

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2870,8 +2870,6 @@ def warn_cxx11_compat_constexpr_body_multiple_return : Warning<
28702870
InGroup<CXXPre14Compat>, DefaultIgnore;
28712871
def note_constexpr_body_previous_return : Note<
28722872
"previous return statement is here">;
2873-
def err_ctordtor_attr_consteval : Error<
2874-
"%0 attribute cannot be applied to a 'consteval' function">;
28752873

28762874
// C++20 function try blocks in constexpr
28772875
def ext_constexpr_function_try_block_cxx20 : ExtWarn<
@@ -3184,13 +3182,6 @@ def err_alignas_underaligned : Error<
31843182
"requested alignment is less than minimum alignment of %1 for type %0">;
31853183
def warn_aligned_attr_underaligned : Warning<err_alignas_underaligned.Summary>,
31863184
InGroup<IgnoredAttributes>;
3187-
def err_ctor_dtor_attr_on_non_void_func : Error<
3188-
"%0 attribute can only be applied to a function which accepts no arguments "
3189-
"and has a 'void' or 'int' return type">;
3190-
def err_ctor_dtor_member_func : Error<
3191-
"%0 attribute cannot be applied to a member function">;
3192-
def err_ctor_dtor_calling_conv : Error<
3193-
"%0 attribute must be applied to a function with the C calling convention">;
31943185
def err_attribute_sizeless_type : Error<
31953186
"%0 attribute cannot be applied to sizeless type %1">;
31963187
def err_attribute_argument_n_type : Error<
@@ -3204,9 +3195,6 @@ def err_attribute_argument_out_of_range : Error<
32043195
def err_init_priority_object_attr : Error<
32053196
"can only use 'init_priority' attribute on file-scope definitions "
32063197
"of objects of class type">;
3207-
def warn_priority_out_of_range : Warning<
3208-
err_attribute_argument_out_of_range.Summary>,
3209-
InGroup<InvalidPriority>, DefaultError;
32103198
def err_attribute_argument_out_of_bounds : Error<
32113199
"%0 attribute parameter %1 is out of bounds">;
32123200
def err_attribute_only_once_per_parameter : Error<

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 24 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,126 +2352,26 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
23522352
D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
23532353
}
23542354

2355-
static void diagnoseInvalidPriority(Sema &S, uint32_t Priority,
2356-
const ParsedAttr &A,
2357-
SourceLocation PriorityLoc) {
2358-
constexpr uint32_t ReservedPriorityLower = 101, ReservedPriorityUpper = 65535;
2359-
2360-
// Only perform the priority check if the attribute is outside of a system
2361-
// header. Values <= 100 are reserved for the implementation, and libc++
2362-
// benefits from being able to specify values in that range. Values > 65535
2363-
// are reserved for historical reasons.
2364-
if ((Priority < ReservedPriorityLower || Priority > ReservedPriorityUpper) &&
2365-
!S.getSourceManager().isInSystemHeader(A.getLoc())) {
2366-
S.Diag(A.getLoc(), diag::warn_priority_out_of_range)
2367-
<< PriorityLoc << A << ReservedPriorityLower << ReservedPriorityUpper;
2368-
}
2369-
}
2370-
2371-
static bool FunctionParamsAreMainLike(ASTContext &Context,
2372-
const FunctionDecl *FD) {
2373-
assert(FD->hasPrototype() && "expected the function to have a prototype");
2374-
const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
2375-
QualType CharPP =
2376-
Context.getPointerType(Context.getPointerType(Context.CharTy));
2377-
QualType Expected[] = {Context.IntTy, CharPP, CharPP, CharPP};
2378-
for (unsigned I = 0;
2379-
I < sizeof(Expected) / sizeof(QualType) && I < FPT->getNumParams();
2380-
++I) {
2381-
QualType AT = FPT->getParamType(I);
2382-
2383-
if (!Context.hasSameUnqualifiedType(AT, Expected[I])) {
2384-
if (Expected[I] == CharPP) {
2385-
// As an extension, the following forms are okay:
2386-
// char const **
2387-
// char const * const *
2388-
// char * const *
2389-
2390-
QualifierCollector Qs;
2391-
const PointerType *PT;
2392-
if ((PT = Qs.strip(AT)->getAs<PointerType>()) &&
2393-
(PT = Qs.strip(PT->getPointeeType())->getAs<PointerType>()) &&
2394-
Context.hasSameType(QualType(Qs.strip(PT->getPointeeType()), 0),
2395-
Context.CharTy)) {
2396-
Qs.removeConst();
2397-
if (!Qs.empty())
2398-
return false;
2399-
continue; // Accepted as an extension.
2400-
}
2401-
}
2402-
return false;
2403-
}
2404-
}
2405-
return true;
2406-
}
2407-
2408-
template <typename CtorDtorAttr>
2409-
static void handleCtorDtorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2410-
uint32_t Priority = CtorDtorAttr::DefaultPriority;
2355+
static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2356+
uint32_t priority = ConstructorAttr::DefaultPriority;
24112357
if (S.getLangOpts().HLSL && AL.getNumArgs()) {
24122358
S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported);
24132359
return;
24142360
}
2361+
if (AL.getNumArgs() &&
2362+
!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
2363+
return;
24152364

2416-
// If we're given an argument for the priority, check that it's valid.
2417-
if (AL.getNumArgs()) {
2418-
if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Priority))
2419-
return;
2420-
2421-
// Diagnose an invalid priority, but continue to process the attribute.
2422-
diagnoseInvalidPriority(S, Priority, AL, AL.getArgAsExpr(0)->getExprLoc());
2423-
}
2365+
D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
2366+
}
24242367

2425-
// Ensure the function we're attaching to is something that is sensible to
2426-
// automatically call before or after main(); it should accept no arguments.
2427-
// In theory, a void return type is the only truly safe return type (consider
2428-
// that calling conventions may place returned values in a hidden pointer
2429-
// argument passed to the function that will not be present when called
2430-
// automatically). However, there is a significant amount of existing code
2431-
// which uses an int return type. So we will accept void, int, and
2432-
// unsigned int return types. Any other return type, or a non-void parameter
2433-
// list is treated as an error because it's a form of type system
2434-
// incompatibility. The function also cannot be a member function. We allow
2435-
// K&R C functions because that's a difficult edge case where it depends on
2436-
// how the function is defined as to whether it does or does not expect
2437-
// arguments.
2438-
//
2439-
// However! glibc on ELF will pass the same arguments to a constructor
2440-
// function as are given to main(), so we will allow `int, char *[]` and
2441-
// `int, char *[], char *[]` (or qualified versions thereof), but only if
2442-
// the target is explicitly for glibc.
2443-
const auto *FD = cast<FunctionDecl>(D);
2444-
QualType RetTy = FD->getReturnType();
2445-
bool IsGlibC = S.Context.getTargetInfo().getTriple().isGNUEnvironment();
2446-
if (!(RetTy->isVoidType() ||
2447-
RetTy->isSpecificBuiltinType(BuiltinType::UInt) ||
2448-
RetTy->isSpecificBuiltinType(BuiltinType::Int)) ||
2449-
FD->isVariadic() ||
2450-
(FD->hasPrototype() &&
2451-
((!IsGlibC && FD->getNumParams() != 0) ||
2452-
(IsGlibC && !FunctionParamsAreMainLike(S.Context, FD))))) {
2453-
S.Diag(AL.getLoc(), diag::err_ctor_dtor_attr_on_non_void_func)
2454-
<< AL << FD->getSourceRange();
2455-
return;
2456-
}
2457-
if (FD->getType()->castAs<FunctionType>()->getCallConv() !=
2458-
CallingConv::CC_C) {
2459-
S.Diag(AL.getLoc(), diag::err_ctor_dtor_calling_conv)
2460-
<< AL << FD->getSourceRange();
2461-
return;
2462-
}
2463-
if (const auto *MD = dyn_cast<CXXMethodDecl>(FD); MD && MD->isInstance()) {
2464-
S.Diag(AL.getLoc(), diag::err_ctor_dtor_member_func)
2465-
<< AL << FD->getSourceRange();
2466-
return;
2467-
}
2468-
if (FD->isConsteval()) {
2469-
S.Diag(AL.getLoc(), diag::err_ctordtor_attr_consteval)
2470-
<< AL << FD->getSourceRange();
2368+
static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2369+
uint32_t priority = DestructorAttr::DefaultPriority;
2370+
if (AL.getNumArgs() &&
2371+
!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
24712372
return;
2472-
}
24732373

2474-
D->addAttr(CtorDtorAttr::Create(S.Context, Priority, AL));
2374+
D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
24752375
}
24762376

24772377
template <typename AttrTy>
@@ -3988,9 +3888,16 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
39883888
return;
39893889
}
39903890

3991-
// Diagnose an invalid priority, but continue to process the attribute.
3992-
diagnoseInvalidPriority(S, prioritynum, AL, E->getExprLoc());
3993-
3891+
// Only perform the priority check if the attribute is outside of a system
3892+
// header. Values <= 100 are reserved for the implementation, and libc++
3893+
// benefits from being able to specify values in that range.
3894+
if ((prioritynum < 101 || prioritynum > 65535) &&
3895+
!S.getSourceManager().isInSystemHeader(AL.getLoc())) {
3896+
S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range)
3897+
<< E->getSourceRange() << AL << 101 << 65535;
3898+
AL.setInvalid();
3899+
return;
3900+
}
39943901
D->addAttr(::new (S.Context) InitPriorityAttr(S.Context, AL, prioritynum));
39953902
}
39963903

@@ -9052,13 +8959,13 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
90528959
handlePassObjectSizeAttr(S, D, AL);
90538960
break;
90548961
case ParsedAttr::AT_Constructor:
9055-
handleCtorDtorAttr<ConstructorAttr>(S, D, AL);
8962+
handleConstructorAttr(S, D, AL);
90568963
break;
90578964
case ParsedAttr::AT_Deprecated:
90588965
handleDeprecatedAttr(S, D, AL);
90598966
break;
90608967
case ParsedAttr::AT_Destructor:
9061-
handleCtorDtorAttr<DestructorAttr>(S, D, AL);
8968+
handleDestructorAttr(S, D, AL);
90628969
break;
90638970
case ParsedAttr::AT_EnableIf:
90648971
handleEnableIfAttr(S, D, AL);

clang/test/CodeGen/PowerPC/aix-destructor-attribute.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
// RUN: -fno-use-cxa-atexit -fregister-global-dtors-with-atexit < %s | \
1313
// RUN: FileCheck --check-prefix=REGISTER %s
1414

15-
int bar(void) __attribute__((destructor(101)));
15+
int bar(void) __attribute__((destructor(100)));
1616
int bar2(void) __attribute__((destructor(65535)));
17+
int bar3(int) __attribute__((destructor(65535)));
1718

1819
int bar(void) {
1920
return 1;
@@ -23,12 +24,16 @@ int bar2(void) {
2324
return 2;
2425
}
2526

26-
// 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 }]
27+
int bar3(int a) {
28+
return a;
29+
}
30+
31+
// 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 }]
2732

28-
// 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 }]
29-
// 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 }]
33+
// 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 }]
34+
// 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 }]
3035

31-
// REGISTER: define internal void @__GLOBAL_init_101() [[ATTR:#[0-9]+]] {
36+
// REGISTER: define internal void @__GLOBAL_init_100() [[ATTR:#[0-9]+]] {
3237
// REGISTER: entry:
3338
// REGISTER: %0 = call i32 @atexit(ptr @bar)
3439
// REGISTER: ret void
@@ -37,10 +42,11 @@ int bar2(void) {
3742
// REGISTER: define internal void @__GLOBAL_init_65535() [[ATTR:#[0-9]+]] {
3843
// REGISTER: entry:
3944
// REGISTER: %0 = call i32 @atexit(ptr @bar2)
45+
// REGISTER: %1 = call i32 @atexit(ptr @bar3)
4046
// REGISTER: ret void
4147
// REGISTER: }
4248

43-
// REGISTER: define internal void @__GLOBAL_cleanup_101() [[ATTR:#[0-9]+]] {
49+
// REGISTER: define internal void @__GLOBAL_cleanup_100() [[ATTR:#[0-9]+]] {
4450
// REGISTER: entry:
4551
// REGISTER: %0 = call i32 @unatexit(ptr @bar)
4652
// REGISTER: %needs_destruct = icmp eq i32 %0, 0
@@ -56,11 +62,20 @@ int bar2(void) {
5662

5763
// REGISTER: define internal void @__GLOBAL_cleanup_65535() [[ATTR:#[0-9]+]] {
5864
// REGISTER: entry:
59-
// REGISTER: %0 = call i32 @unatexit(ptr @bar2)
65+
// REGISTER: %0 = call i32 @unatexit(ptr @bar3)
6066
// REGISTER: %needs_destruct = icmp eq i32 %0, 0
61-
// REGISTER: br i1 %needs_destruct, label %destruct.call, label %destruct.end
67+
// REGISTER: br i1 %needs_destruct, label %destruct.call, label %unatexit.call
6268

6369
// REGISTER: destruct.call:
70+
// REGISTER: call void @bar3()
71+
// REGISTER: br label %unatexit.call
72+
73+
// REGISTER: unatexit.call:
74+
// REGISTER: %1 = call i32 @unatexit(ptr @bar2)
75+
// REGISTER: %needs_destruct1 = icmp eq i32 %1, 0
76+
// REGISTER: br i1 %needs_destruct1, label %destruct.call2, label %destruct.end
77+
78+
// REGISTER: destruct.call2:
6479
// REGISTER: call void @bar2()
6580
// REGISTER: br label %destruct.end
6681

clang/test/CodeGenCXX/aix-destructor-attribute.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ struct test {
1717
~test();
1818
} t;
1919

20-
int bar() __attribute__((destructor(101)));
20+
int bar() __attribute__((destructor(100)));
2121
int bar2() __attribute__((destructor(65535)));
22+
int bar3(int) __attribute__((destructor(65535)));
2223

2324
int bar() {
2425
return 1;
@@ -28,13 +29,17 @@ int bar2() {
2829
return 2;
2930
}
3031

32+
int bar3(int a) {
33+
return a;
34+
}
35+
3136
// NO-REGISTER: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I__, ptr null }]
32-
// 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 }]
37+
// 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 }]
3338

34-
// 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 }]
35-
// 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 }]
39+
// 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 }]
40+
// 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 }]
3641

37-
// REGISTER: define internal void @__GLOBAL_init_101() [[ATTR:#[0-9]+]] {
42+
// REGISTER: define internal void @__GLOBAL_init_100() [[ATTR:#[0-9]+]] {
3843
// REGISTER: entry:
3944
// REGISTER: %0 = call i32 @atexit(ptr @_Z3barv)
4045
// REGISTER: ret void
@@ -43,10 +48,11 @@ int bar2() {
4348
// REGISTER: define internal void @__GLOBAL_init_65535() [[ATTR:#[0-9]+]] {
4449
// REGISTER: entry:
4550
// REGISTER: %0 = call i32 @atexit(ptr @_Z4bar2v)
51+
// REGISTER: %1 = call i32 @atexit(ptr @_Z4bar3i)
4652
// REGISTER: ret void
4753
// REGISTER: }
4854

49-
// REGISTER: define internal void @__GLOBAL_cleanup_101() [[ATTR:#[0-9]+]] {
55+
// REGISTER: define internal void @__GLOBAL_cleanup_100() [[ATTR:#[0-9]+]] {
5056
// REGISTER: entry:
5157
// REGISTER: %0 = call i32 @unatexit(ptr @_Z3barv)
5258
// REGISTER: %needs_destruct = icmp eq i32 %0, 0
@@ -62,11 +68,20 @@ int bar2() {
6268

6369
// REGISTER: define internal void @__GLOBAL_cleanup_65535() [[ATTR:#[0-9]+]] {
6470
// REGISTER: entry:
65-
// REGISTER: %0 = call i32 @unatexit(ptr @_Z4bar2v)
71+
// REGISTER: %0 = call i32 @unatexit(ptr @_Z4bar3i)
6672
// REGISTER: %needs_destruct = icmp eq i32 %0, 0
67-
// REGISTER: br i1 %needs_destruct, label %destruct.call, label %destruct.end
73+
// REGISTER: br i1 %needs_destruct, label %destruct.call, label %unatexit.call
6874

6975
// REGISTER: destruct.call:
76+
// REGISTER: call void @_Z4bar3i()
77+
// REGISTER: br label %unatexit.call
78+
79+
// REGISTER: unatexit.call:
80+
// REGISTER: %1 = call i32 @unatexit(ptr @_Z4bar2v)
81+
// REGISTER: %needs_destruct1 = icmp eq i32 %1, 0
82+
// REGISTER: br i1 %needs_destruct1, label %destruct.call2, label %destruct.end
83+
84+
// REGISTER: destruct.call2:
7085
// REGISTER: call void @_Z4bar2v()
7186
// REGISTER: br label %destruct.end
7287

clang/test/Sema/constructor-attribute-diag-group.c

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)