Bug 93310 - Incorrect constexpr virtual evaluation inside a constructor
Summary: Incorrect constexpr virtual evaluation inside a constructor
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.2.1
: P3 normal
Target Milestone: 10.2
Assignee: Jason Merrill
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2020-01-17 15:04 UTC by Patrick Palka
Modified: 2020-12-09 14:03 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-01-17 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Patrick Palka 2020-01-17 15:04:59 UTC
The following testcase gets miscompiled on GCC 9 and on GCC 10 with -DUSE_CONSTEXPR due to (I believe) the constexpr virtual evaluation incorrectly resolving the dynamic type of ((A *)this) to C rather than B inside B's constructor.

$ cat virtual-2.cc
#if defined USE_CONSTEXPR
# define CONSTEXPR constexpr
#else
# define CONSTEXPR
#endif

struct A
{
  virtual CONSTEXPR char f () const
  { return 'A'; }
};

struct B : A
{
  char x;

  constexpr B () : x (0)
  { x = ((A *)this)->f(); }

  virtual CONSTEXPR char f () const
  { return 'B'; }
};

struct C : B
{
  virtual CONSTEXPR char f () const
  { return 'C'; }
};

int main ()
{
  CONSTEXPR C c;
  if (c.x != 'B')
    __builtin_abort ();
}
$ g++ -std=c++2a virtual-2.cc
$ ./a.out
$ g++ -std=c++2a virtual-2.cc -DUSE_CONSTEXPR
$ ./a.out
zsh: abort     ./a.out
Comment 1 Marek Polacek 2020-01-17 16:08:29 UTC
Confirmed.
Comment 2 GCC Commits 2020-06-04 19:11:54 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:7ece3bd8088983289731450826c238eb2bdd2db5

commit r11-955-g7ece3bd8088983289731450826c238eb2bdd2db5
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jun 3 23:50:50 2020 -0400

    c++: Fix complex constexpr virtual cases [PR93310].
    
    The code in constexpr for looking up the actual type of the object and then
    getting the virtual function from there broke for both of these tests: for
    16, it assumed incorrectly that the DECL_VINDEX would apply to the most
    derived type's vtable; for 17, it failed to consider that during
    construction the base subobject is treated as being of the base type.
    
    Fixed by just doing constant evaluation of the expression that looks up the
    function in the vtable.  This means that a virtual call will involve loading
    the vptr, so we will reject some calls through non-constexpr variables that
    we previously accepted, but this seems appropriate to me.  None of our
    testcases were affected.
    
    gcc/cp/ChangeLog:
    
            PR c++/93310
            * constexpr.c (cxx_eval_constant_expression) [OBJ_TYPE_REF]:
            Evaluate OBJ_TYPE_REF_EXPR.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/93310
            * g++.dg/cpp2a/constexpr-virtual16.C: New test.
            * g++.dg/cpp2a/constexpr-virtual17.C: New test.
            * g++.dg/cpp2a/constexpr-new12.C: Adjust diagnostic.
Comment 3 GCC Commits 2020-06-04 19:13:44 UTC
The releases/gcc-10 branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:6b45b400c51be06f2d0e37a7b461cbd4ce9fe37d

commit r10-8243-g6b45b400c51be06f2d0e37a7b461cbd4ce9fe37d
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jun 3 23:50:50 2020 -0400

    c++: Fix complex constexpr virtual cases [PR93310].
    
    The code in constexpr for looking up the actual type of the object and then
    getting the virtual function from there broke for both of these tests: for
    16, it assumed incorrectly that the DECL_VINDEX would apply to the most
    derived type's vtable; for 17, it failed to consider that during
    construction the base subobject is treated as being of the base type.
    
    Fixed by just doing constant evaluation of the expression that looks up the
    function in the vtable.  This means that a virtual call will involve loading
    the vptr, so we will reject some calls through non-constexpr variables that
    we previously accepted, but this seems appropriate to me.  None of our
    testcases were affected.
    
    gcc/cp/ChangeLog:
    
            PR c++/93310
            * constexpr.c (cxx_eval_constant_expression) [OBJ_TYPE_REF]:
            Evaluate OBJ_TYPE_REF_EXPR.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/93310
            * g++.dg/cpp2a/constexpr-virtual16.C: New test.
            * g++.dg/cpp2a/constexpr-virtual17.C: New test.
            * g++.dg/cpp2a/constexpr-new12.C: Adjust diagnostic.
Comment 4 Jason Merrill 2020-12-09 14:03:48 UTC
Fixed in 10.2/11.  I doubt anyone is still using GCC 9 for C++20 code.