Repository navigation
Constant evaluation of virtual calls to an overrider in a base class [GH #397] #415
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| [GH #397] | ||
| Constant evaluation of virtual calls to an overrider in a base class | ||
|
|
||
| During constant evaluation, a virtual function call whose final overrider is | ||
| a member of an intermediate base class (rather than of the most derived | ||
| class) was evaluated with the complete object as the object expression, | ||
| instead of the base class subobject of which the overrider is a member. For | ||
| example, with --c++20: | ||
|
|
||
| struct A { constexpr virtual int f() const { return 1; } int a = 1; }; | ||
| struct B : A { constexpr int f() const override { return a + 2; } }; | ||
| struct E { int e = 0; }; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If not required for the example, I'd remove |
||
| struct F : E, B {}; | ||
| constexpr int g() { F f; A& r = f; return r.f(); } | ||
| static_assert(g() == 3); // Previously failed. | ||
|
|
||
| This is now fixed. In addition, the adjustment of the result of a call to | ||
| an overrider with a covariant return type (e.g., from a pointer to a derived | ||
| class to a pointer to its base class) was computed incorrectly, and was | ||
| applied even to a null pointer result (which could cause the front end to | ||
| crash); this is also fixed. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| fe_only -DTEST_NUMBER=1 --g++ --c++20 Test_name.c | ||
| "Test_name.c", line 21: error: expression must have a constant value | ||
| constexpr int v = g(); // Error: null pointer argument (previously crashed). | ||
| ^ | ||
| "Test_name.c", line 19: note: attempt to dereference a null pointer | ||
| return __builtin_memcmp(rp.p(), (const X*)&s.z, sizeof(X)); | ||
| ^ | ||
|
|
||
| "Test_name.c", line 21: warning: variable "v" was declared but never referenced | ||
| constexpr int v = g(); // Error: null pointer argument (previously crashed). | ||
| ^ | ||
|
|
||
| 1 error detected in the compilation of "Test_name.c". |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| fe_only -DTEST_NUMBER=1 --c++20 Test_name.c |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| //type:fn | ||
| //options:--g++ --c++20 | ||
| //remark:[GH #397] Null pointer result of a covariant virtual call | ||
|
|
||
| struct E { int e = 0; }; | ||
| struct X { int x = 7; }; | ||
| struct Y { int y = 0; }; | ||
| struct Z : Y, X {}; | ||
| struct P { constexpr virtual const X* p() const { return nullptr; } }; | ||
| struct S : E, P { | ||
| Z z; | ||
| constexpr const Z* p() const override { return nullptr; } | ||
| }; | ||
| constexpr bool f() { S s; const P& rp = s; return rp.p() == nullptr; } | ||
| static_assert(f()); | ||
| constexpr int g() { | ||
| S s; | ||
| const P& rp = s; | ||
| return __builtin_memcmp(rp.p(), (const X*)&s.z, sizeof(X)); | ||
| } | ||
| constexpr int v = g(); // Error: null pointer argument (previously crashed). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| //type:fp | ||
| //options:--c++20 | ||
| //remark:[GH #397] Constant evaluation of a virtual call whose final overrider | ||
| //remark:is a member of an intermediate base class | ||
|
|
||
| struct A { constexpr virtual int f() const { return 1; } int a = 1; }; | ||
| struct B : A { constexpr int f() const override { return a + 2; } }; | ||
| struct E { int e = 0; }; | ||
| struct F : E, B {}; | ||
| constexpr int g() { F f; A& r = f; return r.f(); } | ||
| static_assert(g() == 3); // Previously failed. | ||
|
|
||
| struct G : B {}; | ||
| constexpr int h() { G g; A& r = g; return r.f(); } | ||
| static_assert(h() == 3); // Previously failed. | ||
|
|
||
| struct H : E, G { int x = 5; }; | ||
| constexpr int i() { H h; A& ra = h; B& rb = h; return ra.f() * 10 + rb.f(); } | ||
| static_assert(i() == 33); // Previously failed. | ||
|
|
||
| struct C : A {}; | ||
| constexpr int j() { C c; A& r = c; return r.f(); } | ||
| static_assert(j() == 1); | ||
|
|
||
| struct X { int x = 7; }; | ||
| struct Y { int y = 0; }; | ||
| struct Z : Y, X {}; | ||
| struct P { constexpr virtual const X* p() const { return nullptr; } }; | ||
| struct Q : P { Z z; constexpr const Z* p() const override { return &z; } }; | ||
| struct R : E, Q {}; | ||
| constexpr int k() { R r; const P& rp = r; return rp.p()->x; } | ||
| static_assert(k() == 7); | ||
| struct S : E, P { | ||
| Z z; | ||
| bool null; | ||
| constexpr S(bool b) : null(b) {} | ||
| constexpr const Z* p() const override { return null ? nullptr : &z; } | ||
| }; | ||
| constexpr bool l(bool b) { | ||
| S s(b); | ||
| const P& rp = s; | ||
| return b ? rp.p() == nullptr : rp.p() == (const X*)&s.z; | ||
| } | ||
| static_assert(l(false)); // Previously failed. | ||
| static_assert(l(true)); | ||
| struct W : Y, Z {}; | ||
| struct T : Q { W w; constexpr const W* p() const override { return &w; } }; | ||
| struct U : E, T {}; | ||
| constexpr bool m() { | ||
| U u; | ||
| const P& rp = u; | ||
| const Q& rq = u; | ||
| return rp.p() == (const X*)&u.w && rq.p() == (const Z*)&u.w && | ||
| rp.p()->x == 7; | ||
| } | ||
| static_assert(m()); // Previously failed. | ||
|
|
||
| // A covariant return type whose class is an indirect base class. | ||
| struct V : Y, Z {}; | ||
| struct VV : E, V {}; | ||
| struct I : P { VV vv; constexpr const VV* p() const override { return &vv; } }; | ||
| struct J : E, I {}; | ||
| constexpr bool n() { | ||
| J j; | ||
| const P& rp = j; | ||
| return rp.p() == (const X*)&j.vv && rp.p()->x == 7; | ||
| } | ||
| static_assert(n()); |
Uh oh!
There was an error while loading. Please reload this page.