Re: C++ PATCH for c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr

2019-12-29 Thread Marek Polacek
On Sat, Dec 21, 2019 at 04:50:41PM -0500, Jason Merrill wrote:
> On 12/17/19 5:34 PM, Marek Polacek wrote:
> > +  /* [class.cdtor]/6 "If the operand of the dynamic_cast refers to
> > + the object under construction or destruction and the static type
> > + of the operand is not a pointer to or object of the constructor
> > + or destructor's own class or one of its bases, the dynamic_cast
> > + results in undefined behavior."  And undefined behavior should be
> > + detected in constexpr contexts.  */
> > +  if (!same_type_ignoring_top_level_qualifiers_p (mdtype, complete_type))
> > +{
> > +  unsigned ix;
> > +  FOR_EACH_VEC_ELT_REVERSE (call_stack, ix, t)
> > +   if (tree fn = cp_get_callee_fndecl_nofold (t))
> > + if (DECL_CONSTRUCTOR_P (fn))
> > +   {
> > + /* Get *this of the current constructor.  */
> > + tree cdtor_type = initialized_type (t);
> > + if (!DERIVED_FROM_P (objtype, cdtor_type))
> 
> Walking the call_stack is an interesting idea, since ctx only has the
> innermost call, which might not be the relevant constructor.  And the
> innermost call might not even have a pointer to the object under
> construction.

Exactly.

> But this only finds that there is an object under construction, not whether
> obj is part of the same object.  

That is true also.  :/

> It should be possible to construct a
> testcase where we start constructing one object X, and then pass a pointer
> to X to the constructor for Y; doing a dynamic_cast of the X pointer
> shouldn't give an error just because it isn't a base of Y, since the X
> pointer points to the X under construction, not the Y under construction.
> 
> Something like
> 
> struct X;
> struct Y {
>   virtual void f();
>   Y(X* x) { dynamic_cast(x); } // returns NULL
> };
> struct X
> {
>   virtual void f();
>   X() { Y(this); }
> };
> struct Z: X
> {
>   virtual void f();
> } z;
> 
> Note that in constexpr-dynamic17.C, if you reverse the order of "D: A, B" to
> "D: B, A", we hit undefined behavior in the cast because the A vptr isn't
> set yet (though the diagnostic could be better).  A better way to detect
> this undefined behavior for the A, B case might be to clear the vptrs for A
> after we're done constructing it; the most derived constructor will set them
> again once base constructors are done.  This could happen either in
> emit_mem_initializers or in cxx_expand_call_expression.
> 
> But I think let's leave that for a follow-on patch.  Let's drop this hunk
> and reverse the bases in constexpr-dynamic17.C as I mentioned above so we
> still get an error.  OK with that change.

Agreed; I've opened PR93096.  Here's what I've committed after another
bootstrap/regtest:

commit 9d3f24adb6d09184fd348ef8d92e6d0b965e3f00
Author: mpolacek 
Date:   Sun Dec 29 16:44:41 2019 +

PR c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr.

This patch implements
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1327r1.html>.

When build_dynamic_cast realizes that a dynamic_cast needs a run-time 
check, it
generates a call to __dynamic_cast -- see dyncast.cc in libsupc++ for its
definition.  The gist of my approach is to evaluate such a call at compile 
time.

* constexpr.c (cxx_dynamic_cast_fn_p): New function.
(extract_obj_from_addr_offset): New function.
(get_component_with_type): New function.
(cxx_eval_dynamic_cast_fn): New function.
(cxx_eval_call_expression): Call cxx_eval_dynamic_cast_fn for a call
to __dynamic_cast.
(potential_constant_expression_1): Don't give up on
cxx_dynamic_cast_fn_p.
* rtti.c (build_dynamic_cast_1): When creating a call to
__dynamic_cast, use the location of the original expression.

* g++.dg/cpp2a/constexpr-dynamic1.C: New test.
* g++.dg/cpp2a/constexpr-dynamic10.C: New test.
* g++.dg/cpp2a/constexpr-dynamic11.C: New test.
* g++.dg/cpp2a/constexpr-dynamic12.C: New test.
* g++.dg/cpp2a/constexpr-dynamic13.C: New test.
* g++.dg/cpp2a/constexpr-dynamic14.C: New test.
* g++.dg/cpp2a/constexpr-dynamic15.C: New test.
* g++.dg/cpp2a/constexpr-dynamic16.C: New test.
* g++.dg/cpp2a/constexpr-dynamic17.C: New test.
* g++.dg/cpp2a/constexpr-dynamic2.C: New test.
* g++.dg/cpp2a/constexpr-dynamic3.C: New test.
* g++.dg/cpp2a/constexpr-dynamic4.C: New test.
* g++.dg/cpp2a/constexpr-dynamic5.C: New test.
* g++.dg/cpp2a/constexpr-dynamic6.C: New test.
* g++.dg/cpp2a/cons

Re: C++ PATCH for c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr

2019-12-21 Thread Jason Merrill

On 12/17/19 5:34 PM, Marek Polacek wrote:

On Mon, Dec 16, 2019 at 04:00:14PM -0500, Jason Merrill wrote:

On 12/16/19 3:55 PM, Jason Merrill wrote:

On 12/14/19 4:25 PM, Marek Polacek wrote:

On Fri, Dec 13, 2019 at 05:56:57PM -0500, Jason Merrill wrote:

On 12/13/19 3:20 PM, Marek Polacek wrote:

+  /* Given dynamic_cast(v),
+
+ [expr.dynamic.cast] If C is the class type to which T
points or refers,
+ the runtime check logically executes as follows:
+
+ If, in the most derived object pointed (referred) to
by v, v points
+ (refers) to a public base class subobject of a C
object, and if only
+ one object of type C is derived from the subobject
pointed (referred)
+ to by v the result points (refers) to that C object.
+
+ In this case, HINT >= 0.  */
+  if (hint >= 0)


Won't this code work for hint == -3 as well?


Yes, it does.  In fact, none of the tests was testing the hint == -3
case, so
I've fixed the code up and added constexpr-dynamic15.C to test it.


+    {
+  /* Look for a component with type TYPE.  */
+  obj = get_component_with_type (obj, type);


You don't seem to use mdtype at all in this case.  Shouldn't
get_component_with_type stop at mdtype if it hasn't found type yet?


It was used for diagnostics but not in get_component_with_type.  It makes
sense to stop at MDTYPE; I've adjusted the code to do so.  E.g., if
we have OBJ in the form of g.D.2121.D.2122.D.2123.D.2124, usually the
component with the most derived type is "g", but in a 'tor, it can be
a different component too.


+  /* If not found or not accessible, give an error.  */
+  if (obj == NULL_TREE || obj == error_mark_node)
+    {
+  if (reference_p)
+    {
+  if (!ctx->quiet)
+    {
+  error_at (loc, "reference % failed");
+  if (obj == NULL_TREE)
+    inform (loc, "dynamic type %qT of its operand does not "
+    "have an unambiguous public base class %qT",
+    mdtype, type);
+  else
+    inform (loc, "static type %qT of its operand is a "
+    "non-public base class of dynamic type %qT",
+    objtype, type);
+
+    }
+  *non_constant_p = true;
+    }
+  return integer_zero_node;
+    }
+  else
+    /* The result points to the TYPE object.  */
+    return cp_build_addr_expr (obj, complain);
+    }
+  /* Otherwise, if v points (refers) to a public base class
subobject of the
+ most derived object, and the type of the most derived
object has a base
+ class, of type C, that is unambiguous and public, the
result points
+ (refers) to the C subobject of the most derived object.
+
+ But it can also be an invalid case.  */


And I think we need to fall through to this code if the hint
turns out to be
wrong, i.e. V is a public base of C, but v is not that
subobject, but rather
a sibling base of C, like


True.  HINT is really just an optimization hint, nothing more.  I've
adjusted
the code to fall through to the normal processing if the HINT >= 0
or -3 case
doesn't succeed.


struct A { virtual void f(); };
struct B1: A { };
struct B2: A { };
struct C: B1, B2 { };
int main()
{
    C c;
    A* ap = (B1*)c;
    constexpr auto p = dynamic_cast(ap); // should succeed
}


Whew, there's always One More Case. :/  New constexpr-dynamic16.c
covers it.


--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic11.C
@@ -0,0 +1,34 @@
+// PR c++/88337 - Implement P1327R1: Allow
dynamic_cast/typeid in constexpr.
+// { dg-do compile { target c++2a } }
+
+// dynamic_cast in a constructor.
+
+struct V {
+  virtual void f();
+};
+
+struct A : V { };
+
+struct B : V {
+  constexpr B(V*, A*);
+};
+
+struct D : A, B {
+  constexpr D() : B((A*)this, this) { } // { dg-message "in
'constexpr' expansion of" }
+};
+
+constexpr B::B(V* v, A* a)
+{
+  // well-defined: v of type V*, V base of B results in B*
+  B* b = dynamic_cast(v);
+  if (b != nullptr)
+    __builtin_abort ();
+
+  B& br = dynamic_cast(*v); // { dg-error "reference
.dynamic_cast. failed" }
+// { dg-message "dynamic type .A. of its operand does not
have an unambiguous public base class .B." "" { target *-*-*
} .-1 }
+
+  // FIXME: UB in constexpr should be detected.
+  dynamic_cast(a);  // undefined behavior, a
has type A*, A not a base of B


What undefined behavior?  Seems to me the dynamic_cast should
just fail and
return a null pointer.


This is :
"If the operand of the dynamic_cast refers to the object under
construction
or destruction and the static type of the operand is not a pointer to or
object of the constructor or destructor's own class or one of its
bases, the
dynamic_cast results in undefined behavior."

Clang++ doesn't detect this either.


Ah, interesting.  That text goes back to C++98.  I guess the reason for
that was that the vtable pointer might give problematic answers in that
situation.  It should be straightforward to detect 

Re: C++ PATCH for c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr

2019-12-17 Thread Marek Polacek
On Mon, Dec 16, 2019 at 04:00:14PM -0500, Jason Merrill wrote:
> On 12/16/19 3:55 PM, Jason Merrill wrote:
> > On 12/14/19 4:25 PM, Marek Polacek wrote:
> > > On Fri, Dec 13, 2019 at 05:56:57PM -0500, Jason Merrill wrote:
> > > > On 12/13/19 3:20 PM, Marek Polacek wrote:
> > > > > +  /* Given dynamic_cast(v),
> > > > > +
> > > > > + [expr.dynamic.cast] If C is the class type to which T
> > > > > points or refers,
> > > > > + the runtime check logically executes as follows:
> > > > > +
> > > > > + If, in the most derived object pointed (referred) to
> > > > > by v, v points
> > > > > + (refers) to a public base class subobject of a C
> > > > > object, and if only
> > > > > + one object of type C is derived from the subobject
> > > > > pointed (referred)
> > > > > + to by v the result points (refers) to that C object.
> > > > > +
> > > > > + In this case, HINT >= 0.  */
> > > > > +  if (hint >= 0)
> > > > 
> > > > Won't this code work for hint == -3 as well?
> > > 
> > > Yes, it does.  In fact, none of the tests was testing the hint == -3
> > > case, so
> > > I've fixed the code up and added constexpr-dynamic15.C to test it.
> > > 
> > > > > +    {
> > > > > +  /* Look for a component with type TYPE.  */
> > > > > +  obj = get_component_with_type (obj, type);
> > > > 
> > > > You don't seem to use mdtype at all in this case.  Shouldn't
> > > > get_component_with_type stop at mdtype if it hasn't found type yet?
> > > 
> > > It was used for diagnostics but not in get_component_with_type.  It makes
> > > sense to stop at MDTYPE; I've adjusted the code to do so.  E.g., if
> > > we have OBJ in the form of g.D.2121.D.2122.D.2123.D.2124, usually the
> > > component with the most derived type is "g", but in a 'tor, it can be
> > > a different component too.
> > > 
> > > > > +  /* If not found or not accessible, give an error.  */
> > > > > +  if (obj == NULL_TREE || obj == error_mark_node)
> > > > > +    {
> > > > > +  if (reference_p)
> > > > > +    {
> > > > > +  if (!ctx->quiet)
> > > > > +    {
> > > > > +  error_at (loc, "reference % failed");
> > > > > +  if (obj == NULL_TREE)
> > > > > +    inform (loc, "dynamic type %qT of its operand does not "
> > > > > +    "have an unambiguous public base class %qT",
> > > > > +    mdtype, type);
> > > > > +  else
> > > > > +    inform (loc, "static type %qT of its operand is a "
> > > > > +    "non-public base class of dynamic type %qT",
> > > > > +    objtype, type);
> > > > > +
> > > > > +    }
> > > > > +  *non_constant_p = true;
> > > > > +    }
> > > > > +  return integer_zero_node;
> > > > > +    }
> > > > > +  else
> > > > > +    /* The result points to the TYPE object.  */
> > > > > +    return cp_build_addr_expr (obj, complain);
> > > > > +    }
> > > > > +  /* Otherwise, if v points (refers) to a public base class
> > > > > subobject of the
> > > > > + most derived object, and the type of the most derived
> > > > > object has a base
> > > > > + class, of type C, that is unambiguous and public, the
> > > > > result points
> > > > > + (refers) to the C subobject of the most derived object.
> > > > > +
> > > > > + But it can also be an invalid case.  */
> > > > 
> > > > And I think we need to fall through to this code if the hint
> > > > turns out to be
> > > > wrong, i.e. V is a public base of C, but v is not that
> > > > subobject, but rather
> > > > a sibling base of C, like
> > > 
> > > True.  HINT is really just an optimization hint, nothing more.  I've
> > > adjusted
> > > the code to fall through to the normal processing if the HINT >= 0
> > > or -3 case
> > > doesn't succeed.
> > > 
> > > > struct A { virtual void f(); };
> > > > struct B1: A { };
> > > > struct B2: A { };
> > > > struct C: B1, B2 { };
> > > > int main()
> > > > {
> > > >    C c;
> > > >    A* ap = (B1*)c;
> > > >    constexpr auto p = dynamic_cast(ap); // should succeed
> > > > }
> > > 
> > > Whew, there's always One More Case. :/  New constexpr-dynamic16.c
> > > covers it.
> > > 
> > > > > --- /dev/null
> > > > > +++ gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic11.C
> > > > > @@ -0,0 +1,34 @@
> > > > > +// PR c++/88337 - Implement P1327R1: Allow
> > > > > dynamic_cast/typeid in constexpr.
> > > > > +// { dg-do compile { target c++2a } }
> > > > > +
> > > > > +// dynamic_cast in a constructor.
> > > > > +
> > > > > +struct V {
> > > > > +  virtual void f();
> > > > > +};
> > > > > +
> > > > > +struct A : V { };
> > > > > +
> > > > > +struct B : V {
> > > > > +  constexpr B(V*, A*);
> > > > > +};
> > > > > +
> > > > > +struct D : A, B {
> > > > > +  constexpr D() : B((A*)this, this) { } // { dg-message "in
> > > > > 'constexpr' expansion of" }
> > > > > +};
> > > > > +
> > > > > +constexpr B::B(V* v, A* a)
> > > > > +{
> > > > > +  // well-defined: v of type V*, V base of B results in B*
> > > > > +  

Re: C++ PATCH for c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr

2019-12-16 Thread Jason Merrill

On 12/16/19 3:55 PM, Jason Merrill wrote:

On 12/14/19 4:25 PM, Marek Polacek wrote:

On Fri, Dec 13, 2019 at 05:56:57PM -0500, Jason Merrill wrote:

On 12/13/19 3:20 PM, Marek Polacek wrote:

+  /* Given dynamic_cast(v),
+
+ [expr.dynamic.cast] If C is the class type to which T points 
or refers,

+ the runtime check logically executes as follows:
+
+ If, in the most derived object pointed (referred) to by v, v 
points
+ (refers) to a public base class subobject of a C object, and 
if only
+ one object of type C is derived from the subobject pointed 
(referred)

+ to by v the result points (refers) to that C object.
+
+ In this case, HINT >= 0.  */
+  if (hint >= 0)


Won't this code work for hint == -3 as well?


Yes, it does.  In fact, none of the tests was testing the hint == -3 
case, so

I've fixed the code up and added constexpr-dynamic15.C to test it.


+    {
+  /* Look for a component with type TYPE.  */
+  obj = get_component_with_type (obj, type);


You don't seem to use mdtype at all in this case.  Shouldn't
get_component_with_type stop at mdtype if it hasn't found type yet?


It was used for diagnostics but not in get_component_with_type.  It makes
sense to stop at MDTYPE; I've adjusted the code to do so.  E.g., if
we have OBJ in the form of g.D.2121.D.2122.D.2123.D.2124, usually the
component with the most derived type is "g", but in a 'tor, it can be
a different component too.


+  /* If not found or not accessible, give an error.  */
+  if (obj == NULL_TREE || obj == error_mark_node)
+    {
+  if (reference_p)
+    {
+  if (!ctx->quiet)
+    {
+  error_at (loc, "reference % failed");
+  if (obj == NULL_TREE)
+    inform (loc, "dynamic type %qT of its operand does not "
+    "have an unambiguous public base class %qT",
+    mdtype, type);
+  else
+    inform (loc, "static type %qT of its operand is a "
+    "non-public base class of dynamic type %qT",
+    objtype, type);
+
+    }
+  *non_constant_p = true;
+    }
+  return integer_zero_node;
+    }
+  else
+    /* The result points to the TYPE object.  */
+    return cp_build_addr_expr (obj, complain);
+    }
+  /* Otherwise, if v points (refers) to a public base class 
subobject of the
+ most derived object, and the type of the most derived object 
has a base
+ class, of type C, that is unambiguous and public, the result 
points

+ (refers) to the C subobject of the most derived object.
+
+ But it can also be an invalid case.  */


And I think we need to fall through to this code if the hint turns 
out to be
wrong, i.e. V is a public base of C, but v is not that subobject, but 
rather

a sibling base of C, like


True.  HINT is really just an optimization hint, nothing more.  I've 
adjusted
the code to fall through to the normal processing if the HINT >= 0 or 
-3 case

doesn't succeed.


struct A { virtual void f(); };
struct B1: A { };
struct B2: A { };
struct C: B1, B2 { };
int main()
{
   C c;
   A* ap = (B1*)c;
   constexpr auto p = dynamic_cast(ap); // should succeed
}


Whew, there's always One More Case. :/  New constexpr-dynamic16.c 
covers it.



--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic11.C
@@ -0,0 +1,34 @@
+// PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in 
constexpr.

+// { dg-do compile { target c++2a } }
+
+// dynamic_cast in a constructor.
+
+struct V {
+  virtual void f();
+};
+
+struct A : V { };
+
+struct B : V {
+  constexpr B(V*, A*);
+};
+
+struct D : A, B {
+  constexpr D() : B((A*)this, this) { } // { dg-message "in 
'constexpr' expansion of" }

+};
+
+constexpr B::B(V* v, A* a)
+{
+  // well-defined: v of type V*, V base of B results in B*
+  B* b = dynamic_cast(v);
+  if (b != nullptr)
+    __builtin_abort ();
+
+  B& br = dynamic_cast(*v); // { dg-error "reference 
.dynamic_cast. failed" }
+// { dg-message "dynamic type .A. of its operand does not have an 
unambiguous public base class .B." "" { target *-*-* } .-1 }

+
+  // FIXME: UB in constexpr should be detected.
+  dynamic_cast(a);  // undefined behavior, a has type 
A*, A not a base of B


What undefined behavior?  Seems to me the dynamic_cast should just 
fail and

return a null pointer.


This is :
"If the operand of the dynamic_cast refers to the object under 
construction

or destruction and the static type of the operand is not a pointer to or
object of the constructor or destructor's own class or one of its 
bases, the

dynamic_cast results in undefined behavior."

Clang++ doesn't detect this either.


Ah, interesting.  That text goes back to C++98.  I guess the reason for 
that was that the vtable pointer might give problematic answers in that 
situation.  It should be straightforward to detect this in constexpr 
evaluation; if mdtype is not the actual complete 

Re: C++ PATCH for c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr

2019-12-16 Thread Jason Merrill

On 12/14/19 4:25 PM, Marek Polacek wrote:

On Fri, Dec 13, 2019 at 05:56:57PM -0500, Jason Merrill wrote:

On 12/13/19 3:20 PM, Marek Polacek wrote:

+  /* Given dynamic_cast(v),
+
+ [expr.dynamic.cast] If C is the class type to which T points or refers,
+ the runtime check logically executes as follows:
+
+ If, in the most derived object pointed (referred) to by v, v points
+ (refers) to a public base class subobject of a C object, and if only
+ one object of type C is derived from the subobject pointed (referred)
+ to by v the result points (refers) to that C object.
+
+ In this case, HINT >= 0.  */
+  if (hint >= 0)


Won't this code work for hint == -3 as well?


Yes, it does.  In fact, none of the tests was testing the hint == -3 case, so
I've fixed the code up and added constexpr-dynamic15.C to test it.


+{
+  /* Look for a component with type TYPE.  */
+  obj = get_component_with_type (obj, type);


You don't seem to use mdtype at all in this case.  Shouldn't
get_component_with_type stop at mdtype if it hasn't found type yet?


It was used for diagnostics but not in get_component_with_type.  It makes
sense to stop at MDTYPE; I've adjusted the code to do so.  E.g., if
we have OBJ in the form of g.D.2121.D.2122.D.2123.D.2124, usually the
component with the most derived type is "g", but in a 'tor, it can be
a different component too.


+  /* If not found or not accessible, give an error.  */
+  if (obj == NULL_TREE || obj == error_mark_node)
+   {
+ if (reference_p)
+   {
+ if (!ctx->quiet)
+   {
+ error_at (loc, "reference % failed");
+ if (obj == NULL_TREE)
+   inform (loc, "dynamic type %qT of its operand does not "
+   "have an unambiguous public base class %qT",
+   mdtype, type);
+ else
+   inform (loc, "static type %qT of its operand is a "
+   "non-public base class of dynamic type %qT",
+   objtype, type);
+
+   }
+ *non_constant_p = true;
+   }
+ return integer_zero_node;
+   }
+  else
+   /* The result points to the TYPE object.  */
+   return cp_build_addr_expr (obj, complain);
+}
+  /* Otherwise, if v points (refers) to a public base class subobject of the
+ most derived object, and the type of the most derived object has a base
+ class, of type C, that is unambiguous and public, the result points
+ (refers) to the C subobject of the most derived object.
+
+ But it can also be an invalid case.  */


And I think we need to fall through to this code if the hint turns out to be
wrong, i.e. V is a public base of C, but v is not that subobject, but rather
a sibling base of C, like


True.  HINT is really just an optimization hint, nothing more.  I've adjusted
the code to fall through to the normal processing if the HINT >= 0 or -3 case
doesn't succeed.


struct A { virtual void f(); };
struct B1: A { };
struct B2: A { };
struct C: B1, B2 { };
int main()
{
   C c;
   A* ap = (B1*)c;
   constexpr auto p = dynamic_cast(ap); // should succeed
}


Whew, there's always One More Case. :/  New constexpr-dynamic16.c covers it.


--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic11.C
@@ -0,0 +1,34 @@
+// PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in constexpr.
+// { dg-do compile { target c++2a } }
+
+// dynamic_cast in a constructor.
+
+struct V {
+  virtual void f();
+};
+
+struct A : V { };
+
+struct B : V {
+  constexpr B(V*, A*);
+};
+
+struct D : A, B {
+  constexpr D() : B((A*)this, this) { } // { dg-message "in 'constexpr' expansion 
of" }
+};
+
+constexpr B::B(V* v, A* a)
+{
+  // well-defined: v of type V*, V base of B results in B*
+  B* b = dynamic_cast(v);
+  if (b != nullptr)
+__builtin_abort ();
+
+  B& br = dynamic_cast(*v); // { dg-error "reference .dynamic_cast. 
failed" }
+// { dg-message "dynamic type .A. of its operand does not have an unambiguous public base 
class .B." "" { target *-*-* } .-1 }
+
+  // FIXME: UB in constexpr should be detected.
+  dynamic_cast(a);  // undefined behavior, a has type A*, A not a 
base of B


What undefined behavior?  Seems to me the dynamic_cast should just fail and
return a null pointer.


This is :
"If the operand of the dynamic_cast refers to the object under construction
or destruction and the static type of the operand is not a pointer to or
object of the constructor or destructor's own class or one of its bases, the
dynamic_cast results in undefined behavior."

Clang++ doesn't detect this either.


Ah, interesting.  That text goes back to C++98.  I guess the reason for 
that was that the vtable pointer might give problematic answers in that 
situation.  It should be straightforward to detect this in constexpr 

Re: C++ PATCH for c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr

2019-12-14 Thread Marek Polacek
On Fri, Dec 13, 2019 at 05:56:57PM -0500, Jason Merrill wrote:
> On 12/13/19 3:20 PM, Marek Polacek wrote:
> > +  /* Given dynamic_cast(v),
> > +
> > + [expr.dynamic.cast] If C is the class type to which T points or 
> > refers,
> > + the runtime check logically executes as follows:
> > +
> > + If, in the most derived object pointed (referred) to by v, v points
> > + (refers) to a public base class subobject of a C object, and if only
> > + one object of type C is derived from the subobject pointed (referred)
> > + to by v the result points (refers) to that C object.
> > +
> > + In this case, HINT >= 0.  */
> > +  if (hint >= 0)
> 
> Won't this code work for hint == -3 as well?

Yes, it does.  In fact, none of the tests was testing the hint == -3 case, so
I've fixed the code up and added constexpr-dynamic15.C to test it.

> > +{
> > +  /* Look for a component with type TYPE.  */
> > +  obj = get_component_with_type (obj, type);
> 
> You don't seem to use mdtype at all in this case.  Shouldn't
> get_component_with_type stop at mdtype if it hasn't found type yet?

It was used for diagnostics but not in get_component_with_type.  It makes
sense to stop at MDTYPE; I've adjusted the code to do so.  E.g., if
we have OBJ in the form of g.D.2121.D.2122.D.2123.D.2124, usually the
component with the most derived type is "g", but in a 'tor, it can be
a different component too.

> > +  /* If not found or not accessible, give an error.  */
> > +  if (obj == NULL_TREE || obj == error_mark_node)
> > +   {
> > + if (reference_p)
> > +   {
> > + if (!ctx->quiet)
> > +   {
> > + error_at (loc, "reference % failed");
> > + if (obj == NULL_TREE)
> > +   inform (loc, "dynamic type %qT of its operand does not "
> > +   "have an unambiguous public base class %qT",
> > +   mdtype, type);
> > + else
> > +   inform (loc, "static type %qT of its operand is a "
> > +   "non-public base class of dynamic type %qT",
> > +   objtype, type);
> > +
> > +   }
> > + *non_constant_p = true;
> > +   }
> > + return integer_zero_node;
> > +   }
> > +  else
> > +   /* The result points to the TYPE object.  */
> > +   return cp_build_addr_expr (obj, complain);
> > +}
> > +  /* Otherwise, if v points (refers) to a public base class subobject of 
> > the
> > + most derived object, and the type of the most derived object has a 
> > base
> > + class, of type C, that is unambiguous and public, the result points
> > + (refers) to the C subobject of the most derived object.
> > +
> > + But it can also be an invalid case.  */
> 
> And I think we need to fall through to this code if the hint turns out to be
> wrong, i.e. V is a public base of C, but v is not that subobject, but rather
> a sibling base of C, like

True.  HINT is really just an optimization hint, nothing more.  I've adjusted
the code to fall through to the normal processing if the HINT >= 0 or -3 case
doesn't succeed.

> struct A { virtual void f(); };
> struct B1: A { };
> struct B2: A { };
> struct C: B1, B2 { };
> int main()
> {
>   C c;
>   A* ap = (B1*)c;
>   constexpr auto p = dynamic_cast(ap); // should succeed
> }

Whew, there's always One More Case. :/  New constexpr-dynamic16.c covers it.

> > --- /dev/null
> > +++ gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic11.C
> > @@ -0,0 +1,34 @@
> > +// PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in 
> > constexpr.
> > +// { dg-do compile { target c++2a } }
> > +
> > +// dynamic_cast in a constructor.
> > +
> > +struct V {
> > +  virtual void f();
> > +};
> > +
> > +struct A : V { };
> > +
> > +struct B : V {
> > +  constexpr B(V*, A*);
> > +};
> > +
> > +struct D : A, B {
> > +  constexpr D() : B((A*)this, this) { } // { dg-message "in 'constexpr' 
> > expansion of" }
> > +};
> > +
> > +constexpr B::B(V* v, A* a)
> > +{
> > +  // well-defined: v of type V*, V base of B results in B*
> > +  B* b = dynamic_cast(v);
> > +  if (b != nullptr)
> > +__builtin_abort ();
> > +
> > +  B& br = dynamic_cast(*v); // { dg-error "reference .dynamic_cast. 
> > failed" }
> > +// { dg-message "dynamic type .A. of its operand does not have an 
> > unambiguous public base class .B." "" { target *-*-* } .-1 }
> > +
> > +  // FIXME: UB in constexpr should be detected.
> > +  dynamic_cast(a);  // undefined behavior, a has type A*, A 
> > not a base of B
> 
> What undefined behavior?  Seems to me the dynamic_cast should just fail and
> return a null pointer.

This is :
"If the operand of the dynamic_cast refers to the object under construction
or destruction and the static type of the operand is not a pointer to or
object of the constructor or destructor's own class or one of its bases, the
dynamic_cast results in undefined behavior."


Re: C++ PATCH for c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr

2019-12-13 Thread Jason Merrill

On 12/13/19 3:20 PM, Marek Polacek wrote:

On Thu, Dec 12, 2019 at 02:38:29PM -0500, Jason Merrill wrote:

On 12/11/19 5:50 PM, Marek Polacek wrote:

On Fri, Nov 22, 2019 at 04:11:53PM -0500, Jason Merrill wrote:

On 11/8/19 4:24 PM, Marek Polacek wrote:



2) [class.cdtor] says that when a dynamic_cast is used in a constructor or
destructor and the operand of the dynamic_cast refers to the object under
construction or destruction, this object is considered to be a most derived
object.


This means that during the 'tor the vtable pointer refers to the type_info
for that class and the offset-to-top is 0.  Can you use that?


I can't seem to: For e.g.

struct C : A, C2 { A *c = dynamic_cast(static_cast(this)); };

the object under construction is C, the call to __dynamic_cast will be
__dynamic_cast (SAVE_EXPR <&((struct C *) this)->D.2119>, &_ZTI2C2, &_ZTI1A, -2)
here, OBJ is f.D.2156.D.2119 and ctx->global->ctor_object is f.D.2156.  So OBJ
refers to the object under construction.

But I don't see C anywhere; CLASSTYPE_TYPEINFO_VAR of OBJTYPE is _ZTI2C2.

Am I looking into the wrong place?


Evaluating build_vfield_ref (obj, objtype) will give you the vtable pointer,
in this case &_ZTV1C + 40.  And then you can get C from DECL_CONTEXT
(_ZTV1C).

Or get_tinfo_decl_dynamic (obj) will give you the type_info.


Awesome, thanks a lot!  The following patch uses the first approach.  I've
also simplified the code somewhat.  constexpr-dynamic11.C was expanded a bit.

The error handling inflates the patch, but I'm not sure if a helper macro
would be preferable.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2019-12-13  Marek Polacek  

PR c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr.
* constexpr.c (cxx_dynamic_cast_fn_p): New function.
(extract_obj_from_addr_offset): New function.
(get_component_with_type): New function.
(cxx_eval_dynamic_cast_fn): New function.
(cxx_eval_call_expression): Call cxx_eval_dynamic_cast_fn for a call
to __dynamic_cast.
(potential_constant_expression_1): Don't give up on
cxx_dynamic_cast_fn_p.
* rtti.c (build_dynamic_cast_1): When creating a call to
__dynamic_cast, use the location of the original expression.

* g++.dg/cpp2a/constexpr-dynamic1.C: New test.
* g++.dg/cpp2a/constexpr-dynamic10.C: New test.
* g++.dg/cpp2a/constexpr-dynamic11.C: New test.
* g++.dg/cpp2a/constexpr-dynamic12.C: New test.
* g++.dg/cpp2a/constexpr-dynamic13.C: New test.
* g++.dg/cpp2a/constexpr-dynamic14.C: New test.
* g++.dg/cpp2a/constexpr-dynamic2.C: New test.
* g++.dg/cpp2a/constexpr-dynamic3.C: New test.
* g++.dg/cpp2a/constexpr-dynamic4.C: New test.
* g++.dg/cpp2a/constexpr-dynamic5.C: New test.
* g++.dg/cpp2a/constexpr-dynamic6.C: New test.
* g++.dg/cpp2a/constexpr-dynamic7.C: New test.
* g++.dg/cpp2a/constexpr-dynamic8.C: New test.
* g++.dg/cpp2a/constexpr-dynamic9.C: New test.

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 19e09c74760..1db9c9a96a4 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -1692,6 +1692,239 @@ is_std_allocator_allocate (tree fndecl)
return decl_in_std_namespace_p (decl);
  }
  
+/* Return true if FNDECL is __dynamic_cast.  */

+
+static inline bool
+cxx_dynamic_cast_fn_p (tree fndecl)
+{
+  return (cxx_dialect >= cxx2a
+ && id_equal (DECL_NAME (fndecl), "__dynamic_cast")
+ && CP_DECL_CONTEXT (fndecl) == global_namespace);
+}
+
+/* Often, we have an expression in the form of address + offset, e.g.
+   "&_ZTV1A + 16".  Extract the object from it, i.e. "_ZTV1A".  */
+
+static tree
+extract_obj_from_addr_offset (tree expr)
+{
+  if (TREE_CODE (expr) == POINTER_PLUS_EXPR)
+expr = TREE_OPERAND (expr, 0);
+  STRIP_NOPS (expr);
+  if (TREE_CODE (expr) == ADDR_EXPR)
+expr = TREE_OPERAND (expr, 0);
+  return expr;
+}
+
+/* Given a PATH like
+
+ g.D.2181.D.2154.D.2102.D.2093
+
+   find a component with type TYPE.  Return NULL_TREE if not found, and
+   error_mark_node if the component is not accessible.  */
+
+static tree
+get_component_with_type (tree path, tree type)
+{
+  while (true)
+{
+  if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (path), type))
+   /* Found it.  */
+   return path;
+  else if (TREE_CODE (path) == COMPONENT_REF
+  && DECL_FIELD_IS_BASE (TREE_OPERAND (path, 1)))
+   {
+ /* We need to check that the component we're accessing is in fact
+accessible.  */
+ if (TREE_PRIVATE (TREE_OPERAND (path, 1))
+ || TREE_PROTECTED (TREE_OPERAND (path, 1)))
+   return error_mark_node;
+ path = TREE_OPERAND (path, 0);
+   }
+  else
+   return NULL_TREE;
+}
+}
+
+/* Evaluate a call to __dynamic_cast (permitted by P1327R1).
+
+   The declaration of __dynamic_cast is:
+
+   void* __dynamic_cast (const 

Re: C++ PATCH for c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr

2019-12-13 Thread Marek Polacek
On Thu, Dec 12, 2019 at 02:38:29PM -0500, Jason Merrill wrote:
> On 12/11/19 5:50 PM, Marek Polacek wrote:
> > On Fri, Nov 22, 2019 at 04:11:53PM -0500, Jason Merrill wrote:
> > > On 11/8/19 4:24 PM, Marek Polacek wrote:
> 
> > > > 2) [class.cdtor] says that when a dynamic_cast is used in a constructor 
> > > > or
> > > > destructor and the operand of the dynamic_cast refers to the object 
> > > > under
> > > > construction or destruction, this object is considered to be a most 
> > > > derived
> > > > object.
> > > 
> > > This means that during the 'tor the vtable pointer refers to the type_info
> > > for that class and the offset-to-top is 0.  Can you use that?
> > 
> > I can't seem to: For e.g.
> > 
> > struct C : A, C2 { A *c = dynamic_cast(static_cast(this)); };
> > 
> > the object under construction is C, the call to __dynamic_cast will be
> > __dynamic_cast (SAVE_EXPR <&((struct C *) this)->D.2119>, &_ZTI2C2, 
> > &_ZTI1A, -2)
> > here, OBJ is f.D.2156.D.2119 and ctx->global->ctor_object is f.D.2156.  So 
> > OBJ
> > refers to the object under construction.
> > 
> > But I don't see C anywhere; CLASSTYPE_TYPEINFO_VAR of OBJTYPE is _ZTI2C2.
> > 
> > Am I looking into the wrong place?
> 
> Evaluating build_vfield_ref (obj, objtype) will give you the vtable pointer,
> in this case &_ZTV1C + 40.  And then you can get C from DECL_CONTEXT
> (_ZTV1C).
> 
> Or get_tinfo_decl_dynamic (obj) will give you the type_info.

Awesome, thanks a lot!  The following patch uses the first approach.  I've
also simplified the code somewhat.  constexpr-dynamic11.C was expanded a bit.

The error handling inflates the patch, but I'm not sure if a helper macro
would be preferable.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2019-12-13  Marek Polacek  

PR c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr.
* constexpr.c (cxx_dynamic_cast_fn_p): New function.
(extract_obj_from_addr_offset): New function.
(get_component_with_type): New function.
(cxx_eval_dynamic_cast_fn): New function.
(cxx_eval_call_expression): Call cxx_eval_dynamic_cast_fn for a call
to __dynamic_cast.
(potential_constant_expression_1): Don't give up on
cxx_dynamic_cast_fn_p.
* rtti.c (build_dynamic_cast_1): When creating a call to
__dynamic_cast, use the location of the original expression.

* g++.dg/cpp2a/constexpr-dynamic1.C: New test.
* g++.dg/cpp2a/constexpr-dynamic10.C: New test.
* g++.dg/cpp2a/constexpr-dynamic11.C: New test.
* g++.dg/cpp2a/constexpr-dynamic12.C: New test.
* g++.dg/cpp2a/constexpr-dynamic13.C: New test.
* g++.dg/cpp2a/constexpr-dynamic14.C: New test.
* g++.dg/cpp2a/constexpr-dynamic2.C: New test.
* g++.dg/cpp2a/constexpr-dynamic3.C: New test.
* g++.dg/cpp2a/constexpr-dynamic4.C: New test.
* g++.dg/cpp2a/constexpr-dynamic5.C: New test.
* g++.dg/cpp2a/constexpr-dynamic6.C: New test.
* g++.dg/cpp2a/constexpr-dynamic7.C: New test.
* g++.dg/cpp2a/constexpr-dynamic8.C: New test.
* g++.dg/cpp2a/constexpr-dynamic9.C: New test.

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 19e09c74760..1db9c9a96a4 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -1692,6 +1692,239 @@ is_std_allocator_allocate (tree fndecl)
   return decl_in_std_namespace_p (decl);
 }
 
+/* Return true if FNDECL is __dynamic_cast.  */
+
+static inline bool
+cxx_dynamic_cast_fn_p (tree fndecl)
+{
+  return (cxx_dialect >= cxx2a
+ && id_equal (DECL_NAME (fndecl), "__dynamic_cast")
+ && CP_DECL_CONTEXT (fndecl) == global_namespace);
+}
+
+/* Often, we have an expression in the form of address + offset, e.g.
+   "&_ZTV1A + 16".  Extract the object from it, i.e. "_ZTV1A".  */
+
+static tree
+extract_obj_from_addr_offset (tree expr)
+{
+  if (TREE_CODE (expr) == POINTER_PLUS_EXPR)
+expr = TREE_OPERAND (expr, 0);
+  STRIP_NOPS (expr);
+  if (TREE_CODE (expr) == ADDR_EXPR)
+expr = TREE_OPERAND (expr, 0);
+  return expr;
+}
+
+/* Given a PATH like
+
+ g.D.2181.D.2154.D.2102.D.2093
+
+   find a component with type TYPE.  Return NULL_TREE if not found, and
+   error_mark_node if the component is not accessible.  */
+
+static tree
+get_component_with_type (tree path, tree type)
+{
+  while (true)
+{
+  if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (path), type))
+   /* Found it.  */
+   return path;
+  else if (TREE_CODE (path) == COMPONENT_REF
+  && DECL_FIELD_IS_BASE (TREE_OPERAND (path, 1)))
+   {
+ /* We need to check that the component we're accessing is in fact
+accessible.  */
+ if (TREE_PRIVATE (TREE_OPERAND (path, 1))
+ || TREE_PROTECTED (TREE_OPERAND (path, 1)))
+   return error_mark_node;
+ path = TREE_OPERAND (path, 0);
+   }
+  else
+   return NULL_TREE;
+}
+}
+
+/* Evaluate a call to 

Re: C++ PATCH for c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr

2019-12-12 Thread Jason Merrill

On 12/11/19 5:50 PM, Marek Polacek wrote:

On Fri, Nov 22, 2019 at 04:11:53PM -0500, Jason Merrill wrote:

On 11/8/19 4:24 PM, Marek Polacek wrote:



2) [class.cdtor] says that when a dynamic_cast is used in a constructor or
destructor and the operand of the dynamic_cast refers to the object under
construction or destruction, this object is considered to be a most derived
object.


This means that during the 'tor the vtable pointer refers to the type_info
for that class and the offset-to-top is 0.  Can you use that?


I can't seem to: For e.g.

struct C : A, C2 { A *c = dynamic_cast(static_cast(this)); };

the object under construction is C, the call to __dynamic_cast will be
__dynamic_cast (SAVE_EXPR <&((struct C *) this)->D.2119>, &_ZTI2C2, &_ZTI1A, -2)
here, OBJ is f.D.2156.D.2119 and ctx->global->ctor_object is f.D.2156.  So OBJ
refers to the object under construction.

But I don't see C anywhere; CLASSTYPE_TYPEINFO_VAR of OBJTYPE is _ZTI2C2.

Am I looking into the wrong place?


Evaluating build_vfield_ref (obj, objtype) will give you the vtable 
pointer, in this case &_ZTV1C + 40.  And then you can get C from 
DECL_CONTEXT (_ZTV1C).


Or get_tinfo_decl_dynamic (obj) will give you the type_info.

Jason



Re: C++ PATCH for c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr

2019-12-11 Thread Marek Polacek
On Fri, Nov 22, 2019 at 04:11:53PM -0500, Jason Merrill wrote:
> On 11/8/19 4:24 PM, Marek Polacek wrote:
> > After much weeping and gnashing of teeth, here's a patch to handle 
> > dynamic_cast
> > in constexpr evaluation.  While the change in the standard is trivial (see
> > ), the
> > change in the compiler is less so.
> > 
> > When build_dynamic_cast realizes that a dynamic_cast needs a run-time 
> > check, it
> > generates a call to __dynamic_cast -- see dyncast.cc in libsupc++ for its
> > definition.  The gist of my approach is to evaluate such a call at compile 
> > time.
> > 
> > This should be easy in theory: let the constexpr machinery find out the 
> > dynamic
> > type and then handle a sidecast and upcast.  That's ultimately what the 
> > patch
> > is trying to do but there was a number of hindrances.
> > 
> > 1) We can't use __dynamic_cast's type_info parameters, this type is not a
> > literal class.  But that means we have no idea what we're converting to!
> 
> get_tinfo_decl sets the TREE_TYPE of the DECL_NAME of the tinfo decl to the
> relevant type, can't you use that?

Yes, lovely.  I hadn't noticed that :(.

It doesn't say if this is a reference dynamic_cast or a pointer dynamic_cast,
so I checked OBJ to wheedle that information out of it.

> > 2) [class.cdtor] says that when a dynamic_cast is used in a constructor or
> > destructor and the operand of the dynamic_cast refers to the object under
> > construction or destruction, this object is considered to be a most derived
> > object.
> 
> This means that during the 'tor the vtable pointer refers to the type_info
> for that class and the offset-to-top is 0.  Can you use that?

I can't seem to: For e.g.

struct C : A, C2 { A *c = dynamic_cast(static_cast(this)); };

the object under construction is C, the call to __dynamic_cast will be
__dynamic_cast (SAVE_EXPR <&((struct C *) this)->D.2119>, &_ZTI2C2, &_ZTI1A, -2)
here, OBJ is f.D.2156.D.2119 and ctx->global->ctor_object is f.D.2156.  So OBJ
refers to the object under construction.

But I don't see C anywhere; CLASSTYPE_TYPEINFO_VAR of OBJTYPE is _ZTI2C2.

Am I looking into the wrong place?

> > +  /* Given dynamic_cast(v),
> > +
> > + [expr.dynamic.cast] If C is the class type to which T points or 
> > refers,
> > + the runtime check logically executes as follows:
> > +
> > + If, in the most derived object pointed (referred) to by v, v points
> > + (refers) to a public base class subobject of a C object, and if only
> > + one object of type C is derived from the subobject pointed (referred)
> > + to by v the result points (refers) to that C object.
> > +
> > + In this case, HINT >= 0.  This is a downcast.  */
> 
> Please avoid using up/down to refer to inheritance relationships, people
> disagree about what they mean.  :)

OK, dropped that terminology.

> > +  if (hint >= 0)
> > +{
> > +  /* We now have something like
> > +
> > + g.D.2181.D.2154.D.2102.D.2093
> > +^~
> > +OBJ
> > +
> > +and we're looking for a component with type TYPE.  */
> > +  tree objtype = TREE_TYPE (obj);
> > +  tree ctor_object = ctx->global->ctor_object;
> > +
> > +  for (;;)
> > +   {
> > + /* Unfortunately, we can't rely on HINT, we need to do some
> > +verification here:
> > +
> > +1) Consider
> > + dynamic_cast((A*)(B*)(D*));
> > +   and imagine that there's an accessible base A from E (so HINT
> > +   is >= 0), but it's a different A than where OBJ points to.
> > +   We need to check that the one we're accessing via E->D->B->A is
> > +   in fact accessible.  If e.g. B on this path is private, we gotta
> > +   fail.  So check that every base on the way can be reached from
> > +   the preceding class.
> > +
> > +2) Further, consider
> > +
> > +   struct A { virtual void a(); };
> > +   struct AA : A {};
> > +   struct B : A {};
> > +   struct Y : AA, private B {};
> > +
> > +   dynamic_cast((A*)(B*));
> > +
> > +   Here HINT is >=0, because A is a public unique base of Y,
> > +   but that's not the A accessed via Y->B->A.  */
> > + if (!accessible_base_p (TREE_TYPE (obj), objtype, false)
> > + || !accessible_base_p (type, TREE_TYPE (obj), false))
> > +   {
> > + if (reference_p)
> > +   {
> > + if (!ctx->quiet)
> > +   {
> > + error_at (loc, "reference % failed");
> > + inform (loc, "static type %qT of its operand is a "
> > + "non-public base class of dynamic type %qT",
> > + objtype, type);
> > +   }
> > + *non_constant_p = true;
> > +   }
> > + return integer_zero_node;
> > +   }
> > +
> > + if 

Re: C++ PATCH for c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr

2019-11-22 Thread Jason Merrill

On 11/8/19 4:24 PM, Marek Polacek wrote:

After much weeping and gnashing of teeth, here's a patch to handle dynamic_cast
in constexpr evaluation.  While the change in the standard is trivial (see
), the
change in the compiler is less so.

When build_dynamic_cast realizes that a dynamic_cast needs a run-time check, it
generates a call to __dynamic_cast -- see dyncast.cc in libsupc++ for its
definition.  The gist of my approach is to evaluate such a call at compile time.

This should be easy in theory: let the constexpr machinery find out the dynamic
type and then handle a sidecast and upcast.  That's ultimately what the patch
is trying to do but there was a number of hindrances.

1) We can't use __dynamic_cast's type_info parameters, this type is not a
literal class.  But that means we have no idea what we're converting to!


get_tinfo_decl sets the TREE_TYPE of the DECL_NAME of the tinfo decl to 
the relevant type, can't you use that?



2) [class.cdtor] says that when a dynamic_cast is used in a constructor or
destructor and the operand of the dynamic_cast refers to the object under
construction or destruction, this object is considered to be a most derived
object.


This means that during the 'tor the vtable pointer refers to the 
type_info for that class and the offset-to-top is 0.  Can you use that?



This was tricky, and the only thing that seemed to work was to add
a new member to constexpr_global_ctx.  I was happy to find out that I could
use new_obj I'd added recently.  Note that destruction is *not* handled at
all and in fact I couldn't even construct a testcase where that would make
a difference.



3) We can't rely on the hint __dynamic_cast gave us; the comment in
cxx_eval_dynamic_cast_fn explains why the accessible_base_p checks were
necessary.

There are many various scanarios regarding inheritance so special care was
devoted to test as much as possible, but testing the "dynamic_cast in
a constructor" could be expanded.

This patch doesn't handle polymorphic typeid yet.  I think it will be easier
to review to separate these two.  Hopefully the typeid part will be much
easier.

Bootstrapped/regtested on x86_64-linux.

2019-11-08  Marek Polacek  

PR c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr.
* call.c (is_base_field_ref): No longer static.
* constexpr.c (struct constexpr_global_ctx): Add ctor_object member
and initialize it.
(cxx_dynamic_cast_fn_p): New function.
(cxx_eval_dynamic_cast_fn): Likewise.
(cxx_eval_call_expression): Call cxx_eval_dynamic_cast_fn for a call
to __dynamic_cast.  Save the object a constexpr constructor is
constructing.
(cxx_eval_constant_expression) : Save the target
type of a call to __dynamic_cast.
(potential_constant_expression_1): Don't give up on
cxx_dynamic_cast_fn_p.
* cp-tree.h (is_base_field_ref): Declare.
* parser.c (cp_parser_postfix_expression): Set location of expression.
* rtti.c (build_dynamic_cast_1): When creating a call to
__dynamic_cast, use the location of the original expression.

* g++.dg/cpp2a/constexpr-dynamic1.C: New test.
* g++.dg/cpp2a/constexpr-dynamic10.C: New test.
* g++.dg/cpp2a/constexpr-dynamic11.C: New test.
* g++.dg/cpp2a/constexpr-dynamic12.C: New test.
* g++.dg/cpp2a/constexpr-dynamic13.C: New test.
* g++.dg/cpp2a/constexpr-dynamic14.C: New test.
* g++.dg/cpp2a/constexpr-dynamic2.C: New test.
* g++.dg/cpp2a/constexpr-dynamic3.C: New test.
* g++.dg/cpp2a/constexpr-dynamic4.C: New test.
* g++.dg/cpp2a/constexpr-dynamic5.C: New test.
* g++.dg/cpp2a/constexpr-dynamic6.C: New test.
* g++.dg/cpp2a/constexpr-dynamic7.C: New test.
* g++.dg/cpp2a/constexpr-dynamic8.C: New test.
* g++.dg/cpp2a/constexpr-dynamic9.C: New test.

diff --git gcc/cp/call.c gcc/cp/call.c
index 0034c1cee0d..5de2aca1358 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -8193,7 +8193,7 @@ call_copy_ctor (tree a, tsubst_flags_t complain)
  
  /* Return true iff T refers to a base field.  */
  
-static bool

+bool
  is_base_field_ref (tree t)
  {
STRIP_NOPS (t);
diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 20fddc57825..ef7706347bc 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -1025,8 +1025,11 @@ struct constexpr_global_ctx {
/* Heap VAR_DECLs created during the evaluation of the outermost constant
   expression.  */
auto_vec heap_vars;
+  /* For a constructor, this is the object we're constructing.  */
+  tree ctor_object;
/* Constructor.  */
-  constexpr_global_ctx () : constexpr_ops_count (0) {}
+  constexpr_global_ctx () : constexpr_ops_count (0), ctor_object (NULL_TREE)
+{}
  };
  
  /* The constexpr expansion context.  CALL is the current function

@@ -1663,6 +1666,244 @@ 

C++ PATCH for c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr

2019-11-08 Thread Marek Polacek
After much weeping and gnashing of teeth, here's a patch to handle dynamic_cast
in constexpr evaluation.  While the change in the standard is trivial (see
), the
change in the compiler is less so.

When build_dynamic_cast realizes that a dynamic_cast needs a run-time check, it
generates a call to __dynamic_cast -- see dyncast.cc in libsupc++ for its
definition.  The gist of my approach is to evaluate such a call at compile time.

This should be easy in theory: let the constexpr machinery find out the dynamic
type and then handle a sidecast and upcast.  That's ultimately what the patch
is trying to do but there was a number of hindrances.

1) We can't use __dynamic_cast's type_info parameters, this type is not a
literal class.  But that means we have no idea what we're converting to!
I noticed that build_dynamic_cast_1 will create a cast via cp_convert
to the target type for both pointer/reference dynamic_cast.  So we can save
this type to the constexpr values hash map under a magic key; I abused
dynamic_cast_node for this...

2) [class.cdtor] says that when a dynamic_cast is used in a constructor or
destructor and the operand of the dynamic_cast refers to the object under
construction or destruction, this object is considered to be a most derived
object.  This was tricky, and the only thing that seemed to work was to add
a new member to constexpr_global_ctx.  I was happy to find out that I could
use new_obj I'd added recently.  Note that destruction is *not* handled at
all and in fact I couldn't even construct a testcase where that would make
a difference.

3) We can't rely on the hint __dynamic_cast gave us; the comment in
cxx_eval_dynamic_cast_fn explains why the accessible_base_p checks were
necessary.

There are many various scanarios regarding inheritance so special care was
devoted to test as much as possible, but testing the "dynamic_cast in
a constructor" could be expanded. 

This patch doesn't handle polymorphic typeid yet.  I think it will be easier
to review to separate these two.  Hopefully the typeid part will be much
easier.

Bootstrapped/regtested on x86_64-linux.

2019-11-08  Marek Polacek  

PR c++/88337 - Implement P1327R1: Allow dynamic_cast in constexpr.
* call.c (is_base_field_ref): No longer static.
* constexpr.c (struct constexpr_global_ctx): Add ctor_object member
and initialize it.
(cxx_dynamic_cast_fn_p): New function.
(cxx_eval_dynamic_cast_fn): Likewise.
(cxx_eval_call_expression): Call cxx_eval_dynamic_cast_fn for a call
to __dynamic_cast.  Save the object a constexpr constructor is
constructing.
(cxx_eval_constant_expression) : Save the target
type of a call to __dynamic_cast.
(potential_constant_expression_1): Don't give up on
cxx_dynamic_cast_fn_p.
* cp-tree.h (is_base_field_ref): Declare.
* parser.c (cp_parser_postfix_expression): Set location of expression.
* rtti.c (build_dynamic_cast_1): When creating a call to
__dynamic_cast, use the location of the original expression.

* g++.dg/cpp2a/constexpr-dynamic1.C: New test.
* g++.dg/cpp2a/constexpr-dynamic10.C: New test.
* g++.dg/cpp2a/constexpr-dynamic11.C: New test.
* g++.dg/cpp2a/constexpr-dynamic12.C: New test.
* g++.dg/cpp2a/constexpr-dynamic13.C: New test.
* g++.dg/cpp2a/constexpr-dynamic14.C: New test.
* g++.dg/cpp2a/constexpr-dynamic2.C: New test.
* g++.dg/cpp2a/constexpr-dynamic3.C: New test.
* g++.dg/cpp2a/constexpr-dynamic4.C: New test.
* g++.dg/cpp2a/constexpr-dynamic5.C: New test.
* g++.dg/cpp2a/constexpr-dynamic6.C: New test.
* g++.dg/cpp2a/constexpr-dynamic7.C: New test.
* g++.dg/cpp2a/constexpr-dynamic8.C: New test.
* g++.dg/cpp2a/constexpr-dynamic9.C: New test.

diff --git gcc/cp/call.c gcc/cp/call.c
index 0034c1cee0d..5de2aca1358 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -8193,7 +8193,7 @@ call_copy_ctor (tree a, tsubst_flags_t complain)
 
 /* Return true iff T refers to a base field.  */
 
-static bool
+bool
 is_base_field_ref (tree t)
 {
   STRIP_NOPS (t);
diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 20fddc57825..ef7706347bc 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -1025,8 +1025,11 @@ struct constexpr_global_ctx {
   /* Heap VAR_DECLs created during the evaluation of the outermost constant
  expression.  */
   auto_vec heap_vars;
+  /* For a constructor, this is the object we're constructing.  */
+  tree ctor_object;
   /* Constructor.  */
-  constexpr_global_ctx () : constexpr_ops_count (0) {}
+  constexpr_global_ctx () : constexpr_ops_count (0), ctor_object (NULL_TREE)
+{}
 };
 
 /* The constexpr expansion context.  CALL is the current function
@@ -1663,6 +1666,244 @@ is_std_allocator_allocate (tree fndecl)
   return decl_in_std_namespace_p (decl);
 }