summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Analysis/CFG.h32
-rw-r--r--clang/include/clang/Analysis/ConstructionContext.h123
-rw-r--r--clang/lib/Analysis/CFG.cpp27
-rw-r--r--clang/lib/Analysis/ConstructionContext.cpp40
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp6
-rw-r--r--clang/test/Analysis/cfg-rich-constructors.cpp322
6 files changed, 391 insertions, 159 deletions
diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h
index bb66aac3f6d..3f98e6be9cd 100644
--- a/clang/include/clang/Analysis/CFG.h
+++ b/clang/include/clang/Analysis/CFG.h
@@ -17,6 +17,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/Analysis/ConstructionContext.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/GraphTraits.h"
@@ -38,8 +39,6 @@ namespace clang {
class ASTContext;
class BinaryOperator;
class CFG;
-class ConstructionContext;
-class TemporaryObjectConstructionContext;
class CXXBaseSpecifier;
class CXXBindTemporaryExpr;
class CXXCtorInitializer;
@@ -171,14 +170,11 @@ private:
};
/// CFGCXXRecordTypedCall - Represents a function call that returns a C++ object
-/// by value. This, like constructor, requires a construction context, which
-/// will always be that of a temporary object - usually consumed by an elidable
-/// constructor. For such value-typed calls the ReturnedValueConstructionContext
-/// of their return value is naturally complemented by the
-/// TemporaryObjectConstructionContext at the call site (here). In C such
-/// tracking is not necessary because no additional effort is required for
-/// destroying the object or modeling copy elision. Like CFGConstructor, this is
-/// for now only used by the analyzer's CFG.
+/// by value. This, like constructor, requires a construction context in order
+/// to understand the storage of the returned object . In C such tracking is not
+/// necessary because no additional effort is required for destroying the object
+/// or modeling copy elision. Like CFGConstructor, this element is for now only
+/// used by the analyzer's CFG.
class CFGCXXRecordTypedCall : public CFGStmt {
public:
/// Returns true when call expression \p CE needs to be represented
@@ -187,19 +183,19 @@ public:
return CE->getCallReturnType(ACtx).getCanonicalType()->getAsCXXRecordDecl();
}
- explicit CFGCXXRecordTypedCall(CallExpr *CE,
- const TemporaryObjectConstructionContext *C)
+ explicit CFGCXXRecordTypedCall(CallExpr *CE, const ConstructionContext *C)
: CFGStmt(CE, CXXRecordTypedCall) {
// FIXME: This is not protected against squeezing a non-record-typed-call
// into the constructor. An assertion would require passing an ASTContext
// which would mean paying for something we don't use.
- assert(C);
- Data2.setPointer(const_cast<TemporaryObjectConstructionContext *>(C));
+ assert(C && (isa<TemporaryObjectConstructionContext>(C) ||
+ isa<ReturnedValueConstructionContext>(C) ||
+ isa<VariableConstructionContext>(C)));
+ Data2.setPointer(const_cast<ConstructionContext *>(C));
}
- const TemporaryObjectConstructionContext *getConstructionContext() const {
- return static_cast<TemporaryObjectConstructionContext *>(
- Data2.getPointer());
+ const ConstructionContext *getConstructionContext() const {
+ return static_cast<ConstructionContext *>(Data2.getPointer());
}
private:
@@ -881,7 +877,7 @@ public:
}
void appendCXXRecordTypedCall(CallExpr *CE,
- const TemporaryObjectConstructionContext *CC,
+ const ConstructionContext *CC,
BumpVectorContext &C) {
Elements.push_back(CFGCXXRecordTypedCall(CE, CC), C);
}
diff --git a/clang/include/clang/Analysis/ConstructionContext.h b/clang/include/clang/Analysis/ConstructionContext.h
index 770f1c929e8..67657c93f62 100644
--- a/clang/include/clang/Analysis/ConstructionContext.h
+++ b/clang/include/clang/Analysis/ConstructionContext.h
@@ -99,22 +99,26 @@ class ConstructionContext {
public:
enum Kind {
SimpleVariableKind,
+ CXX17ElidedCopyVariableKind,
+ VARIABLE_BEGIN = SimpleVariableKind,
+ VARIABLE_END = CXX17ElidedCopyVariableKind,
ConstructorInitializerKind,
NewAllocatedObjectKind,
TemporaryObjectKind,
- ReturnedValueKind
+ SimpleReturnedValueKind,
+ CXX17ElidedCopyReturnedValueKind,
+ RETURNED_VALUE_BEGIN = SimpleReturnedValueKind,
+ RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind
};
protected:
Kind K;
-protected:
// Do not make public! These need to only be constructed
// via createFromLayers().
explicit ConstructionContext(Kind K) : K(K) {}
public:
-
/// Consume the construction context layer, together with its parent layers,
/// and wrap it up into a complete construction context.
static const ConstructionContext *
@@ -124,23 +128,68 @@ public:
Kind getKind() const { return K; }
};
-/// Represents construction into a simple local variable, eg. T var(123);.
-class SimpleVariableConstructionContext : public ConstructionContext {
+/// An abstract base class for local variable constructors.
+class VariableConstructionContext : public ConstructionContext {
const DeclStmt *DS;
-public:
- explicit SimpleVariableConstructionContext(const DeclStmt *DS)
- : ConstructionContext(ConstructionContext::SimpleVariableKind), DS(DS) {
+protected:
+ VariableConstructionContext(ConstructionContext::Kind K, const DeclStmt *DS)
+ : ConstructionContext(K), DS(DS) {
+ assert(classof(this));
assert(DS);
}
+public:
const DeclStmt *getDeclStmt() const { return DS; }
static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() >= VARIABLE_BEGIN &&
+ CC->getKind() <= VARIABLE_END;
+ }
+};
+
+/// Represents construction into a simple local variable, eg. T var(123);.
+/// If a variable has an initializer, eg. T var = makeT();, then the final
+/// elidable copy-constructor from makeT() into var would also be a simple
+/// variable constructor handled by this class.
+class SimpleVariableConstructionContext : public VariableConstructionContext {
+public:
+ explicit SimpleVariableConstructionContext(const DeclStmt *DS)
+ : VariableConstructionContext(ConstructionContext::SimpleVariableKind,
+ DS) {}
+
+ static bool classof(const ConstructionContext *CC) {
return CC->getKind() == SimpleVariableKind;
}
};
+/// Represents construction into a simple variable with an initializer syntax,
+/// with a single constructor, eg. T var = makeT();. Such construction context
+/// may only appear in C++17 because previously it was split into a temporary
+/// object constructor and an elidable simple variable 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 variable constructor on the AST level;
+/// in this case we provide a simple variable construction context.
+class CXX17ElidedCopyVariableConstructionContext
+ : public VariableConstructionContext {
+ const CXXBindTemporaryExpr *BTE;
+
+public:
+ explicit CXX17ElidedCopyVariableConstructionContext(
+ const DeclStmt *DS, const CXXBindTemporaryExpr *BTE)
+ : VariableConstructionContext(CXX17ElidedCopyVariableKind, DS), BTE(BTE) {
+ assert(BTE);
+ }
+
+ const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == CXX17ElidedCopyVariableKind;
+ }
+};
+
/// Represents construction into a field or a base class within a bigger object
/// via a constructor initializer, eg. T(): field(123) { ... }.
class ConstructorInitializerConstructionContext : public ConstructionContext {
@@ -219,24 +268,68 @@ public:
}
};
+class ReturnedValueConstructionContext : public ConstructionContext {
+ const ReturnStmt *RS;
+
+protected:
+ explicit ReturnedValueConstructionContext(ConstructionContext::Kind K,
+ const ReturnStmt *RS)
+ : ConstructionContext(K), RS(RS) {
+ assert(classof(this));
+ assert(RS);
+ }
+
+public:
+ const ReturnStmt *getReturnStmt() const { return RS; }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() >= RETURNED_VALUE_BEGIN &&
+ CC->getKind() <= RETURNED_VALUE_END;
+ }
+};
+
/// Represents a temporary object that is being immediately returned from a
/// function by value, eg. return t; or return T(123);. In this case there is
/// always going to be a constructor at the return site. However, the usual
/// temporary-related bureaucracy (CXXBindTemporaryExpr,
/// MaterializeTemporaryExpr) is normally located in the caller function's AST.
-class ReturnedValueConstructionContext : public ConstructionContext {
- const ReturnStmt *RS;
+class SimpleReturnedValueConstructionContext
+ : public ReturnedValueConstructionContext {
+public:
+ explicit SimpleReturnedValueConstructionContext(const ReturnStmt *RS)
+ : ReturnedValueConstructionContext(
+ ConstructionContext::SimpleReturnedValueKind, RS) {}
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == SimpleReturnedValueKind;
+ }
+};
+
+/// Represents a temporary object that is being immediately returned from a
+/// function by value, eg. return t; or return T(123); in C++17.
+/// In C++17 there is not going to be an elidable copy constructor at the
+/// return site. However, the usual temporary-related bureaucracy (CXXBindTemporaryExpr,
+/// MaterializeTemporaryExpr) is normally located in the caller function's AST.
+/// Note that if the object has trivial destructor, then this code is
+/// indistinguishable from a simple returned value constructor on the AST level;
+/// in this case we provide a simple returned value construction context.
+class CXX17ElidedCopyReturnedValueConstructionContext
+ : public ReturnedValueConstructionContext {
+ const CXXBindTemporaryExpr *BTE;
public:
- explicit ReturnedValueConstructionContext(const ReturnStmt *RS)
- : ConstructionContext(ConstructionContext::ReturnedValueKind), RS(RS) {
- assert(RS);
+ explicit CXX17ElidedCopyReturnedValueConstructionContext(
+ const ReturnStmt *RS, const CXXBindTemporaryExpr *BTE)
+ : ReturnedValueConstructionContext(
+ ConstructionContext::CXX17ElidedCopyReturnedValueKind, RS),
+ BTE(BTE) {
+ assert(BTE);
}
- const ReturnStmt *getReturnStmt() const { return RS; }
+ const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
static bool classof(const ConstructionContext *CC) {
- return CC->getKind() == ReturnedValueKind;
+ return CC->getKind() == CXX17ElidedCopyReturnedValueKind;
}
};
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 0672b3d9256..77eb1d37a40 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -760,9 +760,7 @@ private:
const ConstructionContext *CC =
ConstructionContext::createFromLayers(cfg->getBumpVectorContext(),
Layer);
- B->appendCXXRecordTypedCall(
- CE, cast<TemporaryObjectConstructionContext>(CC),
- cfg->getBumpVectorContext());
+ B->appendCXXRecordTypedCall(CE, CC, cfg->getBumpVectorContext());
cleanupConstructionContext(CE);
return;
}
@@ -1284,7 +1282,7 @@ void CFGBuilder::findConstructionContexts(
}
case Stmt::ImplicitCastExprClass: {
auto *Cast = cast<ImplicitCastExpr>(Child);
- // TODO: We need to support CK_ConstructorConversion, maybe other kinds?
+ // Should we support other implicit cast kinds?
switch (Cast->getCastKind()) {
case CK_NoOp:
case CK_ConstructorConversion:
@@ -4920,8 +4918,14 @@ static void print_construction_context(raw_ostream &OS,
break;
}
case ConstructionContext::SimpleVariableKind: {
- const auto *DSCC = cast<SimpleVariableConstructionContext>(CC);
- S1 = DSCC->getDeclStmt();
+ const auto *SDSCC = cast<SimpleVariableConstructionContext>(CC);
+ S1 = SDSCC->getDeclStmt();
+ break;
+ }
+ case ConstructionContext::CXX17ElidedCopyVariableKind: {
+ const auto *CDSCC = cast<CXX17ElidedCopyVariableConstructionContext>(CC);
+ S1 = CDSCC->getDeclStmt();
+ S2 = CDSCC->getCXXBindTemporaryExpr();
break;
}
case ConstructionContext::NewAllocatedObjectKind: {
@@ -4929,9 +4933,16 @@ static void print_construction_context(raw_ostream &OS,
S1 = NECC->getCXXNewExpr();
break;
}
- case ConstructionContext::ReturnedValueKind: {
- const auto *RSCC = cast<ReturnedValueConstructionContext>(CC);
+ case ConstructionContext::SimpleReturnedValueKind: {
+ const auto *RSCC = cast<SimpleReturnedValueConstructionContext>(CC);
+ S1 = RSCC->getReturnStmt();
+ break;
+ }
+ case ConstructionContext::CXX17ElidedCopyReturnedValueKind: {
+ const auto *RSCC =
+ cast<CXX17ElidedCopyReturnedValueConstructionContext>(CC);
S1 = RSCC->getReturnStmt();
+ S2 = RSCC->getCXXBindTemporaryExpr();
break;
}
case ConstructionContext::TemporaryObjectKind: {
diff --git a/clang/lib/Analysis/ConstructionContext.cpp b/clang/lib/Analysis/ConstructionContext.cpp
index 1a1bc7db8fb..68e1cc04746 100644
--- a/clang/lib/Analysis/ConstructionContext.cpp
+++ b/clang/lib/Analysis/ConstructionContext.cpp
@@ -64,11 +64,43 @@ const ConstructionContext *ConstructionContext::createFromLayers(
// lifetime extension on the parent layer.
if (const ConstructionContextLayer *ParentLayer = TopLayer->getParent()) {
assert(ParentLayer->isLast());
- MTE = cast<MaterializeTemporaryExpr>(ParentLayer->getTriggerStmt());
+ if ((MTE = dyn_cast<MaterializeTemporaryExpr>(
+ ParentLayer->getTriggerStmt()))) {
+ // A temporary object which has both destruction and
+ // materialization info.
+ auto *CC =
+ C.getAllocator().Allocate<TemporaryObjectConstructionContext>();
+ return new (CC) TemporaryObjectConstructionContext(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.
+ if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) {
+ assert(!RS->getRetValue()->getType().getCanonicalType()
+ ->getAsCXXRecordDecl()->hasTrivialDestructor());
+ auto *CC =
+ C.getAllocator()
+ .Allocate<
+ CXX17ElidedCopyReturnedValueConstructionContext>();
+ return new (CC)
+ CXX17ElidedCopyReturnedValueConstructionContext(RS, BTE);
+ }
+ if (auto *DS = dyn_cast<DeclStmt>(ParentLayer->getTriggerStmt())) {
+ assert(!cast<VarDecl>(DS->getSingleDecl())->getType()
+ .getCanonicalType()->getAsCXXRecordDecl()
+ ->hasTrivialDestructor());
+ auto *CC =
+ C.getAllocator()
+ .Allocate<CXX17ElidedCopyVariableConstructionContext>();
+ return new (CC) CXX17ElidedCopyVariableConstructionContext(DS, BTE);
+ }
+ llvm_unreachable("Unexpected construction context with destructor!");
}
+ // A temporary object that doesn't require materialization.
auto *CC =
C.getAllocator().Allocate<TemporaryObjectConstructionContext>();
- return new (CC) TemporaryObjectConstructionContext(BTE, MTE);
+ return new (CC)
+ TemporaryObjectConstructionContext(BTE, /*MTE=*/nullptr);
} else if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(S)) {
// If the object requires destruction and is not lifetime-extended,
// then it must have a BTE within its MTE.
@@ -82,8 +114,8 @@ const ConstructionContext *ConstructionContext::createFromLayers(
} else if (const auto *RS = dyn_cast<ReturnStmt>(S)) {
assert(TopLayer->isLast());
auto *CC =
- C.getAllocator().Allocate<ReturnedValueConstructionContext>();
- return new (CC) ReturnedValueConstructionContext(RS);
+ C.getAllocator().Allocate<SimpleReturnedValueConstructionContext>();
+ return new (CC) SimpleReturnedValueConstructionContext(RS);
}
} else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) {
assert(TopLayer->isLast());
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 7cf6896aa8b..07515b36470 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -196,7 +196,7 @@ ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE,
CallOpts.IsTemporaryCtorOrDtor = true;
return MRMgr.getCXXTempObjectRegion(CE, LCtx);
}
- case ConstructionContext::ReturnedValueKind: {
+ case ConstructionContext::SimpleReturnedValueKind: {
// The temporary is to be managed by the parent stack frame.
// So build it in the parent stack frame if we're not in the
// top frame of the analysis.
@@ -211,6 +211,10 @@ ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE,
CallOpts.IsTemporaryCtorOrDtor = true;
return MRMgr.getCXXTempObjectRegion(CE, TempLCtx);
}
+ case ConstructionContext::CXX17ElidedCopyVariableKind:
+ case ConstructionContext::CXX17ElidedCopyReturnedValueKind:
+ // Not implemented yet.
+ break;
}
}
// If we couldn't find an existing region to construct into, assume we're
diff --git a/clang/test/Analysis/cfg-rich-constructors.cpp b/clang/test/Analysis/cfg-rich-constructors.cpp
index c22f96dd42a..9070b003def 100644
--- a/clang/test/Analysis/cfg-rich-constructors.cpp
+++ b/clang/test/Analysis/cfg-rich-constructors.cpp
@@ -1,5 +1,7 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -analyzer-config cfg-temporary-dtors=true -std=c++11 -w %s > %t 2>&1
-// RUN: FileCheck --input-file=%t %s
+// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX11 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -analyzer-config cfg-temporary-dtors=true -std=c++17 -w %s > %t 2>&1
+// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX17 %s
class C {
public:
@@ -98,32 +100,38 @@ void simpleVariableWithOperatorNewInBraces() {
// CHECK: 1: C::get
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
// CHECK-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4])
-// CHECK-NEXT: 4: [B1.3]
-// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], class C)
-// CHECK-NEXT: 6: C c = C::get();
+// CXX11-NEXT: 4: [B1.3]
+// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], class C)
+// CXX11-NEXT: 6: C c = C::get();
+// CXX17-NEXT: 4: C c = C::get();
void simpleVariableInitializedByValue() {
C c = C::get();
}
// CHECK: void simpleVariableWithTernaryOperator(bool coin)
// CHECK: [B1]
-// CHECK-NEXT: 1: [B4.2] ? [B2.5] : [B3.6]
-// CHECK-NEXT: 2: [B1.1]
-// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C)
-// CHECK-NEXT: 4: C c = coin ? C::get() : C(0);
+// CXX11-NEXT: 1: [B4.2] ? [B2.5] : [B3.6]
+// CXX11-NEXT: 2: [B1.1]
+// CXX11-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C)
+// CXX11-NEXT: 4: C c = coin ? C::get() : C(0);
+// CXX17-NEXT: 1: [B4.2] ? [B2.3] : [B3.4]
+// CXX17-NEXT: 2: C c = coin ? C::get() : C(0);
// CHECK: [B2]
// CHECK-NEXT: 1: C::get
// CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
-// CHECK-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B2.4])
-// CHECK-NEXT: 4: [B2.3]
-// CHECK-NEXT: 5: [B2.4] (CXXConstructExpr, [B1.2], class C)
+// CXX11-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B2.4])
+// CXX11-NEXT: 4: [B2.3]
+// CXX11-NEXT: 5: [B2.4] (CXXConstructExpr, [B1.2], class C)
+// CXX17-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B1.2])
// CHECK: [B3]
// CHECK-NEXT: 1: 0
// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *)
-// CHECK-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], class C)
-// CHECK-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
-// CHECK-NEXT: 5: [B3.4]
-// CHECK-NEXT: 6: [B3.5] (CXXConstructExpr, [B1.2], class C)
+// CXX11-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], class C)
+// CXX11-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
+// CXX11-NEXT: 5: [B3.4]
+// CXX11-NEXT: 6: [B3.5] (CXXConstructExpr, [B1.2], class C)
+// CXX17-NEXT: 3: [B3.2] (CXXConstructExpr, [B1.2], class C)
+// CXX17-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
// CHECK: [B4]
// CHECK-NEXT: 1: coin
// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool)
@@ -137,9 +145,10 @@ void simpleVariableWithTernaryOperator(bool coin) {
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *)
// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class C)
// CHECK-NEXT: 4: C([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
-// CHECK-NEXT: 5: [B1.4]
-// CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.7], class C)
-// CHECK-NEXT: 7: C c = C(0);
+// CXX11-NEXT: 5: [B1.4]
+// CXX11-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.7], class C)
+// CXX11-NEXT: 7: C c = C(0);
+// CXX17-NEXT: 5: C c = C(0);
void simpleVariableWithElidableCopy() {
C c = C(0);
}
@@ -165,23 +174,27 @@ void referenceVariableWithInitializer() {
// CHECK: void referenceVariableWithTernaryOperator(bool coin)
// CHECK: [B1]
-// CHECK-NEXT: 1: [B4.2] ? [B2.5] : [B3.6]
+// CXX11-NEXT: 1: [B4.2] ? [B2.5] : [B3.6]
+// CXX17-NEXT: 1: [B4.2] ? [B2.3] : [B3.4]
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const class C)
// CHECK-NEXT: 3: [B1.2]
// CHECK-NEXT: 4: const C &c = coin ? C::get() : C(0);
// CHECK: [B2]
// CHECK-NEXT: 1: C::get
// CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
-// CHECK-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B2.4])
-// CHECK-NEXT: 4: [B2.3]
-// CHECK-NEXT: 5: [B2.4] (CXXConstructExpr, [B1.3], class C)
+// CXX11-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B2.4])
+// CXX11-NEXT: 4: [B2.3]
+// CXX11-NEXT: 5: [B2.4] (CXXConstructExpr, [B1.3], class C)
+// CXX17-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B1.3])
// CHECK: [B3]
// CHECK-NEXT: 1: 0
// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *)
-// CHECK-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], class C)
-// CHECK-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
-// CHECK-NEXT: 5: [B3.4]
-// CHECK-NEXT: 6: [B3.5] (CXXConstructExpr, [B1.3], class C)
+// CXX11-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], class C)
+// CXX11-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
+// CXX11-NEXT: 5: [B3.4]
+// CXX11-NEXT: 6: [B3.5] (CXXConstructExpr, [B1.3], class C)
+// CXX17-NEXT: 3: [B3.2] (CXXConstructExpr, [B1.3], class C)
+// CXX17-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
// CHECK: [B4]
// CHECK-NEXT: 1: coin
// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool)
@@ -214,6 +227,8 @@ public:
// CHECK-NEXT: 2: D([B1.1]) (Delegating initializer)
D(int): D() {}
+// FIXME: Why is CXXRecordTypedCall not present in C++17? Note that once it gets
+// detected the test would not fail, because FileCheck allows partial matches.
// CHECK: D(double)
// CHECK: 1: C::get
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
@@ -224,12 +239,16 @@ public:
// CHECK-NEXT: 7: CFGNewAllocator(C *)
// CHECK-NEXT: 8: C::get
// CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
-// CHECK-NEXT: 10: [B1.9]() (CXXRecordTypedCall, [B1.11])
-// CHECK-NEXT: 11: [B1.10]
-// CHECK-NEXT: 12: [B1.11] (CXXConstructExpr, [B1.13], class C)
-// CHECK-NEXT: 13: new C([B1.12])
-// CHECK-NEXT: 14: [B1.13] (CXXConstructExpr, c1([B1.13]) (Member initializer), class C)
-// CHECK-NEXT: 15: c1([B1.14]) (Member initializer)
+// CXX11-NEXT: 10: [B1.9]() (CXXRecordTypedCall, [B1.11])
+// CXX11-NEXT: 11: [B1.10]
+// CXX11-NEXT: 12: [B1.11] (CXXConstructExpr, [B1.13], class C)
+// CXX11-NEXT: 13: new C([B1.12])
+// CXX11-NEXT: 14: [B1.13] (CXXConstructExpr, c1([B1.13]) (Member initializer), class C)
+// CXX11-NEXT: 15: c1([B1.14]) (Member initializer)
+// CXX17-NEXT: 10: [B1.9]()
+// CXX17-NEXT: 11: new C([B1.10])
+// CXX17-NEXT: 12: [B1.11] (CXXConstructExpr, c1([B1.11]) (Member initializer), class C)
+// CXX17-NEXT: 13: c1([B1.12]) (Member initializer)
D(double): C(C::get()), c1(new C(C::get())) {}
};
@@ -277,9 +296,10 @@ C returnBracesWithMultipleItems() {
// CHECK: C returnTemporary()
// CHECK: 1: C() (CXXConstructExpr, [B1.2], class C)
-// CHECK-NEXT: 2: [B1.1]
-// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C)
-// CHECK-NEXT: 4: return [B1.3];
+// CXX11-NEXT: 2: [B1.1]
+// CXX11-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C)
+// CXX11-NEXT: 4: return [B1.3];
+// CXX17-NEXT: 2: return [B1.1];
C returnTemporary() {
return C();
}
@@ -289,9 +309,11 @@ C returnTemporary() {
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *)
// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class C)
// CHECK-NEXT: 4: C([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
-// CHECK-NEXT: 5: [B1.4]
-// CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.7], class C)
-// CHECK-NEXT: 7: return [B1.6];
+// CXX11-NEXT: 5: [B1.4]
+// CXX11-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.7], class C)
+// CXX11-NEXT: 7: return [B1.6];
+// CXX17-NEXT: 5: return [B1.4];
+
C returnTemporaryWithArgument() {
return C(nullptr);
}
@@ -300,9 +322,10 @@ C returnTemporaryWithArgument() {
// CHECK: 1: C::get
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
// CHECK-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4])
-// CHECK-NEXT: 4: [B1.3]
-// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], class C)
-// CHECK-NEXT: 6: return [B1.5];
+// CXX11-NEXT: 4: [B1.3]
+// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], class C)
+// CXX11-NEXT: 6: return [B1.5];
+// CXX17-NEXT: 4: return [B1.3];
C returnTemporaryConstructedByFunction() {
return C::get();
}
@@ -310,13 +333,16 @@ C returnTemporaryConstructedByFunction() {
// CHECK: C returnChainOfCopies()
// CHECK: 1: C::get
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
-// CHECK-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4])
-// CHECK-NEXT: 4: [B1.3]
-// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.7], class C)
-// CHECK-NEXT: 6: C([B1.5]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
-// CHECK-NEXT: 7: [B1.6]
-// CHECK-NEXT: 8: [B1.7] (CXXConstructExpr, [B1.9], class C)
-// CHECK-NEXT: 9: return [B1.8];
+// CXX11-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4])
+// CXX11-NEXT: 4: [B1.3]
+// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.7], class C)
+// CXX11-NEXT: 6: C([B1.5]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
+// CXX11-NEXT: 7: [B1.6]
+// CXX11-NEXT: 8: [B1.7] (CXXConstructExpr, [B1.9], class C)
+// CXX11-NEXT: 9: return [B1.8];
+// CXX17-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.5])
+// CXX17-NEXT: 4: C([B1.3]) (CXXFunctionalCastExpr, NoOp, class C)
+// CXX17-NEXT: 5: return [B1.4];
C returnChainOfCopies() {
return C(C::get());
}
@@ -331,18 +357,44 @@ public:
~D();
};
+// FIXME: There should be no temporary destructor in C++17.
// CHECK: return_stmt_with_dtor::D returnTemporary()
-// CHECK: 1: return_stmt_with_dtor::D() (CXXConstructExpr, [B1.2], [B1.4], class return_stmt_with_dtor::D)
-// CHECK-NEXT: 2: [B1.1] (BindTemporary)
-// CHECK-NEXT: 3: [B1.2] (ImplicitCastExpr, NoOp, const class return_stmt_with_dtor::D)
-// CHECK-NEXT: 4: [B1.3]
-// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.7], class return_stmt_with_dtor::D)
-// CHECK-NEXT: 6: ~return_stmt_with_dtor::D() (Temporary object destructor)
-// CHECK-NEXT: 7: return [B1.5];
+// CXX11: 1: return_stmt_with_dtor::D() (CXXConstructExpr, [B1.2], [B1.4], class return_stmt_with_dtor::D)
+// CXX11-NEXT: 2: [B1.1] (BindTemporary)
+// CXX11-NEXT: 3: [B1.2] (ImplicitCastExpr, NoOp, const class return_stmt_with_dtor::D)
+// CXX11-NEXT: 4: [B1.3]
+// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.7], class return_stmt_with_dtor::D)
+// CXX11-NEXT: 6: ~return_stmt_with_dtor::D() (Temporary object destructor)
+// CXX11-NEXT: 7: return [B1.5];
+// CXX17: 1: return_stmt_with_dtor::D() (CXXConstructExpr, [B1.4], [B1.2], class return_stmt_w
+// CXX17-NEXT: 2: [B1.1] (BindTemporary)
+// CXX17-NEXT: 3: ~return_stmt_with_dtor::D() (Temporary object destructor)
+// CXX17-NEXT: 4: return [B1.2];
D returnTemporary() {
return D();
}
+// FIXME: There should be no temporary destructor in C++17.
+// CHECK: void returnByValueIntoVariable()
+// CHECK: 1: returnTemporary
+// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class return_stmt_with_dtor::D (*)(void))
+// 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 return_stmt_with_dtor::D)
+// CXX11-NEXT: 6: [B1.5]
+// CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.8], class return_stmt_with_dtor::D)
+// CXX11-NEXT: 8: return_stmt_with_dtor::D d = returnTemporary();
+// CXX11-NEXT: 9: ~return_stmt_with_dtor::D() (Temporary object destructor)
+// CXX11-NEXT: 10: [B1.8].~D() (Implicit destructor)
+// CXX17-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.5], [B1.4])
+// CXX17-NEXT: 4: [B1.3] (BindTemporary)
+// CXX17-NEXT: 5: return_stmt_with_dtor::D d = returnTemporary();
+// CXX17-NEXT: 6: ~return_stmt_with_dtor::D() (Temporary object destructor)
+// CXX17-NEXT: 7: [B1.5].~D() (Implicit destructor)
+void returnByValueIntoVariable() {
+ D d = returnTemporary();
+}
+
} // end namespace return_stmt_with_dtor
namespace temporary_object_expr_without_dtors {
@@ -426,34 +478,60 @@ void referenceVariableWithInitializer() {
}
// CHECK: void referenceVariableWithTernaryOperator(bool coin)
-// CHECK: [B4]
-// CHECK-NEXT: 1: [B7.2] ? [B5.8] : [B6.8]
-// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT: 3: [B4.2]
-// CHECK-NEXT: 4: const temporary_object_expr_with_dtors::D &d = coin ? D::get() : temporary_object_expr_with_dtors::D(0);
-// CHECK-NEXT: T: (Temp Dtor) [B6.3]
-// CHECK: [B5]
-// CHECK-NEXT: 1: D::get
-// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, FunctionToPointerDecay, class temporary_object_expr_with_dtors::D (*)(void))
-// CHECK-NEXT: 3: [B5.2]() (CXXRecordTypedCall, [B5.4], [B5.6])
-// CHECK-NEXT: 4: [B5.3] (BindTemporary)
-// CHECK-NEXT: 5: [B5.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT: 6: [B5.5]
-// CHECK-NEXT: 7: [B5.6] (CXXConstructExpr, [B5.8], [B4.3], class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT: 8: [B5.7] (BindTemporary)
-// CHECK: [B6]
-// CHECK-NEXT: 1: 0
-// CHECK-NEXT: 2: [B6.1] (CXXConstructExpr, [B6.3], [B6.6], class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT: 3: [B6.2] (BindTemporary)
-// CHECK-NEXT: 4: temporary_object_expr_with_dtors::D([B6.3]) (CXXFunctionalCastExpr, ConstructorConversion, class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT: 5: [B6.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT: 6: [B6.5]
-// CHECK-NEXT: 7: [B6.6] (CXXConstructExpr, [B6.8], [B4.3], class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT: 8: [B6.7] (BindTemporary)
-// CHECK: [B7]
-// CHECK-NEXT: 1: coin
-// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK-NEXT: T: [B7.2] ? ... : ...
+// CXX11: [B1]
+// CXX11-NEXT: 1: [B4.4].~D() (Implicit destructor)
+// CXX11: [B2]
+// CXX11-NEXT: 1: ~temporary_object_expr_with_dtors::D() (Temporary object destructor)
+// CXX11: [B3]
+// CXX11-NEXT: 1: ~temporary_object_expr_with_dtors::D() (Temporary object destructor)
+// CXX11: [B4]
+// CXX11-NEXT: 1: [B7.2] ? [B5.8] : [B6.8]
+// CXX11-NEXT: 2: [B4.1] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT: 3: [B4.2]
+// CXX11-NEXT: 4: const temporary_object_expr_with_dtors::D &d = coin ? D::get() : temporary_object_expr_with_dtors::D(0);
+// CXX11-NEXT: T: (Temp Dtor) [B6.3]
+// CXX11: [B5]
+// CXX11-NEXT: 1: D::get
+// CXX11-NEXT: 2: [B5.1] (ImplicitCastExpr, FunctionToPointerDecay, class temporary_object_expr_with_dtors::D (*)(void))
+// CXX11-NEXT: 3: [B5.2]() (CXXRecordTypedCall, [B5.4], [B5.6])
+// CXX11-NEXT: 4: [B5.3] (BindTemporary)
+// CXX11-NEXT: 5: [B5.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT: 6: [B5.5]
+// CXX11-NEXT: 7: [B5.6] (CXXConstructExpr, [B5.8], [B4.3], class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT: 8: [B5.7] (BindTemporary)
+// CXX11: [B6]
+// CXX11-NEXT: 1: 0
+// CXX11-NEXT: 2: [B6.1] (CXXConstructExpr, [B6.3], [B6.6], class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT: 3: [B6.2] (BindTemporary)
+// CXX11-NEXT: 4: temporary_object_expr_with_dtors::D([B6.3]) (CXXFunctionalCastExpr, ConstructorConversion, class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT: 5: [B6.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT: 6: [B6.5]
+// CXX11-NEXT: 7: [B6.6] (CXXConstructExpr, [B6.8], [B4.3], class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT: 8: [B6.7] (BindTemporary)
+// CXX11: [B7]
+// CXX11-NEXT: 1: coin
+// CXX11-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CXX11-NEXT: T: [B7.2] ? ... : ...
+// CXX17: [B1]
+// CXX17-NEXT: 1: [B4.2] ? [B2.4] : [B3.4]
+// CXX17-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
+// CXX17-NEXT: 3: [B1.2]
+// CXX17-NEXT: 4: const temporary_object_expr_with_dtors::D &d = coin ? D::get() : temporary_object_expr_with_dtors::D(0);
+// CXX17-NEXT: 5: [B1.4].~D() (Implicit destructor)
+// CXX17: [B2]
+// CXX17-NEXT: 1: D::get
+// CXX17-NEXT: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class temporary_object_expr_with_dtors::D (*)(void))
+// CXX17-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B2.4], [B1.3])
+// CXX17-NEXT: 4: [B2.3] (BindTemporary)
+// CXX17: [B3]
+// CXX17-NEXT: 1: 0
+// CXX17-NEXT: 2: [B3.1] (CXXConstructExpr, [B3.3], [B1.3], class temporary_object_expr_with_dtors::D)
+// CXX17-NEXT: 3: [B3.2] (BindTemporary)
+// CXX17-NEXT: 4: temporary_object_expr_with_dtors::D([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class temporary_object_expr_with_dtors::D)
+// CXX17: [B4]
+// CXX17-NEXT: 1: coin
+// CXX17-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CXX17-NEXT: T: [B4.2] ? ... : ...
void referenceVariableWithTernaryOperator(bool coin) {
const D &d = coin ? D::get() : D(0);
}
@@ -472,15 +550,24 @@ void referenceWithFunctionalCast() {
// Test the condition constructor, we don't care about branch constructors here.
// CHECK: void constructorInTernaryCondition()
-// CHECK: 1: 1
-// CHECK-NEXT: 2: [B7.1] (CXXConstructExpr, [B7.3], class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT: 3: [B7.2] (BindTemporary)
-// CHECK-NEXT: 4: temporary_object_expr_with_dtors::D([B7.3]) (CXXFunctionalCastExpr, ConstructorConv
-// CHECK-NEXT: 5: [B7.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT: 6: [B7.5].operator bool
-// CHECK-NEXT: 7: [B7.5]
-// CHECK-NEXT: 8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK-NEXT: T: [B7.8] ? ... : ...
+// CXX11: 1: 1
+// CXX11-NEXT: 2: [B7.1] (CXXConstructExpr, [B7.3], class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT: 3: [B7.2] (BindTemporary)
+// CXX11-NEXT: 4: temporary_object_expr_with_dtors::D([B7.3]) (CXXFunctionalCastExpr, ConstructorConversion, class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT: 5: [B7.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT: 6: [B7.5].operator bool
+// CXX11-NEXT: 7: [B7.5]
+// CXX11-NEXT: 8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11-NEXT: T: [B7.8] ? ... : ...
+// CXX17: 1: 1
+// CXX17-NEXT: 2: [B4.1] (CXXConstructExpr, [B4.3], class temporary_object_expr_with_dtors::D)
+// CXX17-NEXT: 3: [B4.2] (BindTemporary)
+// CXX17-NEXT: 4: temporary_object_expr_with_dtors::D([B4.3]) (CXXFunctionalCastExpr, ConstructorConversion, class temporary_object_expr_with_dtors::D)
+// CXX17-NEXT: 5: [B4.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
+// CXX17-NEXT: 6: [B4.5].operator bool
+// CXX17-NEXT: 7: [B4.5]
+// CXX17-NEXT: 8: [B4.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX17-NEXT: T: [B4.8] ? ... : ...
void constructorInTernaryCondition() {
const D &d = D(1) ? D(2) : D(3);
}
@@ -500,17 +587,23 @@ public:
// CHECK: void implicitConstructionConversionFromTemporary()
// CHECK: 1: implicit_constructor_conversion::A() (CXXConstructExpr, [B1.3], class implicit_constructor_conversion::A)
-// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A)
-// CHECK-NEXT: 3: [B1.2]
-// CHECK-NEXT: 4: [B1.3] (CXXConstructExpr, [B1.6], [B1.8], class implicit_constructor_conversion::B)
-// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
-// CHECK-NEXT: 6: [B1.5] (BindTemporary)
-// CHECK-NEXT: 7: [B1.6] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B)
-// CHECK-NEXT: 8: [B1.7]
-// CHECK-NEXT: 9: [B1.8] (CXXConstructExpr, [B1.10], class implicit_constructor_conversion::B)
-// CHECK-NEXT: 10: implicit_constructor_conversion::B b = implicit_constructor_conversion::A();
-// CHECK-NEXT: 11: ~implicit_constructor_conversion::B() (Temporary object destructor)
-// CHECK-NEXT: 12: [B1.10].~B() (Implicit destructor)
+// CXX11-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A)
+// CXX11-NEXT: 3: [B1.2]
+// CXX11-NEXT: 4: [B1.3] (CXXConstructExpr, [B1.6], [B1.8], class implicit_constructor_conversion::B)
+// CXX11-NEXT: 5: [B1.4] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
+// CXX11-NEXT: 6: [B1.5] (BindTemporary)
+// CXX11-NEXT: 7: [B1.6] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B)
+// CXX11-NEXT: 8: [B1.7]
+// CXX11-NEXT: 9: [B1.8] (CXXConstructExpr, [B1.10], class implicit_constructor_conversion::B)
+// CXX11-NEXT: 10: implicit_constructor_conversion::B b = implicit_constructor_conversion::A();
+// CXX11-NEXT: 11: ~implicit_constructor_conversion::B() (Temporary object destructor)
+// CXX11-NEXT: 12: [B1.10].~B() (Implicit destructor)
+// CXX17-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A)
+// CXX17-NEXT: 3: [B1.2]
+// CXX17-NEXT: 4: [B1.3] (CXXConstructExpr, [B1.6], class implicit_constructor_conversion::B)
+// CXX17-NEXT: 5: [B1.4] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
+// CXX17-NEXT: 6: implicit_constructor_conversion::B b = implicit_constructor_conversion::A();
+// CXX17-NEXT: 7: [B1.6].~B() (Implicit destructor)
void implicitConstructionConversionFromTemporary() {
B b = A();
}
@@ -521,15 +614,19 @@ void implicitConstructionConversionFromTemporary() {
// CHECK-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.5])
// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A)
// CHECK-NEXT: 5: [B1.4]
-// CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.8], [B1.10], class implicit_constructor_conversion::B)
-// CHECK-NEXT: 7: [B1.6] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
-// CHECK-NEXT: 8: [B1.7] (BindTemporary)
-// CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B)
-// CHECK-NEXT: 10: [B1.9]
-// CHECK-NEXT: 11: [B1.10] (CXXConstructExpr, [B1.12], class implicit_constructor_conversion::B)
-// CHECK-NEXT: 12: implicit_constructor_conversion::B b = get();
-// CHECK-NEXT: 13: ~implicit_constructor_conversion::B() (Temporary object destructor)
-// CHECK-NEXT: 14: [B1.12].~B() (Implicit destructor)
+// CXX11-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.8], [B1.10], class implicit_constructor_conversion::B)
+// CXX11-NEXT: 7: [B1.6] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
+// CXX11-NEXT: 8: [B1.7] (BindTemporary)
+// CXX11-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B)
+// CXX11-NEXT: 10: [B1.9]
+// CXX11-NEXT: 11: [B1.10] (CXXConstructExpr, [B1.12], class implicit_constructor_conversion::B)
+// CXX11-NEXT: 12: implicit_constructor_conversion::B b = get();
+// CXX11-NEXT: 13: ~implicit_constructor_conversion::B() (Temporary object destructor)
+// CXX11-NEXT: 14: [B1.12].~B() (Implicit destructor)
+// CXX17-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.8], class implicit_constructor_conversion::B)
+// CXX17-NEXT: 7: [B1.6] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
+// CXX17-NEXT: 8: implicit_constructor_conversion::B b = get();
+// CXX17-NEXT: 9: [B1.8].~B() (Implicit destructor)
void implicitConstructionConversionFromFunctionValue() {
B b = get();
}
@@ -548,7 +645,6 @@ void implicitConstructionConversionFromTemporaryWithLifetimeExtension() {
const B &b = A();
}
-// FIXME: Find construction context for the implicit constructor conversion.
// CHECK: void implicitConstructionConversionFromFunctionValueWithLifetimeExtension()
// CHECK: 1: get
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class implicit_constructor_conver
OpenPOWER on IntegriCloud