diff options
| author | Artem Dergachev <artem.dergachev@gmail.com> | 2018-02-15 02:32:32 +0000 |
|---|---|---|
| committer | Artem Dergachev <artem.dergachev@gmail.com> | 2018-02-15 02:32:32 +0000 |
| commit | 94020268fe9f48a88f06a9739ce7b6025945338c (patch) | |
| tree | c179fc676a59b0b0a53eccfbdf9bebfa239b4854 /clang/test/Analysis/temporaries.cpp | |
| parent | e231bd342eacb2fe84af9d563c77ea4be5e1f250 (diff) | |
| download | bcm5719-llvm-94020268fe9f48a88f06a9739ce7b6025945338c.tar.gz bcm5719-llvm-94020268fe9f48a88f06a9739ce7b6025945338c.zip | |
[analyzer] Allow inlining constructors into return values.
This only affects the cfg-temporary-dtors mode - in this mode we begin inlining
constructors that are constructing function return values. These constructors
have a correct construction context since r324952.
Because temporary destructors are not only never inlined, but also don't have
the correct target region yet, this change is not entirely safe. But this
will be fixed in the subsequent commits, while this stays off behind the
cfg-temporary-dtors flag.
Lifetime extension for return values is still not modeled correctly.
Differential Revision: https://reviews.llvm.org/D42875
llvm-svn: 325202
Diffstat (limited to 'clang/test/Analysis/temporaries.cpp')
| -rw-r--r-- | clang/test/Analysis/temporaries.cpp | 164 |
1 files changed, 162 insertions, 2 deletions
diff --git a/clang/test/Analysis/temporaries.cpp b/clang/test/Analysis/temporaries.cpp index 9e2d45f693a..a1fa0368be1 100644 --- a/clang/test/Analysis/temporaries.cpp +++ b/clang/test/Analysis/temporaries.cpp @@ -1,9 +1,10 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s -// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -w -std=c++03 %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -w -std=c++11 %s // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s -std=c++11 extern bool clang_analyzer_eval(bool); extern bool clang_analyzer_warnIfReached(); +void clang_analyzer_checkInlined(bool); struct Trivial { Trivial(int x) : value(x) {} @@ -422,6 +423,10 @@ namespace destructors { struct CtorWithNoReturnDtor { CtorWithNoReturnDtor() = default; + CtorWithNoReturnDtor(int x) { + clang_analyzer_checkInlined(false); // no-warning + } + ~CtorWithNoReturnDtor() __attribute__((noreturn)); }; @@ -439,6 +444,12 @@ namespace destructors { clang_analyzer_warnIfReached(); // no-warning } +#if __cplusplus >= 201103L + CtorWithNoReturnDtor returnNoReturnDtor() { + return {1}; // no-crash + } +#endif + #endif // TEMPORARY_DTORS } @@ -530,3 +541,152 @@ void run() { Sub(i).m(); } } + +namespace test_return_temporary { +class C { + int x, y; + +public: + C(int x, int y) : x(x), y(y) {} + int getX() const { return x; } + int getY() const { return y; } + ~C() {} +}; + +class D: public C { +public: + D() : C(1, 2) {} + D(const D &d): C(d.getX(), d.getY()) {} +}; + +C returnTemporaryWithVariable() { C c(1, 2); return c; } +C returnTemporaryWithAnotherFunctionWithVariable() { + return returnTemporaryWithVariable(); +} +C returnTemporaryWithCopyConstructionWithVariable() { + return C(returnTemporaryWithVariable()); +} + +C returnTemporaryWithConstruction() { return C(1, 2); } +C returnTemporaryWithAnotherFunctionWithConstruction() { + return returnTemporaryWithConstruction(); +} +C returnTemporaryWithCopyConstructionWithConstruction() { + return C(returnTemporaryWithConstruction()); +} + +D returnTemporaryWithVariableAndNonTrivialCopy() { D d; return d; } +D returnTemporaryWithAnotherFunctionWithVariableAndNonTrivialCopy() { + return returnTemporaryWithVariableAndNonTrivialCopy(); +} +D returnTemporaryWithCopyConstructionWithVariableAndNonTrivialCopy() { + return D(returnTemporaryWithVariableAndNonTrivialCopy()); +} + +#if __cplusplus >= 201103L +C returnTemporaryWithBraces() { return {1, 2}; } +C returnTemporaryWithAnotherFunctionWithBraces() { + return returnTemporaryWithBraces(); +} +C returnTemporaryWithCopyConstructionWithBraces() { + return C(returnTemporaryWithBraces()); +} +#endif // C++11 + +void test() { + C c1 = returnTemporaryWithVariable(); + clang_analyzer_eval(c1.getX() == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(c1.getY() == 2); // expected-warning{{TRUE}} + + C c2 = returnTemporaryWithAnotherFunctionWithVariable(); + clang_analyzer_eval(c2.getX() == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(c2.getY() == 2); // expected-warning{{TRUE}} + + C c3 = returnTemporaryWithCopyConstructionWithVariable(); + clang_analyzer_eval(c3.getX() == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(c3.getY() == 2); // expected-warning{{TRUE}} + + C c4 = returnTemporaryWithConstruction(); + // Should be TRUE under TEMPORARY_DTORS once this sort of construction + // in the inlined function is supported. + clang_analyzer_eval(c4.getX() == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(c4.getY() == 2); // expected-warning{{UNKNOWN}} + + C c5 = returnTemporaryWithAnotherFunctionWithConstruction(); + // Should be TRUE under TEMPORARY_DTORS once this sort of construction + // in the inlined function is supported. + clang_analyzer_eval(c5.getX() == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(c5.getY() == 2); // expected-warning{{UNKNOWN}} + + C c6 = returnTemporaryWithCopyConstructionWithConstruction(); + // Should be TRUE under TEMPORARY_DTORS once this sort of construction + // in the inlined function is supported. + clang_analyzer_eval(c5.getX() == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(c5.getY() == 2); // expected-warning{{UNKNOWN}} + +#if __cplusplus >= 201103L + + C c7 = returnTemporaryWithBraces(); + clang_analyzer_eval(c7.getX() == 1); + clang_analyzer_eval(c7.getY() == 2); +#ifdef TEMPORARY_DTORS + // expected-warning@-3{{TRUE}} + // expected-warning@-3{{TRUE}} +#else + // expected-warning@-6{{UNKNOWN}} + // expected-warning@-6{{UNKNOWN}} +#endif + + C c8 = returnTemporaryWithAnotherFunctionWithBraces(); + clang_analyzer_eval(c8.getX() == 1); + clang_analyzer_eval(c8.getY() == 2); +#ifdef TEMPORARY_DTORS + // expected-warning@-3{{TRUE}} + // expected-warning@-3{{TRUE}} +#else + // expected-warning@-6{{UNKNOWN}} + // expected-warning@-6{{UNKNOWN}} +#endif + + C c9 = returnTemporaryWithCopyConstructionWithBraces(); + clang_analyzer_eval(c9.getX() == 1); + clang_analyzer_eval(c9.getY() == 2); +#ifdef TEMPORARY_DTORS + // expected-warning@-3{{TRUE}} + // expected-warning@-3{{TRUE}} +#else + // expected-warning@-6{{UNKNOWN}} + // expected-warning@-6{{UNKNOWN}} +#endif + +#endif // C++11 + + D d1 = returnTemporaryWithVariableAndNonTrivialCopy(); + clang_analyzer_eval(d1.getX() == 1); + clang_analyzer_eval(d1.getY() == 2); +#ifdef TEMPORARY_DTORS + // expected-warning@-3{{TRUE}} + // expected-warning@-3{{TRUE}} +#else + // expected-warning@-6{{UNKNOWN}} + // expected-warning@-6{{UNKNOWN}} +#endif + + D d2 = returnTemporaryWithAnotherFunctionWithVariableAndNonTrivialCopy(); + clang_analyzer_eval(d2.getX() == 1); + clang_analyzer_eval(d2.getY() == 2); +#ifdef TEMPORARY_DTORS + // expected-warning@-3{{TRUE}} + // expected-warning@-3{{TRUE}} +#else + // expected-warning@-6{{UNKNOWN}} + // expected-warning@-6{{UNKNOWN}} +#endif + + // Should be TRUE under TEMPORARY_DTORS once this sort of construction + // in the inlined function is supported. + D d3 = returnTemporaryWithCopyConstructionWithVariableAndNonTrivialCopy(); + clang_analyzer_eval(d3.getX() == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(d3.getY() == 2); // expected-warning{{UNKNOWN}} +} +} // namespace test_return_temporary |

