commit 1499daa7ea067fd905536a5ead1876107c8fbbc5
Author: Jason Merrill <jason@redhat.com>
Date: Wed Dec 21 13:42:30 2011 -0500
PR c++/51611
* cp-tree.h (CONVERT_EXPR_VBASE_PATH): New.
* class.c (build_base_path): Defer vbase conversion in an NSDMI.
* tree.c (bot_replace): Expand it here.
* cp-gimplify.c (cp_genericize_r): Make sure deferred conversion
doesn't leak into GENERIC.
@@ -318,6 +318,19 @@ build_base_path (enum tree_code code,
return expr;
}
+ /* If we're in an NSDMI, we don't have the full constructor context yet
+ that we need for converting to a virtual base, so just build a stub
+ CONVERT_EXPR and expand it later in bot_replace. */
+ if (virtual_access && fixed_type_p < 0
+ && current_scope () != current_function_decl)
+ {
+ expr = build1 (CONVERT_EXPR, ptr_target_type, expr);
+ CONVERT_EXPR_VBASE_PATH (expr) = true;
+ if (!want_pointer)
+ expr = build_indirect_ref (EXPR_LOCATION (expr), expr, RO_NULL);
+ return expr;
+ }
+
/* Do we need to check for a null pointer? */
if (want_pointer && !nonnull)
{
@@ -1100,6 +1100,8 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
wtd->omp_ctx = omp_ctx.outer;
splay_tree_delete (omp_ctx.variables);
}
+ else if (TREE_CODE (stmt) == CONVERT_EXPR)
+ gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt));
pointer_set_insert (p_set, *stmt_p);
@@ -74,6 +74,7 @@ c-common.h, not after.
DECL_OVERRIDE_P (in FUNCTION_DECL)
IMPLICIT_CONV_EXPR_DIRECT_INIT (in IMPLICIT_CONV_EXPR)
TRANSACTION_EXPR_IS_STMT (in TRANSACTION_EXPR)
+ CONVERT_EXPR_VBASE_PATH (in CONVERT_EXPR)
1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
@@ -4011,6 +4012,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
(TREE_CODE (EXPR) == TARGET_EXPR && TREE_LANG_FLAG_2 (EXPR) \
&& same_type_ignoring_top_level_qualifiers_p (TYPE, TREE_TYPE (EXPR)))
+/* True if this CONVERT_EXPR is for a conversion to virtual base in
+ an NSDMI, and should be re-evaluated when used in a constructor. */
+#define CONVERT_EXPR_VBASE_PATH(NODE) \
+ TREE_LANG_FLAG_0 (CONVERT_EXPR_CHECK (NODE))
+
/* An enumeration of the kind of tags that C++ accepts. */
enum tag_types {
none_type = 0, /* Not a tag type. */
@@ -1944,6 +1944,20 @@ bot_replace (tree* t,
parsing with the real one for this function. */
*t = current_class_ptr;
}
+ else if (TREE_CODE (*t) == CONVERT_EXPR
+ && CONVERT_EXPR_VBASE_PATH (*t))
+ {
+ /* In an NSDMI build_base_path defers building conversions to virtual
+ bases, and we handle it here. */
+ tree basetype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (*t)));
+ VEC(tree,gc) *vbases = CLASSTYPE_VBASECLASSES (current_class_type);
+ int i; tree binfo;
+ FOR_EACH_VEC_ELT (tree, vbases, i, binfo)
+ if (BINFO_TYPE (binfo) == basetype)
+ break;
+ *t = build_base_path (PLUS_EXPR, TREE_OPERAND (*t, 0), binfo, true,
+ tf_warning_or_error);
+ }
return NULL_TREE;
}
new file mode 100644
@@ -0,0 +1,26 @@
+// PR c++/51611
+// { dg-options -std=c++0x }
+// { dg-do run }
+
+struct A
+{
+ A(): i(42) { }
+ int i;
+ int f() { return i; }
+};
+
+struct B : virtual A
+{
+ int j = i + f();
+ int k = A::i + A::f();
+};
+
+struct C: B { int pad; };
+
+int main()
+{
+ C c;
+ if (c.j != 84 || c.k != 84)
+ __builtin_abort();
+}
+