From e77ac66b8c1cf4f09f931d37749ed258f122d708 Mon Sep 17 00:00:00 2001 From: isuckatcs <65320245+isuckatcs@users.noreply.github.com> Date: Mon, 13 Jun 2022 15:53:31 +0200 Subject: [PATCH] [Static Analyzer] Structured binding to data members Introducing structured binding to data members. Differential Revision: https://reviews.llvm.org/D127643 --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 19 ++- .../uninit-structured-binding-struct.cpp | 116 ++++++++++++++++++ 2 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 clang/test/Analysis/uninit-structured-binding-struct.cpp diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index a0c7dda896ef..6ba19d52488c 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -2591,9 +2591,22 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, // operator&. return; } - if (isa(D)) { - // FIXME: proper support for bound declarations. - // For now, let's just prevent crashing. + if (const auto *BD = dyn_cast(D)) { + const auto *DD = cast(BD->getDecomposedDecl()); + + if (const auto *ME = dyn_cast(BD->getBinding())) { + const auto *Field = cast(ME->getMemberDecl()); + + SVal Base = state->getLValue(DD, LCtx); + if (DD->getType()->isReferenceType()) { + Base = state->getSVal(Base.getAsRegion()); + } + + SVal V = state->getLValue(Field, Base); + + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V)); + } + return; } diff --git a/clang/test/Analysis/uninit-structured-binding-struct.cpp b/clang/test/Analysis/uninit-structured-binding-struct.cpp new file mode 100644 index 000000000000..fec82c0d8589 --- /dev/null +++ b/clang/test/Analysis/uninit-structured-binding-struct.cpp @@ -0,0 +1,116 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 -verify %s + +void clang_analyzer_eval(bool); + +struct s { + int a; + int b; +}; + +void a(void) { + s tst; + + auto [i, j] = tst; + + int x = i; // expected-warning{{Assigned value is garbage or undefined}} +} + +void b(void) { + s tst; + tst.a = 1; + + auto [i, j] = tst; + + clang_analyzer_eval(i == 1); // expected-warning{{TRUE}} + int y = j; // expected-warning{{Assigned value is garbage or undefined}} +} + +void c(void) { + s tst; + + auto &[i, j] = tst; + + int x = i; // expected-warning{{Assigned value is garbage or undefined}} +} + +void d(void) { + s tst; + tst.a = 1; + + auto &[i, j] = tst; + + clang_analyzer_eval(i == 1); // expected-warning{{TRUE}} + i = 2; + clang_analyzer_eval(tst.a == 2); // expected-warning{{TRUE}} + + int y = j; // expected-warning{{Assigned value is garbage or undefined}} +} + +void e(void) { + s tst; + tst.a = 1; + + auto &[i, j] = tst; + + clang_analyzer_eval(i == 1); // expected-warning{{TRUE}} + + tst.b = 2; + clang_analyzer_eval(j == 2); // expected-warning{{TRUE}} +} + +void f(void) { + s tst; + + auto &&[i, j] = tst; + + int x = i; // expected-warning{{Assigned value is garbage or undefined}} +} + +void g(void) { + s tst; + tst.a = 1; + + auto &&[i, j] = tst; + + clang_analyzer_eval(i == 1); // expected-warning{{TRUE}} + int y = j; // expected-warning{{Assigned value is garbage or undefined}} +} + +struct s2 { + int a = 1; + int b = 2; +}; + +struct s3 { + s x; + s2 y; +}; + +void h(void) { + s3 tst; + + clang_analyzer_eval(tst.y.a == 1); // expected-warning{{TRUE}} + + auto [i, j] = tst; + + // FIXME: These should be undefined, but we have to fix + // reading undefined from lazy compound values first. + clang_analyzer_eval(i.a); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(i.b); // expected-warning{{UNKNOWN}} + + clang_analyzer_eval(j.a == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(j.b == 2); // expected-warning{{TRUE}} +} + +void i(void) { + s3 tst; + + clang_analyzer_eval(tst.y.a == 1); // expected-warning{{TRUE}} + + auto &[i, j] = tst; + j.a = 3; + + clang_analyzer_eval(tst.y.a == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(tst.y.b == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(j.b == 2); // expected-warning{{TRUE}} +}