This revision was automatically updated to reflect the committed changes.
Closed by commit rC334684: [analyzer] Re-enable C++17-specific RVO construction
contexts. (authored by dergachev, committed by ).
Herald added a subscriber: mikhail.ramalho.
Repository:
rC Clang
https://reviews.llvm.org/D47405
Files:
lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
test/Analysis/cxx17-mandatory-elision.cpp
Index: test/Analysis/cxx17-mandatory-elision.cpp
===================================================================
--- test/Analysis/cxx17-mandatory-elision.cpp
+++ test/Analysis/cxx17-mandatory-elision.cpp
@@ -150,9 +150,8 @@
ClassWithoutDestructor c = make3(v);
#if __cplusplus >= 201703L
- // FIXME: Both should be TRUE.
clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
- clang_analyzer_eval(v.buf[0] == &c); // expected-warning{{FALSE}}
+ clang_analyzer_eval(v.buf[0] == &c); // expected-warning{{TRUE}}
#else
clang_analyzer_eval(v.len == 5); // expected-warning{{TRUE}}
clang_analyzer_eval(v.buf[0] != v.buf[1]); // expected-warning{{TRUE}}
@@ -183,6 +182,13 @@
AddressVector<ClassWithDestructor> v;
{
ClassWithDestructor c = ClassWithDestructor(v);
+ // Check if the last destructor is an automatic destructor.
+ // A temporary destructor would have fired by now.
+#if __cplusplus >= 201703L
+ clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
+#else
+ clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
+#endif
}
#if __cplusplus >= 201703L
// 0. Construct the variable.
@@ -210,6 +216,13 @@
AddressVector<ClassWithDestructor> v;
{
TestCtorInitializer t(v);
+ // Check if the last destructor is an automatic destructor.
+ // A temporary destructor would have fired by now.
+#if __cplusplus >= 201703L
+ clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
+#else
+ clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
+#endif
}
#if __cplusplus >= 201703L
// 0. Construct the member variable.
@@ -227,4 +240,53 @@
#endif
}
+
+ClassWithDestructor make1(AddressVector<ClassWithDestructor> &v) {
+ return ClassWithDestructor(v);
+}
+ClassWithDestructor make2(AddressVector<ClassWithDestructor> &v) {
+ return make1(v);
+}
+ClassWithDestructor make3(AddressVector<ClassWithDestructor> &v) {
+ return make2(v);
+}
+
+void testMultipleReturnsWithDestructors() {
+ AddressVector<ClassWithDestructor> v;
+ {
+ ClassWithDestructor c = make3(v);
+ // Check if the last destructor is an automatic destructor.
+ // A temporary destructor would have fired by now.
+#if __cplusplus >= 201703L
+ clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
+#else
+ clang_analyzer_eval(v.len == 9); // expected-warning{{TRUE}}
+#endif
+ }
+
+#if __cplusplus >= 201703L
+ // 0. Construct the variable. Yes, constructor in make1() constructs
+ // the variable 'c'.
+ // 1. Destroy the variable.
+ clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
+#else
+ // 0. Construct the temporary in make1().
+ // 1. Construct the temporary in make2().
+ // 2. Destroy the temporary in make1().
+ // 3. Construct the temporary in make3().
+ // 4. Destroy the temporary in make2().
+ // 5. Construct the temporary here.
+ // 6. Destroy the temporary in make3().
+ // 7. Construct the variable.
+ // 8. Destroy the temporary here.
+ // 9. Destroy the variable.
+ clang_analyzer_eval(v.len == 10); // expected-warning{{TRUE}}
+ clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
+ clang_analyzer_eval(v.buf[1] == v.buf[4]); // expected-warning{{TRUE}}
+ clang_analyzer_eval(v.buf[3] == v.buf[6]); // expected-warning{{TRUE}}
+ clang_analyzer_eval(v.buf[5] == v.buf[8]); // expected-warning{{TRUE}}
+ clang_analyzer_eval(v.buf[7] == v.buf[9]); // expected-warning{{TRUE}}
+#endif
+}
} // namespace address_vector_tests
Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -180,7 +180,8 @@
}
break;
}
- case ConstructionContext::SimpleReturnedValueKind: {
+ case ConstructionContext::SimpleReturnedValueKind:
+ case ConstructionContext::CXX17ElidedCopyReturnedValueKind: {
// 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.
@@ -193,16 +194,10 @@
// call in the parent stack frame. This is equivalent to not being
// able to find construction context at all.
break;
- } else if (!isa<TemporaryObjectConstructionContext>(
- RTC->getConstructionContext())) {
- // FIXME: The return value is constructed directly into a
- // non-temporary due to C++17 mandatory copy elision. This is not
- // implemented yet.
- assert(getContext().getLangOpts().CPlusPlus17);
- break;
}
- CC = RTC->getConstructionContext();
- LCtx = CallerLCtx;
+ return prepareForObjectConstruction(
+ cast<Expr>(SFC->getCallSite()), State, CallerLCtx,
+ RTC->getConstructionContext(), CallOpts);
} else {
// We are on the top frame of the analysis.
// TODO: What exactly happens when we are? Does the temporary object
@@ -212,9 +207,7 @@
SVal V = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx));
return std::make_pair(State, V);
}
-
- // Continue as if we have a temporary with a different location context.
- // FALLTHROUGH.
+ llvm_unreachable("Unhandled return value construction context!");
}
case ConstructionContext::TemporaryObjectKind: {
const auto *TCC = cast<TemporaryObjectConstructionContext>(CC);
@@ -261,9 +254,6 @@
CallOpts.IsTemporaryCtorOrDtor = true;
return std::make_pair(State, V);
}
- case ConstructionContext::CXX17ElidedCopyReturnedValueKind:
- // Not implemented yet.
- break;
}
}
// If we couldn't find an existing region to construct into, assume we're
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits