| // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.ArrayDelete -std=c++11 -verify -analyzer-output=text %s | |
| struct Base { | |
| virtual ~Base() = default; | |
| }; | |
| struct Derived : public Base {}; | |
| struct DoubleDerived : public Derived {}; | |
| Derived *get(); | |
| Base *create() { | |
| Base *b = new Derived[3]; // expected-note{{Casting from 'Derived' to 'Base' here}} | |
| return b; | |
| } | |
| void sink(Base *b) { | |
| delete[] b; // expected-warning{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}} | |
| // expected-note@-1{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}} | |
| } | |
| void sink_cast(Base *b) { | |
| delete[] static_cast<Derived*>(b); // no-warning | |
| } | |
| void sink_derived(Derived *d) { | |
| delete[] d; // no-warning | |
| } | |
| void same_function() { | |
| Base *sd = new Derived[10]; // expected-note{{Casting from 'Derived' to 'Base' here}} | |
| delete[] sd; // expected-warning{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}} | |
| // expected-note@-1{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}} | |
| Base *dd = new DoubleDerived[10]; // expected-note{{Casting from 'DoubleDerived' to 'Base' here}} | |
| delete[] dd; // expected-warning{{Deleting an array of 'DoubleDerived' objects as their base class 'Base' is undefined}} | |
| // expected-note@-1{{Deleting an array of 'DoubleDerived' objects as their base class 'Base' is undefined}} | |
| } | |
| void different_function() { | |
| Base *assigned = get(); // expected-note{{Casting from 'Derived' to 'Base' here}} | |
| delete[] assigned; // expected-warning{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}} | |
| // expected-note@-1{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}} | |
| Base *indirect; | |
| indirect = get(); // expected-note{{Casting from 'Derived' to 'Base' here}} | |
| delete[] indirect; // expected-warning{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}} | |
| // expected-note@-1{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}} | |
| Base *created = create(); // expected-note{{Calling 'create'}} | |
| // expected-note@-1{{Returning from 'create'}} | |
| delete[] created; // expected-warning{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}} | |
| // expected-note@-1{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}} | |
| Base *sb = new Derived[10]; // expected-note{{Casting from 'Derived' to 'Base' here}} | |
| sink(sb); // expected-note{{Calling 'sink'}} | |
| } | |
| void safe_function() { | |
| Derived *d = new Derived[10]; | |
| delete[] d; // no-warning | |
| Base *b = new Derived[10]; | |
| delete[] static_cast<Derived*>(b); // no-warning | |
| Base *sb = new Derived[10]; | |
| sink_cast(sb); // no-warning | |
| Derived *sd = new Derived[10]; | |
| sink_derived(sd); // no-warning | |
| } | |
| void multiple_derived() { | |
| Base *b = new DoubleDerived[10]; // expected-note{{Casting from 'DoubleDerived' to 'Base' here}} | |
| delete[] b; // expected-warning{{Deleting an array of 'DoubleDerived' objects as their base class 'Base' is undefined}} | |
| // expected-note@-1{{Deleting an array of 'DoubleDerived' objects as their base class 'Base' is undefined}} | |
| Base *b2 = new DoubleDerived[10]; // expected-note{{Casting from 'DoubleDerived' to 'Base' here}} | |
| Derived *d2 = static_cast<Derived*>(b2); // expected-note{{Casting from 'Base' to 'Derived' here}} | |
| delete[] d2; // expected-warning{{Deleting an array of 'DoubleDerived' objects as their base class 'Derived' is undefined}} | |
| // expected-note@-1{{Deleting an array of 'DoubleDerived' objects as their base class 'Derived' is undefined}} | |
| Derived *d3 = new DoubleDerived[10]; // expected-note{{Casting from 'DoubleDerived' to 'Derived' here}} | |
| Base *b3 = d3; // expected-note{{Casting from 'Derived' to 'Base' here}} | |
| delete[] b3; // expected-warning{{Deleting an array of 'DoubleDerived' objects as their base class 'Base' is undefined}} | |
| // expected-note@-1{{Deleting an array of 'DoubleDerived' objects as their base class 'Base' is undefined}} | |
| Base *b4 = new DoubleDerived[10]; | |
| Derived *d4 = static_cast<Derived*>(b4); | |
| DoubleDerived *dd4 = static_cast<DoubleDerived*>(d4); | |
| delete[] dd4; // no-warning | |
| Base *b5 = new DoubleDerived[10]; // expected-note{{Casting from 'DoubleDerived' to 'Base' here}} | |
| DoubleDerived *dd5 = static_cast<DoubleDerived*>(b5); // expected-note{{Casting from 'Base' to 'DoubleDerived' here}} | |
| Derived *d5 = dd5; // expected-note{{Casting from 'DoubleDerived' to 'Derived' here}} | |
| delete[] d5; // expected-warning{{Deleting an array of 'DoubleDerived' objects as their base class 'Derived' is undefined}} | |
| // expected-note@-1{{Deleting an array of 'DoubleDerived' objects as their base class 'Derived' is undefined}} | |
| } | |
| void unrelated_casts() { | |
| Base *b = new DoubleDerived[10]; // expected-note{{Casting from 'DoubleDerived' to 'Base' here}} | |
| Base &b2 = *b; // no-note: See the FIXME. | |
| // FIXME: Displaying casts of reference types is not supported. | |
| Derived &d2 = static_cast<Derived&>(b2); // no-note: See the FIXME. | |
| Derived *d = &d2; // no-note: See the FIXME. | |
| delete[] d; // expected-warning{{Deleting an array of 'DoubleDerived' objects as their base class 'Derived' is undefined}} | |
| // expected-note@-1{{Deleting an array of 'DoubleDerived' objects as their base class 'Derived' is undefined}} | |
| } |