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 *
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 {
}
};
+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;
}
};
// 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:
// 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)
// 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);
}
// 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)
// 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))
// 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())) {}
};
// 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();
}
// 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);
}
// 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();
}
// 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());
}
~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 {
}
// 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);
}
// 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);
}
// 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();
}
// 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();
}
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