Skip to content

Commit 533e475

Browse files
committed
[Sema] do not destruct fields of unions
The C++ standard prohibits this implicit destructor call, leading to incorrect reports from clang-analyzer. This causes projects that use std::option (including llvm) to fail the cplusplus.NewDelete test incorrectly when run through the analyzer. Fixes #119415
1 parent cb04bc0 commit 533e475

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

clang/lib/Analysis/CFG.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,6 +2041,8 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
20412041
}
20422042

20432043
// First destroy member objects.
2044+
if (RD->isUnion())
2045+
return;
20442046
for (auto *FI : RD->fields()) {
20452047
// Check for constant size array. Set type to array element type.
20462048
QualType QT = FI->getType();

clang/test/Analysis/NewDelete-checker-test.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,3 +441,31 @@ void testLeakBecauseNTTPIsNotDeallocation() {
441441
void* p = ::operator new(10);
442442
deallocate_via_nttp<not_free>(p);
443443
} // leak-warning{{Potential leak of memory pointed to by 'p'}}
444+
445+
namespace optional_union {
446+
template <typename T>
447+
class unique_ptr {
448+
T *q;
449+
public:
450+
unique_ptr() : q(new T) {}
451+
~unique_ptr() {
452+
delete q;
453+
}
454+
};
455+
456+
union custom_union_t {
457+
unique_ptr<int> present;
458+
char notpresent;
459+
custom_union_t() : present(unique_ptr<int>()) {}
460+
~custom_union_t() {};
461+
};
462+
463+
void testUnionCorrect() {
464+
custom_union_t a;
465+
a.present.~unique_ptr<int>();
466+
}
467+
468+
void testUnionLeak() {
469+
custom_union_t a;
470+
} // leak-warning{{Potential leak of memory pointed to by 'a.present.q'}}
471+
}

clang/test/Analysis/dtor-array.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,3 +377,27 @@ void directUnknownSymbol() {
377377
}
378378

379379
}
380+
381+
void testUnionDtor() {
382+
static int unionDtorCalled;
383+
InlineDtor::cnt = 0;
384+
InlineDtor::dtorCalled = 0;
385+
unionDtorCalled = 0;
386+
{
387+
union UnionDtor {
388+
InlineDtor kind1;
389+
char kind2;
390+
~UnionDtor() { unionDtorCalled++; }
391+
};
392+
UnionDtor u1{.kind1{}};
393+
UnionDtor u2{.kind2{}};
394+
auto u3 = new UnionDtor{.kind1{}};
395+
auto u4 = new UnionDtor{.kind2{}};
396+
delete u3;
397+
delete u4;
398+
}
399+
400+
clang_analyzer_eval(unionDtorCalled == 4); // expected-warning {{TRUE}}
401+
clang_analyzer_eval(InlineDtor::dtorCalled != 4); // expected-warning {{TRUE}}
402+
clang_analyzer_eval(InlineDtor::dtorCalled == 0); // expected-warning {{TRUE}}
403+
}

0 commit comments

Comments
 (0)