This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: PR 11687
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 6 Sep 2003 21:11:37 -0700
- Subject: C++ PATCH: PR 11687
- Reply-to: mark at codesourcery dot com
This patch fixes another regression introduced by my static_cast
rewrite. C++ says that there exists a conversion from a derived class
to an ambiguous class, but you aren't allowed to use it. Who knew?
Tested on i686-pc-linux-gnu, applied on the mainline and the branch.
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
2003-09-06 Mark Mitchell <mark@codesourcery.com>
PR c++/11687
* call.c (standard_conversion): Improve comments.
(perform_direct_initialization): Make sure we return an expression
of the correct type.
* typeck.c (build_static_cast): Check for ambiguity and
accessibility when performing conversions.
2003-09-06 Mark Mitchell <mark@codesourcery.com>
PR c++/11687
* g++.dg/expr/static_cast5.C: New test.
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.431
diff -c -5 -p -r1.431 call.c
*** cp/call.c 5 Sep 2003 18:04:15 -0000 1.431
--- cp/call.c 6 Sep 2003 05:09:42 -0000
*************** standard_conversion (tree to, tree from,
*** 699,718 ****
TYPE_PTRMEM_POINTED_TO_TYPE (from));
conv = build_conv (PMEM_CONV, from, conv);
}
}
else if (IS_AGGR_TYPE (TREE_TYPE (from))
! && IS_AGGR_TYPE (TREE_TYPE (to)))
! {
! if (DERIVED_FROM_P (TREE_TYPE (to), TREE_TYPE (from)))
! {
! from =
! cp_build_qualified_type (TREE_TYPE (to),
! cp_type_quals (TREE_TYPE (from)));
! from = build_pointer_type (from);
! conv = build_conv (PTR_CONV, from, conv);
! }
}
if (tcode == POINTER_TYPE)
{
to_pointee = TREE_TYPE (to);
--- 699,727 ----
TYPE_PTRMEM_POINTED_TO_TYPE (from));
conv = build_conv (PMEM_CONV, from, conv);
}
}
else if (IS_AGGR_TYPE (TREE_TYPE (from))
! && IS_AGGR_TYPE (TREE_TYPE (to))
! /* [conv.ptr]
!
! An rvalue of type "pointer to cv D," where D is a
! class type, can be converted to an rvalue of type
! "pointer to cv B," where B is a base class (clause
! _class.derived_) of D. If B is an inaccessible
! (clause _class.access_) or ambiguous
! (_class.member.lookup_) base class of D, a program
! that necessitates this conversion is ill-formed. */
! /* Therefore, we use DERIVED_FROM_P, and not
! ACESSIBLY_UNIQUELY_DERIVED_FROM_P, in this test. */
! && DERIVED_FROM_P (TREE_TYPE (to), TREE_TYPE (from)))
! {
! from =
! cp_build_qualified_type (TREE_TYPE (to),
! cp_type_quals (TREE_TYPE (from)));
! from = build_pointer_type (from);
! conv = build_conv (PTR_CONV, from, conv);
}
if (tcode == POINTER_TYPE)
{
to_pointee = TREE_TYPE (to);
*************** perform_direct_initialization_if_possibl
*** 5968,5981 ****
-- If the initialization is direct-initialization ...,
constructors are considered. ... If no constructor applies, or
the overload resolution is ambiguous, the initialization is
ill-formed. */
if (CLASS_TYPE_P (type))
! return build_special_member_call (NULL_TREE, complete_ctor_identifier,
! build_tree_list (NULL_TREE, expr),
! TYPE_BINFO (type),
! LOOKUP_NORMAL);
conv = implicit_conversion (type, TREE_TYPE (expr), expr,
LOOKUP_NORMAL);
if (!conv || ICS_BAD_FLAG (conv))
return NULL_TREE;
return convert_like_real (conv, expr, NULL_TREE, 0, 0,
--- 5977,5993 ----
-- If the initialization is direct-initialization ...,
constructors are considered. ... If no constructor applies, or
the overload resolution is ambiguous, the initialization is
ill-formed. */
if (CLASS_TYPE_P (type))
! {
! expr = build_special_member_call (NULL_TREE, complete_ctor_identifier,
! build_tree_list (NULL_TREE, expr),
! TYPE_BINFO (type),
! LOOKUP_NORMAL);
! return build_cplus_new (type, expr);
! }
conv = implicit_conversion (type, TREE_TYPE (expr), expr,
LOOKUP_NORMAL);
if (!conv || ICS_BAD_FLAG (conv))
return NULL_TREE;
return convert_like_real (conv, expr, NULL_TREE, 0, 0,
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.500
diff -c -5 -p -r1.500 typeck.c
*** cp/typeck.c 5 Sep 2003 08:24:23 -0000 1.500
--- cp/typeck.c 6 Sep 2003 05:09:45 -0000
*************** build_static_cast (tree type, tree expr)
*** 4425,4440 ****
&& can_convert (build_pointer_type (TYPE_MAIN_VARIANT (intype)),
build_pointer_type (TYPE_MAIN_VARIANT
(TREE_TYPE (type))))
&& at_least_as_qualified_p (TREE_TYPE (type), intype))
{
! /* At this point we have checked all of the conditions except
! that B is not a virtual base class of D. That will be
! checked by build_base_path. */
! tree base = lookup_base (TREE_TYPE (type), intype, ba_any, NULL);
! /* Convert from B* to D*. */
expr = build_base_path (MINUS_EXPR, build_address (expr),
base, /*nonnull=*/false);
/* Convert the pointer to a reference -- but then remember that
there are no expressions with reference type in C++. */
return convert_from_reference (build_nop (type, expr));
--- 4425,4441 ----
&& can_convert (build_pointer_type (TYPE_MAIN_VARIANT (intype)),
build_pointer_type (TYPE_MAIN_VARIANT
(TREE_TYPE (type))))
&& at_least_as_qualified_p (TREE_TYPE (type), intype))
{
! /* There is a standard conversion from "D*" to "B*" even if "B"
! is ambiguous or inaccessible. Therefore, we ask lookup_base
! to check these conditions. */
! tree base = lookup_base (TREE_TYPE (type), intype, ba_check, NULL);
! /* Convert from "B*" to "D*". This function will check that "B"
! is not a virtual base of "D". */
expr = build_base_path (MINUS_EXPR, build_address (expr),
base, /*nonnull=*/false);
/* Convert the pointer to a reference -- but then remember that
there are no expressions with reference type in C++. */
return convert_from_reference (build_nop (type, expr));
*************** build_static_cast (tree type, tree expr)
*** 4489,4500 ****
(TREE_TYPE (type)))))
{
tree base;
check_for_casting_away_constness (intype, type, "static_cast");
! base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
! ba_check | ba_quiet, NULL);
return build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false);
}
if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
--- 4490,4501 ----
(TREE_TYPE (type)))))
{
tree base;
check_for_casting_away_constness (intype, type, "static_cast");
! base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), ba_check,
! NULL);
return build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false);
}
if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
Index: testsuite/g++.dg/expr/static_cast5.C
===================================================================
RCS file: testsuite/g++.dg/expr/static_cast5.C
diff -N testsuite/g++.dg/expr/static_cast5.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/expr/static_cast5.C 7 Sep 2003 04:07:31 -0000
***************
*** 0 ****
--- 1,17 ----
+ void ambig()
+ {
+ struct A {};
+ struct B : A {};
+ struct C : A {};
+ struct D : B, C {};
+
+ D d;
+ A* ap = static_cast<B*> (&d);
+ D* db = static_cast<D*> (ap); // { dg-error "" }
+
+ D& dr1 = static_cast<D&> (*ap); // { dg-error "" }
+
+ A& ar = static_cast<C&> (d);
+ D& dr = static_cast<D&> (ar); // { dg-error "" }
+ }
+