[PATCH] D44238: [CFG] Fix automatic destructors when a member is bound to a reference.
Artem Dergachev via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 7 17:25:29 PST 2018
NoQ created this revision.
NoQ added reviewers: rsmith, doug.gregor, dcoughlin, xazax.hun, a.sidorin, george.karpenkov, szepet.
Herald added subscribers: cfe-commits, rnkovacs.
In code like
const int &x = A().x;
the destructor for `A()` was not present in the CFG due to two problems in the pattern-matching in `getReferenceInitTemporaryType()`:
1. The no-op cast from `T` to `const T` is not necessarily performed on a record type. It may be performed on essentially any type. In the current example, it is performed on an xvalue of type `int` in order to turn it into a `const int`.
2. Since https://reviews.llvm.org/rC288563 member access is no longer performed over rvalues, but goes after the `MaterializeTemporaryExpr` instead.
**This is not an analyzer-specific change.** It may add/remove compiler warnings, but i don't think it makes any sense to hide this behind an analyzer-specific flag.
Repository:
rC Clang
https://reviews.llvm.org/D44238
Files:
lib/Analysis/CFG.cpp
test/Analysis/auto-obj-dtors-cfg-output.cpp
Index: test/Analysis/auto-obj-dtors-cfg-output.cpp
===================================================================
--- test/Analysis/auto-obj-dtors-cfg-output.cpp
+++ test/Analysis/auto-obj-dtors-cfg-output.cpp
@@ -14,6 +14,8 @@
class A {
public:
+ int x;
+
// CHECK: [B1 (ENTRY)]
// CHECK-NEXT: Succs (1): B0
// CHECK: [B0 (EXIT)]
@@ -67,6 +69,25 @@
const A& c = A();
}
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// WARNINGS-NEXT: 1: A() (CXXConstructExpr, class A)
+// ANALYZER-NEXT: 1: A() (CXXConstructExpr, [B1.2], [B1.3], class A)
+// CHECK-NEXT: 2: [B1.1] (BindTemporary)
+// CHECK-NEXT: 3: [B1.2]
+// CHECK-NEXT: 4: [B1.3].x
+// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const int)
+// CHECK-NEXT: 6: const int &x = A().x;
+// CHECK-NEXT: 7: [B1.6].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_const_ref_to_field() {
+ const int &x = A().x;
+}
+
// CHECK: [B2 (ENTRY)]
// CHECK-NEXT: Succs (1): B1
// CHECK: [B1]
Index: lib/Analysis/CFG.cpp
===================================================================
--- lib/Analysis/CFG.cpp
+++ lib/Analysis/CFG.cpp
@@ -1458,16 +1458,15 @@
if (const CastExpr *CE = dyn_cast<CastExpr>(Init)) {
if ((CE->getCastKind() == CK_DerivedToBase ||
CE->getCastKind() == CK_UncheckedDerivedToBase ||
- CE->getCastKind() == CK_NoOp) &&
- Init->getType()->isRecordType()) {
+ CE->getCastKind() == CK_NoOp)) {
Init = CE->getSubExpr();
continue;
}
}
- // Skip member accesses into rvalues.
+ // Skip member accesses.
if (const MemberExpr *ME = dyn_cast<MemberExpr>(Init)) {
- if (!ME->isArrow() && ME->getBase()->isRValue()) {
+ if (!ME->isArrow()) {
Init = ME->getBase();
continue;
}
@@ -4873,10 +4872,12 @@
const VarDecl *VD = DE->getVarDecl();
Helper.handleDecl(VD, OS);
- const Type* T = VD->getType().getTypePtr();
- if (const ReferenceType* RT = T->getAs<ReferenceType>())
- T = RT->getPointeeType().getTypePtr();
- T = T->getBaseElementTypeUnsafe();
+ ASTContext &ACtx = VD->getASTContext();
+ QualType T = VD->getType();
+ if (T->isReferenceType())
+ T = getReferenceInitTemporaryType(ACtx, VD->getInit(), nullptr);
+ if (const ArrayType *AT = ACtx.getAsArrayType(T))
+ T = ACtx.getBaseElementType(AT);
OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
OS << " (Implicit destructor)\n";
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D44238.137516.patch
Type: text/x-patch
Size: 2664 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180308/910dd50b/attachment.bin>
More information about the cfe-commits
mailing list