brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.5 KiB · 8ce2000 Raw
335 lines · cpp
1// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -analyzer-config eagerly-assume=false %s2// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -DTEMPORARIES -verify -analyzer-config eagerly-assume=false %s3// RUN: %clang_analyze_cc1 -Wno-unused -std=c++17 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -DTEMPORARIES -analyzer-config eagerly-assume=false %s4// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -DMOVES -verify -analyzer-config eagerly-assume=false %s5// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -DTEMPORARIES -DMOVES -verify -analyzer-config eagerly-assume=false %s6// RUN: %clang_analyze_cc1 -Wno-unused -std=c++17 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -DTEMPORARIES -DMOVES -analyzer-config eagerly-assume=false %s7 8// Note: The C++17 run-lines don't -verify yet - it is a no-crash test.9 10void clang_analyzer_eval(bool);11void clang_analyzer_checkInlined(bool);12 13namespace pr17001_call_wrong_destructor {14bool x;15struct A {16  int *a;17  A() {}18  ~A() {}19};20struct B : public A {21  B() {}22  ~B() { x = true; }23};24 25void f() {26  {27    const A &a = B();28  }29  clang_analyzer_eval(x); // expected-warning{{TRUE}}30}31} // end namespace pr17001_call_wrong_destructor32 33namespace pr19539_crash_on_destroying_an_integer {34struct A {35  int i;36  int j[2];37  A() : i(1) {38    j[0] = 2;39    j[1] = 3;40  }41  ~A() {}42};43 44void f() {45  const int &x = A().i; // no-crash46  const int &y = A().j[1]; // no-crash47  const int &z = (A().j[1], A().j[0]); // no-crash48 49  clang_analyzer_eval(x == 1);50  clang_analyzer_eval(y == 3);51  clang_analyzer_eval(z == 2);52#ifdef TEMPORARIES53  // expected-warning@-4{{TRUE}}54  // expected-warning@-4{{TRUE}}55  // expected-warning@-4{{TRUE}}56#else57  // expected-warning@-8{{UNKNOWN}}58  // expected-warning@-8{{UNKNOWN}}59  // expected-warning@-8{{UNKNOWN}}60#endif61}62} // end namespace pr19539_crash_on_destroying_an_integer63 64namespace maintain_original_object_address_on_lifetime_extension {65class C {66  C **after, **before;67 68public:69  bool x;70 71  C(bool x, C **after, C **before) : x(x), after(after), before(before) {72    *before = this;73  }74 75  // Don't track copies in our tests.76  C(const C &c) : x(c.x), after(nullptr), before(nullptr) {}77 78  ~C() { if (after) *after = this; }79 80  operator bool() const { return x; }81 82  static C make(C **after, C **before) { return C(false, after, before); }83};84 85void f1() {86  C *after, *before;87  {88    const C &c = C(true, &after, &before);89  }90  clang_analyzer_eval(after == before);91#ifdef TEMPORARIES92  // expected-warning@-2{{TRUE}}93#else94  // expected-warning@-4{{UNKNOWN}}95#endif96}97 98void f2() {99  C *after, *before;100  {101    C c = C(1, &after, &before);102  }103  clang_analyzer_eval(after == before); // expected-warning{{TRUE}}104}105 106void f3(bool coin) {107  C *after, *before;108  {109    const C &c = coin ? C(true, &after, &before) : C(false, &after, &before);110  }111  clang_analyzer_eval(after == before);112#ifdef TEMPORARIES113  // expected-warning@-2{{TRUE}}114#else115  // expected-warning@-4{{UNKNOWN}}116#endif117}118 119void f4(bool coin) {120  C *after, *before;121  {122    // no-crash123    const C &c = C(coin, &after, &before) ?: C(false, &after, &before);124  }125  // FIXME: Add support for lifetime extension through binary conditional126  // operator. Ideally also add support for the binary conditional operator in127  // C++. Because for now it calls the constructor for the condition twice.128  if (coin) {129    // FIXME: Should not warn.130    clang_analyzer_eval(after == before);131#ifdef TEMPORARIES132  // expected-warning@-2{{The left operand of '==' is a garbage value}}133#else134  // expected-warning@-4{{UNKNOWN}}135#endif136  } else {137    // FIXME: Should be TRUE.138    clang_analyzer_eval(after == before);139#ifdef TEMPORARIES140  // expected-warning@-2{{FALSE}}141#else142  // expected-warning@-4{{UNKNOWN}}143#endif144  }145}146 147void f5() {148  C *after, *before;149  {150    const bool &x = C(true, &after, &before).x; // no-crash151  }152  clang_analyzer_eval(after == before);153#ifdef TEMPORARIES154  // expected-warning@-2{{TRUE}}155#else156  // expected-warning@-4{{UNKNOWN}}157#endif158}159 160struct A { // A is an aggregate.161  const C &c;162};163 164void f6() {165  C *after, *before;166  {167    A a{C(true, &after, &before)};168  }169  // FIXME: Should be TRUE. Should not warn about garbage value.170  clang_analyzer_eval(after == before); // expected-warning{{UNKNOWN}}171}172 173void f7() {174  C *after, *before;175  {176    A a = {C(true, &after, &before)};177  }178  // FIXME: Should be TRUE. Should not warn about garbage value.179  clang_analyzer_eval(after == before); // expected-warning{{UNKNOWN}}180}181 182void f8() {183  C *after, *before;184  {185    A a[2] = {C(false, nullptr, nullptr), C(true, &after, &before)};186  }187  // FIXME: Should be TRUE. Should not warn about garbage value.188  clang_analyzer_eval(after == before); // expected-warning{{UNKNOWN}}189}190} // end namespace maintain_original_object_address_on_lifetime_extension191 192namespace maintain_original_object_address_on_move {193class C {194  int *x;195 196public:197  C() : x(nullptr) {}198  C(int *x) : x(x) {}199  C(const C &c) = delete;200  C(C &&c) : x(c.x) { c.x = nullptr; }201  C &operator=(C &&c) {202    x = c.x;203    c.x = nullptr;204    return *this;205  }206  ~C() {207    // This was triggering the division by zero warning in f1() and f2():208    // Because move-elision materialization was incorrectly causing the object209    // to be relocated from one address to another before move, but destructor210    // was operating on the old address, it was still thinking that 'x' is set.211    if (x)212      *x = 0;213  }214};215 216void f1() {217  int x = 1;218  // &x is replaced with nullptr in move-constructor before the temporary dies.219  C c = C(&x);220  // Hence x was not set to 0 yet.221  1 / x; // no-warning222}223void f2() {224  int x = 1;225  C c;226  // &x is replaced with nullptr in move-assignment before the temporary dies.227  c = C(&x);228  // Hence x was not set to 0 yet.229  1 / x; // no-warning230}231} // end namespace maintain_original_object_address_on_move232 233namespace maintain_address_of_copies {234class C;235 236struct AddressVector {237  C *buf[10];238  int len;239 240  AddressVector() : len(0) {}241 242  void push(C *c) {243    buf[len] = c;244    ++len;245  }246};247 248class C {249  AddressVector &v;250 251public:252  C(AddressVector &v) : v(v) { v.push(this); }253  ~C() { v.push(this); }254 255#ifdef MOVES256  C(C &&c) : v(c.v) { v.push(this); }257#endif258 259  // Note how return-statements prefer move-constructors when available.260  C(const C &c) : v(c.v) {261#ifdef MOVES262    clang_analyzer_checkInlined(false); // no-warning263#else264    v.push(this);265#endif266  } // no-warning267 268  static C make(AddressVector &v) { return C(v); }269};270 271void f1() {272  AddressVector v;273  {274    C c = C(v);275  }276  // 0. Construct variable 'c' (copy/move elided).277  // 1. Destroy variable 'c'.278  clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}279  clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}280}281 282void f2() {283  AddressVector v;284  {285    const C &c = C::make(v);286  }287  // 0. Construct the return value of make() (copy/move elided) and288  //    lifetime-extend it directly via reference 'c',289  // 1. Destroy the temporary lifetime-extended by 'c'.290  clang_analyzer_eval(v.len == 2);291  clang_analyzer_eval(v.buf[0] == v.buf[1]);292#ifdef TEMPORARIES293  // expected-warning@-3{{TRUE}}294  // expected-warning@-3{{TRUE}}295#else296  // expected-warning@-6{{UNKNOWN}}297  // expected-warning@-6{{UNKNOWN}}298#endif299}300 301void f3() {302  AddressVector v;303  {304    C &&c = C::make(v);305  }306  // 0. Construct the return value of make() (copy/move elided) and307  //    lifetime-extend it directly via reference 'c',308  // 1. Destroy the temporary lifetime-extended by 'c'.309  clang_analyzer_eval(v.len == 2);310  clang_analyzer_eval(v.buf[0] == v.buf[1]);311#ifdef TEMPORARIES312  // expected-warning@-3{{TRUE}}313  // expected-warning@-3{{TRUE}}314#else315  // expected-warning@-6{{UNKNOWN}}316  // expected-warning@-6{{UNKNOWN}}317#endif318}319 320C doubleMake(AddressVector &v) {321  return C::make(v);322}323 324void f4() {325  AddressVector v;326  {327    C c = doubleMake(v);328  }329  // 0. Construct variable 'c' (all copies/moves elided),330  // 1. Destroy variable 'c'.331  clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}332  clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}333}334} // end namespace maintain_address_of_copies335