Skip to content

Commit 40568fe

Browse files
committed
[CodeGen] Emit destructor calls to destruct compound literals
Fix a bug in IRGen where it wasn't destructing compound literals in C that are ObjC pointer arrays or non-trivial structs. Also diagnose jumps that enter or exit the lifetime of the compound literals. rdar://problem/51867864 Differential Revision: https://reviews.llvm.org/D64464
1 parent ddfcda0 commit 40568fe

27 files changed

+460
-28
lines changed

clang/include/clang/AST/ASTImporter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "clang/AST/DeclBase.h"
1818
#include "clang/AST/DeclarationName.h"
19+
#include "clang/AST/ExprCXX.h"
1920
#include "clang/AST/NestedNameSpecifier.h"
2021
#include "clang/AST/TemplateName.h"
2122
#include "clang/AST/Type.h"
@@ -349,6 +350,10 @@ class TypeSourceInfo;
349350
return ToOrErr.takeError();
350351
}
351352

353+
/// Import cleanup objects owned by ExprWithCleanup.
354+
llvm::Expected<ExprWithCleanups::CleanupObject>
355+
Import(ExprWithCleanups::CleanupObject From);
356+
352357
/// Import the given type from the "from" context into the "to"
353358
/// context. A null type is imported as a null type (no error).
354359
///

clang/include/clang/AST/ExprCXX.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3321,13 +3321,15 @@ class DependentScopeDeclRefExpr final
33213321
/// literal is the extent of the enclosing scope.
33223322
class ExprWithCleanups final
33233323
: public FullExpr,
3324-
private llvm::TrailingObjects<ExprWithCleanups, BlockDecl *> {
3324+
private llvm::TrailingObjects<
3325+
ExprWithCleanups,
3326+
llvm::PointerUnion<BlockDecl *, CompoundLiteralExpr *>> {
33253327
public:
33263328
/// The type of objects that are kept in the cleanup.
3327-
/// It's useful to remember the set of blocks; we could also
3328-
/// remember the set of temporaries, but there's currently
3329-
/// no need.
3330-
using CleanupObject = BlockDecl *;
3329+
/// It's useful to remember the set of blocks and block-scoped compound
3330+
/// literals; we could also remember the set of temporaries, but there's
3331+
/// currently no need.
3332+
using CleanupObject = llvm::PointerUnion<BlockDecl *, CompoundLiteralExpr *>;
33313333

33323334
private:
33333335
friend class ASTStmtReader;

clang/include/clang/AST/TextNodeDumper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ class TextNodeDumper
184184
void dumpBareDeclRef(const Decl *D);
185185
void dumpName(const NamedDecl *ND);
186186
void dumpAccessSpecifier(AccessSpecifier AS);
187+
void dumpCleanupObject(const ExprWithCleanups::CleanupObject &C);
187188

188189
void dumpDeclRef(const Decl *D, StringRef Label = {});
189190

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5543,6 +5543,8 @@ def note_enters_block_captures_weak : Note<
55435543
def note_enters_block_captures_non_trivial_c_struct : Note<
55445544
"jump enters lifetime of block which captures a C struct that is non-trivial "
55455545
"to destroy">;
5546+
def note_enters_compound_literal_scope : Note<
5547+
"jump enters lifetime of a compound literal that is non-trivial to destruct">;
55465548

55475549
def note_exits_cleanup : Note<
55485550
"jump exits scope of variable with __attribute__((cleanup))">;
@@ -5586,6 +5588,8 @@ def note_exits_block_captures_weak : Note<
55865588
def note_exits_block_captures_non_trivial_c_struct : Note<
55875589
"jump exits lifetime of block which captures a C struct that is non-trivial "
55885590
"to destroy">;
5591+
def note_exits_compound_literal_scope : Note<
5592+
"jump exits lifetime of a compound literal that is non-trivial to destruct">;
55895593

55905594
def err_func_returning_qualified_void : ExtWarn<
55915595
"function cannot return qualified void type %0">,

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -613,9 +613,8 @@ class Sema final {
613613
CleanupInfo Cleanup;
614614

615615
/// ExprCleanupObjects - This is the stack of objects requiring
616-
/// cleanup that are created by the current full expression. The
617-
/// element type here is ExprWithCleanups::Object.
618-
SmallVector<BlockDecl*, 8> ExprCleanupObjects;
616+
/// cleanup that are created by the current full expression.
617+
SmallVector<ExprWithCleanups::CleanupObject, 8> ExprCleanupObjects;
619618

620619
/// Store a set of either DeclRefExprs or MemberExprs that contain a reference
621620
/// to a variable (constant) that may or may not be odr-used in this Expr, and

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,9 @@ namespace serialization {
19001900
CTOR_INITIALIZER_INDIRECT_MEMBER
19011901
};
19021902

1903+
/// Kinds of cleanup objects owned by ExprWithCleanups.
1904+
enum CleanupObjectKind { COK_Block, COK_CompoundLiteral };
1905+
19031906
/// Describes the redeclarations of a declaration.
19041907
struct LocalRedeclarationsInfo {
19051908
// The ID of the first declaration

clang/lib/AST/ASTImporter.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7910,6 +7910,18 @@ void ASTImporter::RegisterImportedDecl(Decl *FromD, Decl *ToD) {
79107910
MapImported(FromD, ToD);
79117911
}
79127912

7913+
llvm::Expected<ExprWithCleanups::CleanupObject>
7914+
ASTImporter::Import(ExprWithCleanups::CleanupObject From) {
7915+
if (auto *CLE = From.dyn_cast<CompoundLiteralExpr *>()) {
7916+
if (Expected<Expr *> R = Import(CLE))
7917+
return ExprWithCleanups::CleanupObject(cast<CompoundLiteralExpr>(*R));
7918+
}
7919+
7920+
// FIXME: Handle BlockDecl when we implement importing BlockExpr in
7921+
// ASTNodeImporter.
7922+
return make_error<ImportError>(ImportError::UnsupportedConstruct);
7923+
}
7924+
79137925
Expected<QualType> ASTImporter::Import(QualType FromT) {
79147926
if (FromT.isNull())
79157927
return QualType{};

clang/lib/AST/JSONNodeDumper.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,16 @@ void JSONNodeDumper::VisitExprWithCleanups(const ExprWithCleanups *EWC) {
13341334
if (EWC->getNumObjects()) {
13351335
JOS.attributeArray("cleanups", [this, EWC] {
13361336
for (const ExprWithCleanups::CleanupObject &CO : EWC->getObjects())
1337-
JOS.value(createBareDeclRef(CO));
1337+
if (auto *BD = CO.dyn_cast<BlockDecl *>()) {
1338+
JOS.value(createBareDeclRef(BD));
1339+
} else if (auto *CLE = CO.dyn_cast<CompoundLiteralExpr *>()) {
1340+
llvm::json::Object Obj;
1341+
Obj["id"] = createPointerRepresentation(CLE);
1342+
Obj["kind"] = CLE->getStmtClassName();
1343+
JOS.value(std::move(Obj));
1344+
} else {
1345+
llvm_unreachable("unexpected cleanup object type");
1346+
}
13381347
});
13391348
}
13401349
}

clang/lib/AST/TextNodeDumper.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,23 @@ void TextNodeDumper::dumpAccessSpecifier(AccessSpecifier AS) {
448448
}
449449
}
450450

451+
void TextNodeDumper::dumpCleanupObject(
452+
const ExprWithCleanups::CleanupObject &C) {
453+
if (auto *BD = C.dyn_cast<BlockDecl *>())
454+
dumpDeclRef(BD, "cleanup");
455+
else if (auto *CLE = C.dyn_cast<CompoundLiteralExpr *>())
456+
AddChild([=] {
457+
OS << "cleanup ";
458+
{
459+
ColorScope Color(OS, ShowColors, StmtColor);
460+
OS << CLE->getStmtClassName();
461+
}
462+
dumpPointer(CLE);
463+
});
464+
else
465+
llvm_unreachable("unexpected cleanup type");
466+
}
467+
451468
void TextNodeDumper::dumpDeclRef(const Decl *D, StringRef Label) {
452469
if (!D)
453470
return;
@@ -950,7 +967,7 @@ void TextNodeDumper::VisitMaterializeTemporaryExpr(
950967

951968
void TextNodeDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) {
952969
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
953-
dumpDeclRef(Node->getObject(i), "cleanup");
970+
dumpCleanupObject(Node->getObject(i));
954971
}
955972

956973
void TextNodeDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *Node) {

clang/lib/CodeGen/CGBlocks.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -860,13 +860,13 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) {
860860
}
861861

862862
/// Enter a full-expression with a non-trivial number of objects to
863-
/// clean up. This is in this file because, at the moment, the only
864-
/// kind of cleanup object is a BlockDecl*.
863+
/// clean up.
865864
void CodeGenFunction::enterNonTrivialFullExpression(const FullExpr *E) {
866865
if (const auto EWC = dyn_cast<ExprWithCleanups>(E)) {
867866
assert(EWC->getNumObjects() != 0);
868867
for (const ExprWithCleanups::CleanupObject &C : EWC->getObjects())
869-
enterBlockScope(*this, C);
868+
if (auto *BD = C.dyn_cast<BlockDecl *>())
869+
enterBlockScope(*this, BD);
870870
}
871871
}
872872

0 commit comments

Comments
 (0)