r328255 - [CFG] [analyzer] Add C++17-specific ctor-initializer construction contexts.
Artem Dergachev via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 22 15:02:38 PDT 2018
Author: dergachev
Date: Thu Mar 22 15:02:38 2018
New Revision: 328255
URL: http://llvm.org/viewvc/llvm-project?rev=328255&view=rev
Log:
[CFG] [analyzer] Add C++17-specific ctor-initializer construction contexts.
CXXCtorInitializer-based constructors are also affected by the C++17 mandatory
copy elision, like variable constructors and return value constructors.
Extend r328248 to support those.
Differential Revision: https://reviews.llvm.org/D44763
Modified:
cfe/trunk/include/clang/Analysis/CFG.h
cfe/trunk/include/clang/Analysis/ConstructionContext.h
cfe/trunk/lib/Analysis/CFG.cpp
cfe/trunk/lib/Analysis/ConstructionContext.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
cfe/trunk/test/Analysis/cfg-rich-constructors.cpp
Modified: cfe/trunk/include/clang/Analysis/CFG.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=328255&r1=328254&r2=328255&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/CFG.h (original)
+++ cfe/trunk/include/clang/Analysis/CFG.h Thu Mar 22 15:02:38 2018
@@ -189,8 +189,10 @@ public:
// into the constructor. An assertion would require passing an ASTContext
// which would mean paying for something we don't use.
assert(C && (isa<TemporaryObjectConstructionContext>(C) ||
+ // These are possible in C++17 due to mandatory copy elision.
isa<ReturnedValueConstructionContext>(C) ||
- isa<VariableConstructionContext>(C)));
+ isa<VariableConstructionContext>(C) ||
+ isa<ConstructorInitializerConstructionContext>(C)));
Data2.setPointer(const_cast<ConstructionContext *>(C));
}
Modified: cfe/trunk/include/clang/Analysis/ConstructionContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ConstructionContext.h?rev=328255&r1=328254&r2=328255&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/ConstructionContext.h (original)
+++ cfe/trunk/include/clang/Analysis/ConstructionContext.h Thu Mar 22 15:02:38 2018
@@ -102,7 +102,10 @@ public:
CXX17ElidedCopyVariableKind,
VARIABLE_BEGIN = SimpleVariableKind,
VARIABLE_END = CXX17ElidedCopyVariableKind,
- ConstructorInitializerKind,
+ SimpleConstructorInitializerKind,
+ CXX17ElidedCopyConstructorInitializerKind,
+ INITIALIZER_BEGIN = SimpleConstructorInitializerKind,
+ INITIALIZER_END = CXX17ElidedCopyConstructorInitializerKind,
NewAllocatedObjectKind,
TemporaryObjectKind,
SimpleReturnedValueKind,
@@ -202,17 +205,15 @@ public:
}
};
-/// Represents construction into a field or a base class within a bigger object
-/// via a constructor initializer, eg. T(): field(123) { ... }.
+// An abstract base class for constructor-initializer-based constructors.
class ConstructorInitializerConstructionContext : public ConstructionContext {
const CXXCtorInitializer *I;
- friend class ConstructionContext; // Allows to create<>() itself.
-
+protected:
explicit ConstructorInitializerConstructionContext(
- const CXXCtorInitializer *I)
- : ConstructionContext(ConstructionContext::ConstructorInitializerKind),
- I(I) {
+ ConstructionContext::Kind K, const CXXCtorInitializer *I)
+ : ConstructionContext(K), I(I) {
+ assert(classof(this));
assert(I);
}
@@ -220,7 +221,57 @@ public:
const CXXCtorInitializer *getCXXCtorInitializer() const { return I; }
static bool classof(const ConstructionContext *CC) {
- return CC->getKind() == ConstructorInitializerKind;
+ return CC->getKind() >= INITIALIZER_BEGIN &&
+ CC->getKind() <= INITIALIZER_END;
+ }
+};
+
+/// Represents construction into a field or a base class within a bigger object
+/// via a constructor initializer, eg. T(): field(123) { ... }.
+class SimpleConstructorInitializerConstructionContext
+ : public ConstructorInitializerConstructionContext {
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit SimpleConstructorInitializerConstructionContext(
+ const CXXCtorInitializer *I)
+ : ConstructorInitializerConstructionContext(
+ ConstructionContext::SimpleConstructorInitializerKind, I) {}
+
+public:
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == SimpleConstructorInitializerKind;
+ }
+};
+
+/// Represents construction into a field or a base class within a bigger object
+/// via a constructor initializer, with a single constructor, eg.
+/// T(): field(Field(123)) { ... }. Such construction context may only appear
+/// in C++17 because previously it was split into a temporary object constructor
+/// and an elidable simple constructor-initializer copy-constructor and we were
+/// producing separate construction contexts for these constructors. In C++17
+/// we have a single construction context that combines both. Note that if the
+/// object has trivial destructor, then this code is indistinguishable from
+/// a simple constructor-initializer constructor on the AST level; in this case
+/// we provide a simple constructor-initializer construction context.
+class CXX17ElidedCopyConstructorInitializerConstructionContext
+ : public ConstructorInitializerConstructionContext {
+ const CXXBindTemporaryExpr *BTE;
+
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit CXX17ElidedCopyConstructorInitializerConstructionContext(
+ const CXXCtorInitializer *I, const CXXBindTemporaryExpr *BTE)
+ : ConstructorInitializerConstructionContext(
+ CXX17ElidedCopyConstructorInitializerKind, I),
+ BTE(BTE) {
+ assert(BTE);
+ }
+
+public:
+ const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == CXX17ElidedCopyConstructorInitializerKind;
}
};
Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=328255&r1=328254&r2=328255&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Thu Mar 22 15:02:38 2018
@@ -4911,10 +4911,18 @@ static void print_construction_context(r
const ConstructionContext *CC) {
const Stmt *S1 = nullptr, *S2 = nullptr;
switch (CC->getKind()) {
- case ConstructionContext::ConstructorInitializerKind: {
+ case ConstructionContext::SimpleConstructorInitializerKind: {
OS << ", ";
- const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
- print_initializer(OS, Helper, ICC->getCXXCtorInitializer());
+ const auto *SICC = cast<SimpleConstructorInitializerConstructionContext>(CC);
+ print_initializer(OS, Helper, SICC->getCXXCtorInitializer());
+ break;
+ }
+ case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind: {
+ OS << ", ";
+ const auto *CICC =
+ cast<CXX17ElidedCopyConstructorInitializerConstructionContext>(CC);
+ print_initializer(OS, Helper, CICC->getCXXCtorInitializer());
+ S2 = CICC->getCXXBindTemporaryExpr();
break;
}
case ConstructionContext::SimpleVariableKind: {
Modified: cfe/trunk/lib/Analysis/ConstructionContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ConstructionContext.cpp?rev=328255&r1=328254&r2=328255&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ConstructionContext.cpp (original)
+++ cfe/trunk/lib/Analysis/ConstructionContext.cpp Thu Mar 22 15:02:38 2018
@@ -62,21 +62,31 @@ const ConstructionContext *ConstructionC
// lifetime extension on the parent layer.
if (const ConstructionContextLayer *ParentLayer = TopLayer->getParent()) {
assert(ParentLayer->isLast());
+ // C++17 *requires* elision of the constructor at the return site
+ // and at variable/member initialization site, while previous standards
+ // were allowing an optional elidable constructor.
+ // This is the C++17 copy-elided construction into a ctor initializer.
+ if (const CXXCtorInitializer *I = ParentLayer->getTriggerInit()) {
+ return create<
+ CXX17ElidedCopyConstructorInitializerConstructionContext>(C,
+ I, BTE);
+ }
+ assert(ParentLayer->getTriggerStmt() &&
+ "Non-statement-based layers have been handled above!");
+ // This is the normal, non-C++17 case: a temporary object which has
+ // both destruction and materialization info attached to it in the AST.
if ((MTE = dyn_cast<MaterializeTemporaryExpr>(
ParentLayer->getTriggerStmt()))) {
- // A temporary object which has both destruction and
- // materialization info.
return create<TemporaryObjectConstructionContext>(C, BTE, MTE);
}
- // C++17 *requires* elision of the constructor at the return site
- // and at variable initialization site, while previous standards
- // were allowing an optional elidable constructor.
+ // This is C++17 copy-elided construction into return statement.
if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) {
assert(!RS->getRetValue()->getType().getCanonicalType()
->getAsCXXRecordDecl()->hasTrivialDestructor());
return create<CXX17ElidedCopyReturnedValueConstructionContext>(C,
RS, BTE);
}
+ // This is C++17 copy-elided construction into a simple variable.
if (auto *DS = dyn_cast<DeclStmt>(ParentLayer->getTriggerStmt())) {
assert(!cast<VarDecl>(DS->getSingleDecl())->getType()
.getCanonicalType()->getAsCXXRecordDecl()
@@ -104,7 +114,7 @@ const ConstructionContext *ConstructionC
llvm_unreachable("Unexpected construction context with statement!");
} else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) {
assert(TopLayer->isLast());
- return create<ConstructorInitializerConstructionContext>(C, I);
+ return create<SimpleConstructorInitializerConstructionContext>(C, I);
}
llvm_unreachable("Unexpected construction context!");
}
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=328255&r1=328254&r2=328255&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Thu Mar 22 15:02:38 2018
@@ -134,7 +134,7 @@ ExprEngine::getRegionForConstructedObjec
makeZeroElementRegion(State, LValue, Ty, CallOpts.IsArrayCtorOrDtor);
return LValue.getAsRegion();
}
- case ConstructionContext::ConstructorInitializerKind: {
+ case ConstructionContext::SimpleConstructorInitializerKind: {
const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
const auto *Init = ICC->getCXXCtorInitializer();
assert(Init->isAnyMemberInitializer());
@@ -217,6 +217,7 @@ ExprEngine::getRegionForConstructedObjec
}
case ConstructionContext::CXX17ElidedCopyVariableKind:
case ConstructionContext::CXX17ElidedCopyReturnedValueKind:
+ case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind:
// Not implemented yet.
break;
}
Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=328255&r1=328254&r2=328255&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original)
+++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Thu Mar 22 15:02:38 2018
@@ -252,6 +252,34 @@ public:
D(double): C(C::get()), c1(new C(C::get())) {}
};
+// Let's see if initializers work well for fields with destructors.
+class E {
+public:
+ static E get();
+ ~E();
+};
+
+class F {
+ E e;
+
+public:
+// FIXME: There should be no temporary destructor in C++17.
+// CHECK: F()
+// CHECK: 1: E::get
+// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class ctor_initializers::E (*)(
+// CXX11-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6])
+// CXX11-NEXT: 4: [B1.3] (BindTemporary)
+// CXX11-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class ctor_initializers::E)
+// CXX11-NEXT: 6: [B1.5]
+// CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, e([B1.6]) (Member initializer), class ctor_initializers
+// CXX11-NEXT: 8: e([B1.7]) (Member initializer)
+// CXX11-NEXT: 9: ~ctor_initializers::E() (Temporary object destructor)
+// CXX17-NEXT: 3: [B1.2]() (CXXRecordTypedCall, e([B1.4]) (Member initializer), [B1.4])
+// CXX17-NEXT: 4: [B1.3] (BindTemporary)
+// CXX17-NEXT: 5: e([B1.4]) (Member initializer)
+// CXX17-NEXT: 6: ~ctor_initializers::E() (Temporary object destructor)
+ F(): e(E::get()) {}
+};
} // end namespace ctor_initializers
namespace return_stmt_without_dtor {
More information about the cfe-commits
mailing list