summaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog84
-rw-r--r--gcc/cp/call.c52
-rw-r--r--gcc/cp/class.c90
-rw-r--r--gcc/cp/cp-tree.h24
-rw-r--r--gcc/cp/decl.c15
-rw-r--r--gcc/cp/error.c5
-rw-r--r--gcc/cp/init.c3
-rw-r--r--gcc/cp/method.c217
-rw-r--r--gcc/cp/name-lookup.c13
-rw-r--r--gcc/cp/parser.c15
-rw-r--r--gcc/cp/pt.c58
-rw-r--r--gcc/cp/semantics.c28
-rw-r--r--gcc/cp/tree.c2
-rw-r--r--gcc/cp/typeck.c4
14 files changed, 524 insertions, 86 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a52b643c638..73ab5a9b0ae 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,87 @@
+2012-10-18 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/54501
+ * decl.c (reshape_init_array_1): Avoid infinite loops.
+
+2012-10-15 Alexandre Oliva <aoliva@redhat.com>
+ Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/17805
+ * call.c (build_new_op_1): Filter out operator functions that don't
+ satisfy enum-conversion match requirements.
+
+2012-10-15 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/50080 (again)
+ * parser.c (cp_parser_optional_template_keyword): When -pedantic
+ and C++98 mode restore pre-Core/468 behavior.
+
+2012-10-15 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/50080
+ * parser.c (cp_parser_optional_template_keyword): Implement
+ Core/468, allow outside template.
+
+2012-10-14 Jason Merrill <jason@redhat.com>
+ Ville Voutilainen <ville.voutilainen@gmail.com>
+
+ Implement C++11 inheriting constructors.
+ * cp-tree.h (cpp0x_warn_str): Add CPP0X_INHERITING_CTORS.
+ (DECL_INHERITED_CTOR_BASE, SET_DECL_INHERITED_CTOR_BASE): New.
+ (special_function_kind): Add sfk_inheriting_constructor.
+ * class.c (add_method): An inheriting ctor is hidden by a
+ user-declared one.
+ (one_inheriting_sig, one_inherited_ctor): New.
+ (add_implicitly_declared_members): Handle inheriting ctors.
+ * error.c (maybe_warn_cpp0x): Handle CPP0X_INHERITING_CTORS.
+ * init.c (emit_mem_initializers): Don't set LOOKUP_DEFAULTED
+ for an inheriting constructor.
+ * method.c (type_has_trivial_fn): Handle sfk_inheriting_constructor.
+ (type_set_nontrivial_flag): Likewise.
+ (add_one_base_init): Split out from...
+ (do_build_copy_constructor): ...here. Handle inheriting constructors.
+ (locate_fn_flags): Handle a list of arg types.
+ (synthesized_method_walk): Handle inheriting constructors.
+ (maybe_explain_implicit_delete): Likewise.
+ (deduce_inheriting_ctor): New.
+ (implicitly_declare_fn): Handle inheriting constructors.
+ * name-lookup.c (push_class_level_binding_1): An inheriting constructor
+ does not declare the base's name.
+ (do_class_using_decl): Allow inheriting constructors.
+ * pt.c (template_parms_to_args): Split from current_template_args.
+ (add_inherited_template_parms): New.
+ (tsubst_decl): Handle inheriting constructors.
+ * tree.c (special_function_p): Handle inheriting constructors.
+
+2012-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/54381
+ * semantics.c (finish_call_expr): Pass array of 3 sizeof_arg
+ trees and locs (corresponding to first 3 arguments) to
+ sizeof_pointer_memaccess_warning.
+
+2012-10-12 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/24449
+ * decl.c (grokfndecl): When checking for ::main declarations
+ use PROCESSING_REAL_TEMPLATE_DECL_P().
+
+2012-10-12 Marc Glisse <marc.glisse@inria.fr>
+
+ PR c++/53055
+ * call.c (build_new_op_1): Pass RO_ARROW_STAR to cp_build_indirect_ref.
+ * typeck.c (cp_build_indirect_ref): Handle RO_ARROW_STAR.
+
+2012-10-11 Jason Merrill <jason@redhat.com>
+
+ * cp-tree.h (DECL_THUNKS): NULL_TREE for non-virtual functions.
+ (SET_DECL_THUNKS): New.
+ * decl.c (duplicate_decls): Adjust.
+ * method.c (make_thunk): Adjust.
+
+ * decl.c (grokdeclarator): Set DECL_GNU_TLS_P for static data
+ members, too.
+
2012-10-09 Dodji Seketeli <dodji@redhat.com>
PR c++/53540 - using fails to be equivalent to typedef
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 3351a585f2b..e21049b8e64 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5043,6 +5043,11 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
NULL_TREE, arglist, NULL_TREE,
NULL_TREE, false, NULL_TREE, NULL_TREE,
flags, &candidates, complain);
+
+ args[0] = arg1;
+ args[1] = arg2;
+ args[2] = NULL_TREE;
+
/* Add class-member operators to the candidate set. */
if (CLASS_TYPE_P (TREE_TYPE (arg1)))
{
@@ -5062,10 +5067,49 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
BASELINK_ACCESS_BINFO (fns),
flags, &candidates, complain);
}
+ /* Per 13.3.1.2/3, 2nd bullet, if no operand has a class type, then
+ only non-member functions that have type T1 or reference to
+ cv-qualified-opt T1 for the first argument, if the first argument
+ has an enumeration type, or T2 or reference to cv-qualified-opt
+ T2 for the second argument, if the the second argument has an
+ enumeration type. Filter out those that don't match. */
+ else if (! arg2 || ! CLASS_TYPE_P (TREE_TYPE (arg2)))
+ {
+ struct z_candidate **candp, **next;
- args[0] = arg1;
- args[1] = arg2;
- args[2] = NULL_TREE;
+ for (candp = &candidates; *candp; candp = next)
+ {
+ tree parmlist, parmtype;
+ int i, nargs = (arg2 ? 2 : 1);
+
+ cand = *candp;
+ next = &cand->next;
+
+ parmlist = TYPE_ARG_TYPES (TREE_TYPE (cand->fn));
+
+ for (i = 0; i < nargs; ++i)
+ {
+ parmtype = TREE_VALUE (parmlist);
+
+ if (TREE_CODE (parmtype) == REFERENCE_TYPE)
+ parmtype = TREE_TYPE (parmtype);
+ if (TREE_CODE (TREE_TYPE (args[i])) == ENUMERAL_TYPE
+ && (same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (args[i]), parmtype)))
+ break;
+
+ parmlist = TREE_CHAIN (parmlist);
+ }
+
+ /* No argument has an appropriate type, so remove this
+ candidate function from the list. */
+ if (i == nargs)
+ {
+ *candp = cand->next;
+ next = candp;
+ }
+ }
+ }
add_builtin_candidates (&candidates, code, code2, fnname, args,
flags, complain);
@@ -5309,7 +5353,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
return cp_build_array_ref (input_location, arg1, arg2, complain);
case MEMBER_REF:
- return build_m_component_ref (cp_build_indirect_ref (arg1, RO_NULL,
+ return build_m_component_ref (cp_build_indirect_ref (arg1, RO_ARROW_STAR,
complain),
arg2, complain);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 0e77b81c85b..a478de80563 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -132,7 +132,7 @@ static void finish_struct_methods (tree);
static void maybe_warn_about_overly_private_class (tree);
static int method_name_cmp (const void *, const void *);
static int resort_method_name_cmp (const void *, const void *);
-static void add_implicitly_declared_members (tree, int, int);
+static void add_implicitly_declared_members (tree, tree*, int, int);
static tree fixed_type_or_null (tree, int *, int *);
static tree build_simple_base_path (tree expr, tree binfo);
static tree build_vtbl_ref_1 (tree, tree);
@@ -1087,6 +1087,20 @@ add_method (tree type, tree method, tree using_decl)
|| same_type_p (TREE_TYPE (fn_type),
TREE_TYPE (method_type))))
{
+ if (DECL_INHERITED_CTOR_BASE (method))
+ {
+ if (DECL_INHERITED_CTOR_BASE (fn))
+ {
+ error_at (DECL_SOURCE_LOCATION (method),
+ "%q#D inherited from %qT", method,
+ DECL_INHERITED_CTOR_BASE (method));
+ error_at (DECL_SOURCE_LOCATION (fn),
+ "conflicts with version inherited from %qT",
+ DECL_INHERITED_CTOR_BASE (fn));
+ }
+ /* Otherwise defer to the other function. */
+ return false;
+ }
if (using_decl)
{
if (DECL_CONTEXT (fn) == type)
@@ -2750,6 +2764,51 @@ declare_virt_assop_and_dtor (tree t)
NULL, t);
}
+/* Declare the inheriting constructor for class T inherited from base
+ constructor CTOR with the parameter array PARMS of size NPARMS. */
+
+static void
+one_inheriting_sig (tree t, tree ctor, tree *parms, int nparms)
+{
+ /* We don't declare an inheriting ctor that would be a default,
+ copy or move ctor. */
+ if (nparms == 0
+ || (nparms == 1
+ && TREE_CODE (parms[0]) == REFERENCE_TYPE
+ && TYPE_MAIN_VARIANT (TREE_TYPE (parms[0])) == t))
+ return;
+ int i;
+ tree parmlist = void_list_node;
+ for (i = nparms - 1; i >= 0; i--)
+ parmlist = tree_cons (NULL_TREE, parms[i], parmlist);
+ tree fn = implicitly_declare_fn (sfk_inheriting_constructor,
+ t, false, ctor, parmlist);
+ if (add_method (t, fn, NULL_TREE))
+ {
+ DECL_CHAIN (fn) = TYPE_METHODS (t);
+ TYPE_METHODS (t) = fn;
+ }
+}
+
+/* Declare all the inheriting constructors for class T inherited from base
+ constructor CTOR. */
+
+static void
+one_inherited_ctor (tree ctor, tree t)
+{
+ tree parms = FUNCTION_FIRST_USER_PARMTYPE (ctor);
+
+ tree *new_parms = XALLOCAVEC (tree, list_length (parms));
+ int i = 0;
+ for (; parms && parms != void_list_node; parms = TREE_CHAIN (parms))
+ {
+ if (TREE_PURPOSE (parms))
+ one_inheriting_sig (t, ctor, new_parms, i);
+ new_parms[i++] = TREE_VALUE (parms);
+ }
+ one_inheriting_sig (t, ctor, new_parms, i);
+}
+
/* Create default constructors, assignment operators, and so forth for
the type indicated by T, if they are needed. CANT_HAVE_CONST_CTOR,
and CANT_HAVE_CONST_ASSIGNMENT are nonzero if, for whatever reason,
@@ -2758,7 +2817,7 @@ declare_virt_assop_and_dtor (tree t)
a const reference, respectively. */
static void
-add_implicitly_declared_members (tree t,
+add_implicitly_declared_members (tree t, tree* access_decls,
int cant_have_const_cctor,
int cant_have_const_assignment)
{
@@ -2826,6 +2885,26 @@ add_implicitly_declared_members (tree t,
/* We can't be lazy about declaring functions that might override
a virtual function from a base class. */
declare_virt_assop_and_dtor (t);
+
+ while (*access_decls)
+ {
+ tree using_decl = TREE_VALUE (*access_decls);
+ tree decl = USING_DECL_DECLS (using_decl);
+ if (DECL_SELF_REFERENCE_P (decl))
+ {
+ /* declare, then remove the decl */
+ tree ctor_list = CLASSTYPE_CONSTRUCTORS (TREE_TYPE (decl));
+ location_t loc = input_location;
+ input_location = DECL_SOURCE_LOCATION (using_decl);
+ if (ctor_list)
+ for (; ctor_list; ctor_list = OVL_NEXT (ctor_list))
+ one_inherited_ctor (OVL_CURRENT (ctor_list), t);
+ *access_decls = TREE_CHAIN (*access_decls);
+ input_location = loc;
+ }
+ else
+ access_decls = &TREE_CHAIN (*access_decls);
+ }
}
/* Subroutine of insert_into_classtype_sorted_fields. Recursively
@@ -4342,7 +4421,8 @@ deduce_noexcept_on_destructor (tree dtor)
{
tree ctx = DECL_CONTEXT (dtor);
tree implicit_fn = implicitly_declare_fn (sfk_destructor, ctx,
- /*const_p=*/false);
+ /*const_p=*/false,
+ NULL, NULL);
tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
TREE_TYPE (dtor) = build_exception_variant (TREE_TYPE (dtor), eh_spec);
}
@@ -5135,14 +5215,14 @@ check_bases_and_members (tree t)
}
/* Synthesize any needed methods. */
- add_implicitly_declared_members (t,
+ add_implicitly_declared_members (t, &access_decls,
cant_have_const_ctor,
no_const_asn_ref);
/* Check defaulted declarations here so we have cant_have_const_ctor
and don't need to worry about clones. */
for (fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn))
- if (DECL_DEFAULTED_IN_CLASS_P (fn))
+ if (!DECL_ARTIFICIAL (fn) && DECL_DEFAULTED_IN_CLASS_P (fn))
{
int copy = copy_fn_p (fn);
if (copy > 0)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 35819ed10c4..7b4277b05b7 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -420,6 +420,8 @@ typedef enum cpp0x_warn_str
CPP0X_USER_DEFINED_LITERALS,
/* delegating constructors */
CPP0X_DELEGATING_CTORS,
+ /* inheriting constructors */
+ CPP0X_INHERITING_CTORS,
/* C++11 attributes */
CPP0X_ATTRIBUTES
} cpp0x_warn_str;
@@ -2378,7 +2380,20 @@ struct GTY((variable_size)) lang_decl {
/* The thunks associated with NODE, a FUNCTION_DECL. */
#define DECL_THUNKS(NODE) \
- (LANG_DECL_FN_CHECK (NODE)->context)
+ (DECL_VIRTUAL_P (NODE) ? LANG_DECL_FN_CHECK (NODE)->context : NULL_TREE)
+
+/* Set DECL_THUNKS. */
+#define SET_DECL_THUNKS(NODE,THUNKS) \
+ (LANG_DECL_FN_CHECK (NODE)->context = (THUNKS))
+
+/* If NODE, a FUNCTION_DECL, is a C++11 inheriting constructor, then this
+ is the base it inherits from. */
+#define DECL_INHERITED_CTOR_BASE(NODE) \
+ (DECL_CONSTRUCTOR_P (NODE) ? LANG_DECL_FN_CHECK (NODE)->context : NULL_TREE)
+
+/* Set the inherited base. */
+#define SET_DECL_INHERITED_CTOR_BASE(NODE,INH) \
+ (LANG_DECL_FN_CHECK (NODE)->context = (INH))
/* Nonzero if NODE is a thunk, rather than an ordinary function. */
#define DECL_THUNK_P(NODE) \
@@ -4138,7 +4153,8 @@ typedef enum special_function_kind {
sfk_deleting_destructor, /* A destructor for complete objects that
deletes the object after it has been
destroyed. */
- sfk_conversion /* A conversion operator. */
+ sfk_conversion, /* A conversion operator. */
+ sfk_inheriting_constructor /* An inheriting constructor */
} special_function_kind;
/* The various kinds of linkage. From [basic.link],
@@ -5319,6 +5335,7 @@ extern void use_thunk (tree, bool);
extern bool trivial_fn_p (tree);
extern bool maybe_explain_implicit_delete (tree);
extern void explain_implicit_non_constexpr (tree);
+extern void deduce_inheriting_ctor (tree);
extern void synthesize_method (tree);
extern tree lazily_declare_fn (special_function_kind,
tree);
@@ -5331,7 +5348,7 @@ extern tree get_default_ctor (tree);
extern tree get_dtor (tree, tsubst_flags_t);
extern tree locate_ctor (tree);
extern tree implicitly_declare_fn (special_function_kind, tree,
- bool);
+ bool, tree, tree);
/* In optimize.c */
extern bool maybe_clone_body (tree);
@@ -5366,6 +5383,7 @@ extern tree maybe_update_decl_type (tree, tree);
extern bool check_default_tmpl_args (tree, tree, bool, bool, int);
extern tree push_template_decl (tree);
extern tree push_template_decl_real (tree, bool);
+extern tree add_inherited_template_parms (tree, tree);
extern bool redeclare_class_template (tree, tree);
extern tree lookup_template_class (tree, tree, tree, tree,
int, tsubst_flags_t);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 0b936ea1a8b..d25aa804971 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2052,7 +2052,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
/* DECL_THUNKS is only valid for virtual functions,
otherwise it is a DECL_FRIEND_CONTEXT. */
if (DECL_VIRTUAL_P (newdecl))
- DECL_THUNKS (newdecl) = DECL_THUNKS (olddecl);
+ SET_DECL_THUNKS (newdecl, DECL_THUNKS (olddecl));
}
/* Only variables have this field. */
else if (TREE_CODE (newdecl) == VAR_DECL
@@ -5040,6 +5040,7 @@ reshape_init_array_1 (tree elt_type, tree max_index, reshape_iter *d,
++index)
{
tree elt_init;
+ constructor_elt *old_cur = d->cur;
check_array_designated_initializer (d->cur, index);
elt_init = reshape_init_r (elt_type, d, /*first_initializer_p=*/false,
@@ -5050,6 +5051,10 @@ reshape_init_array_1 (tree elt_type, tree max_index, reshape_iter *d,
size_int (index), elt_init);
if (!TREE_CONSTANT (elt_init))
TREE_CONSTANT (new_init) = false;
+
+ /* This can happen with an invalid initializer (c++/54501). */
+ if (d->cur == old_cur && !sized_array_p)
+ break;
}
return new_init;
@@ -7416,7 +7421,7 @@ grokfndecl (tree ctype,
if (ctype == NULL_TREE && DECL_MAIN_P (decl))
{
- if (processing_template_decl)
+ if (PROCESSING_REAL_TEMPLATE_DECL_P())
error ("cannot declare %<::main%> to be a template");
if (inlinep)
error ("cannot declare %<::main%> to be inline");
@@ -10446,7 +10451,11 @@ grokdeclarator (const cp_declarator *declarator,
DECL_EXTERNAL (decl) = 1;
if (thread_p)
- DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
+ {
+ DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
+ if (declspecs->gnu_thread_keyword_p)
+ DECL_GNU_TLS_P (decl) = true;
+ }
if (constexpr_p && !initialized)
{
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 2934c9b1078..76f939f1049 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -3374,6 +3374,11 @@ maybe_warn_cpp0x (cpp0x_warn_str str)
"delegating constructors "
"only available with -std=c++11 or -std=gnu++11");
break;
+ case CPP0X_INHERITING_CTORS:
+ pedwarn (input_location, 0,
+ "inheriting constructors "
+ "only available with -std=c++11 or -std=gnu++11");
+ break;
case CPP0X_ATTRIBUTES:
pedwarn (input_location, 0,
"c++11 attributes "
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 40d0ce325f3..044603887e8 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1036,7 +1036,8 @@ emit_mem_initializers (tree mem_inits)
return;
}
- if (DECL_DEFAULTED_FN (current_function_decl))
+ if (DECL_DEFAULTED_FN (current_function_decl)
+ && ! DECL_INHERITED_CTOR_BASE (current_function_decl))
flags |= LOOKUP_DEFAULTED;
/* Sort the mem-initializers into the order in which the
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index a42ed60a99f..4da5cc9ebca 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -126,7 +126,8 @@ make_thunk (tree function, bool this_adjusting,
FUNCTION_DECL, NULL_TREE, TREE_TYPE (function));
DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);
cxx_dup_lang_specific_decl (thunk);
- DECL_THUNKS (thunk) = NULL_TREE;
+ DECL_VIRTUAL_P (thunk) = true;
+ SET_DECL_THUNKS (thunk, NULL_TREE);
DECL_CONTEXT (thunk) = DECL_CONTEXT (function);
TREE_READONLY (thunk) = TREE_READONLY (function);
@@ -157,7 +158,7 @@ make_thunk (tree function, bool this_adjusting,
/* Add it to the list of thunks associated with FUNCTION. */
DECL_CHAIN (thunk) = DECL_THUNKS (function);
- DECL_THUNKS (function) = thunk;
+ SET_DECL_THUNKS (function, thunk);
return thunk;
}
@@ -428,6 +429,8 @@ type_has_trivial_fn (tree ctype, special_function_kind sfk)
return !TYPE_HAS_COMPLEX_MOVE_ASSIGN (ctype);
case sfk_destructor:
return !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (ctype);
+ case sfk_inheriting_constructor:
+ return false;
default:
gcc_unreachable ();
}
@@ -459,6 +462,7 @@ type_set_nontrivial_flag (tree ctype, special_function_kind sfk)
case sfk_destructor:
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (ctype) = true;
return;
+ case sfk_inheriting_constructor:
default:
gcc_unreachable ();
}
@@ -477,7 +481,46 @@ trivial_fn_p (tree fn)
return type_has_trivial_fn (DECL_CONTEXT (fn), special_function_p (fn));
}
-/* Generate code for default X(X&) or X(X&&) constructor. */
+/* Subroutine of do_build_copy_constructor: Add a mem-initializer for BINFO
+ given the parameter or parameters PARM, possibly inherited constructor
+ base INH, or move flag MOVE_P. */
+
+static tree
+add_one_base_init (tree binfo, tree parm, bool move_p, tree inh,
+ tree member_init_list)
+{
+ tree init;
+ if (inh)
+ {
+ /* An inheriting constructor only has a mem-initializer for
+ the base it inherits from. */
+ if (BINFO_TYPE (binfo) != inh)
+ return member_init_list;
+
+ tree *p = &init;
+ init = NULL_TREE;
+ for (; parm; parm = DECL_CHAIN (parm))
+ {
+ tree exp = convert_from_reference (parm);
+ if (TREE_CODE (TREE_TYPE (parm)) != REFERENCE_TYPE)
+ exp = move (exp);
+ *p = build_tree_list (NULL_TREE, exp);
+ p = &TREE_CHAIN (*p);
+ }
+ }
+ else
+ {
+ init = build_base_path (PLUS_EXPR, parm, binfo, 1,
+ tf_warning_or_error);
+ if (move_p)
+ init = move (init);
+ init = build_tree_list (NULL_TREE, init);
+ }
+ return tree_cons (binfo, init, member_init_list);
+}
+
+/* Generate code for default X(X&) or X(X&&) constructor or an inheriting
+ constructor. */
static void
do_build_copy_constructor (tree fndecl)
@@ -485,8 +528,10 @@ do_build_copy_constructor (tree fndecl)
tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl);
bool trivial = trivial_fn_p (fndecl);
+ tree inh = DECL_INHERITED_CTOR_BASE (fndecl);
- parm = convert_from_reference (parm);
+ if (!inh)
+ parm = convert_from_reference (parm);
if (trivial
&& is_empty_class (current_class_type))
@@ -515,14 +560,8 @@ do_build_copy_constructor (tree fndecl)
for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0;
VEC_iterate (tree, vbases, i, binfo); i++)
{
- init = build_base_path (PLUS_EXPR, parm, binfo, 1,
- tf_warning_or_error);
- if (move_p)
- init = move (init);
- member_init_list
- = tree_cons (binfo,
- build_tree_list (NULL_TREE, init),
- member_init_list);
+ member_init_list = add_one_base_init (binfo, parm, move_p, inh,
+ member_init_list);
}
for (binfo = TYPE_BINFO (current_class_type), i = 0;
@@ -530,15 +569,8 @@ do_build_copy_constructor (tree fndecl)
{
if (BINFO_VIRTUAL_P (base_binfo))
continue;
-
- init = build_base_path (PLUS_EXPR, parm, base_binfo, 1,
- tf_warning_or_error);
- if (move_p)
- init = move (init);
- member_init_list
- = tree_cons (base_binfo,
- build_tree_list (NULL_TREE, init),
- member_init_list);
+ member_init_list = add_one_base_init (base_binfo, parm, move_p,
+ inh, member_init_list);
}
for (; fields; fields = DECL_CHAIN (fields))
@@ -548,6 +580,8 @@ do_build_copy_constructor (tree fndecl)
if (TREE_CODE (field) != FIELD_DECL)
continue;
+ if (inh)
+ continue;
expr_type = TREE_TYPE (field);
if (DECL_NAME (field))
@@ -832,8 +866,23 @@ locate_fn_flags (tree type, tree name, tree argtype, int flags,
args = make_tree_vector ();
if (argtype)
{
- tree arg = build_stub_object (argtype);
- VEC_quick_push (tree, args, arg);
+ if (TREE_CODE (argtype) == TREE_LIST)
+ {
+ for (tree elt = argtype; elt != void_list_node;
+ elt = TREE_CHAIN (elt))
+ {
+ tree type = TREE_VALUE (elt);
+ if (TREE_CODE (type) != REFERENCE_TYPE)
+ type = cp_build_reference_type (type, /*rval*/true);
+ tree arg = build_stub_object (type);
+ VEC_safe_push (tree, gc, args, arg);
+ }
+ }
+ else
+ {
+ tree arg = build_stub_object (argtype);
+ VEC_quick_push (tree, args, arg);
+ }
}
fns = lookup_fnfields (binfo, name, 0);
@@ -1109,7 +1158,8 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
static void
synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
tree *spec_p, bool *trivial_p, bool *deleted_p,
- bool *constexpr_p, bool *no_implicit_p, bool diag)
+ bool *constexpr_p, bool *no_implicit_p, bool diag,
+ tree inherited_base, tree inherited_parms)
{
tree binfo, base_binfo, scope, fnname, rval, argtype;
bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor;
@@ -1161,6 +1211,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
case sfk_constructor:
case sfk_move_constructor:
case sfk_copy_constructor:
+ case sfk_inheriting_constructor:
ctor_p = true;
fnname = complete_ctor_identifier;
break;
@@ -1169,6 +1220,9 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
gcc_unreachable ();
}
+ gcc_assert ((sfk == sfk_inheriting_constructor)
+ == (inherited_base != NULL_TREE));
+
/* If that user-written default constructor would satisfy the
requirements of a constexpr constructor (7.1.5), the
implicitly-defined default constructor is constexpr. */
@@ -1180,6 +1234,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
{
case sfk_constructor:
case sfk_destructor:
+ case sfk_inheriting_constructor:
copy_arg_p = false;
break;
@@ -1230,7 +1285,9 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
scope = push_scope (ctype);
- flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
+ flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE;
+ if (!inherited_base)
+ flags |= LOOKUP_DEFAULTED;
complain = diag ? tf_warning_or_error : tf_none;
@@ -1251,7 +1308,11 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
if (copy_arg_p)
argtype = build_stub_type (basetype, quals, move_p);
+ else if (basetype == inherited_base)
+ argtype = inherited_parms;
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
+ if (inherited_base)
+ argtype = NULL_TREE;
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
constexpr_p, no_implicit_p, diag, basetype);
@@ -1404,14 +1465,16 @@ maybe_explain_implicit_delete (tree decl)
}
if (!informed)
{
- tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (decl));
+ tree parms = FUNCTION_FIRST_USER_PARMTYPE (decl);
+ tree parm_type = TREE_VALUE (parms);
bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
tree scope = push_scope (ctype);
inform (0, "%q+#D is implicitly deleted because the default "
"definition would be ill-formed:", decl);
pop_scope (scope);
synthesized_method_walk (ctype, sfk, const_p,
- NULL, NULL, NULL, NULL, NULL, true);
+ NULL, NULL, NULL, NULL, NULL, true,
+ DECL_INHERITED_CTOR_BASE (decl), parms);
}
input_location = loc;
@@ -1431,7 +1494,27 @@ explain_implicit_non_constexpr (tree decl)
bool dummy;
synthesized_method_walk (DECL_CLASS_CONTEXT (decl),
special_function_p (decl), const_p,
- NULL, NULL, NULL, &dummy, NULL, true);
+ NULL, NULL, NULL, &dummy, NULL, true,
+ NULL_TREE, NULL_TREE);
+}
+
+/* DECL is an instantiation of an inheriting constructor template. Deduce
+ the correct exception-specification and deletedness for this particular
+ specialization. */
+
+void
+deduce_inheriting_ctor (tree decl)
+{
+ gcc_assert (DECL_INHERITED_CTOR_BASE (decl));
+ tree spec;
+ bool trivial, constexpr_, deleted, no_implicit;
+ synthesized_method_walk (DECL_CONTEXT (decl), sfk_inheriting_constructor,
+ false, &spec, &trivial, &deleted, &constexpr_,
+ &no_implicit, /*diag*/false,
+ DECL_INHERITED_CTOR_BASE (decl),
+ FUNCTION_FIRST_USER_PARMTYPE (decl));
+ DECL_DELETED_FN (decl) = deleted;
+ TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), spec);
}
/* Implicitly declare the special function indicated by KIND, as a
@@ -1441,7 +1524,9 @@ explain_implicit_non_constexpr (tree decl)
FUNCTION_DECL for the implicitly declared function. */
tree
-implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
+implicitly_declare_fn (special_function_kind kind, tree type,
+ bool const_p, tree inherited_ctor,
+ tree inherited_parms)
{
tree fn;
tree parameter_types = void_list_node;
@@ -1498,6 +1583,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
case sfk_copy_assignment:
case sfk_move_constructor:
case sfk_move_assignment:
+ case sfk_inheriting_constructor:
{
bool move_p;
if (kind == sfk_copy_assignment
@@ -1509,23 +1595,44 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
else
name = constructor_name (type);
- if (const_p)
- rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
+ if (kind == sfk_inheriting_constructor)
+ parameter_types = inherited_parms;
else
- rhs_parm_type = type;
- move_p = (kind == sfk_move_assignment
- || kind == sfk_move_constructor);
- rhs_parm_type = cp_build_reference_type (rhs_parm_type, move_p);
+ {
+ if (const_p)
+ rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
+ else
+ rhs_parm_type = type;
+ move_p = (kind == sfk_move_assignment
+ || kind == sfk_move_constructor);
+ rhs_parm_type = cp_build_reference_type (rhs_parm_type, move_p);
- parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types);
+ parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types);
+ }
break;
}
default:
gcc_unreachable ();
}
- synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
- &deleted_p, &constexpr_p, &no_implicit_p, false);
+ tree inherited_base = (inherited_ctor
+ ? DECL_CONTEXT (inherited_ctor)
+ : NULL_TREE);
+ if (inherited_ctor && TREE_CODE (inherited_ctor) == TEMPLATE_DECL)
+ {
+ /* For an inheriting constructor template, just copy these flags from
+ the inherited constructor template for now. */
+ raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (inherited_ctor));
+ trivial_p = false;
+ deleted_p = DECL_DELETED_FN (DECL_TEMPLATE_RESULT (inherited_ctor));
+ constexpr_p
+ = DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT (inherited_ctor));
+ no_implicit_p = false;
+ }
+ else
+ synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
+ &deleted_p, &constexpr_p, &no_implicit_p, false,
+ inherited_base, inherited_parms);
/* Don't bother marking a deleted constructor as constexpr. */
if (deleted_p)
constexpr_p = false;
@@ -1543,9 +1650,10 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
if (raises)
fn_type = build_exception_variant (fn_type, raises);
fn = build_lang_decl (FUNCTION_DECL, name, fn_type);
- DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (TYPE_NAME (type));
+ if (kind != sfk_inheriting_constructor)
+ DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (TYPE_NAME (type));
if (kind == sfk_constructor || kind == sfk_copy_constructor
- || kind == sfk_move_constructor)
+ || kind == sfk_move_constructor || kind == sfk_inheriting_constructor)
DECL_CONSTRUCTOR_P (fn) = 1;
else if (kind == sfk_destructor)
DECL_DESTRUCTOR_P (fn) = 1;
@@ -1574,6 +1682,27 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
DECL_PARM_INDEX (decl) = DECL_PARM_LEVEL (decl) = 1;
DECL_ARGUMENTS (fn) = decl;
}
+ else if (kind == sfk_inheriting_constructor)
+ {
+ tree *p = &DECL_ARGUMENTS (fn);
+ for (tree parm = inherited_parms; parm != void_list_node;
+ parm = TREE_CHAIN (parm))
+ {
+ *p = cp_build_parm_decl (NULL_TREE, TREE_VALUE (parm));
+ DECL_CONTEXT (*p) = fn;
+ p = &DECL_CHAIN (*p);
+ }
+ SET_DECL_INHERITED_CTOR_BASE (fn, inherited_base);
+ DECL_NONCONVERTING_P (fn) = DECL_NONCONVERTING_P (inherited_ctor);
+ /* A constructor so declared has the same access as the corresponding
+ constructor in X. */
+ TREE_PRIVATE (fn) = TREE_PRIVATE (inherited_ctor);
+ TREE_PROTECTED (fn) = TREE_PROTECTED (inherited_ctor);
+ /* Copy constexpr from the inherited constructor even if the
+ inheriting constructor doesn't satisfy the requirements. */
+ constexpr_p
+ = DECL_DECLARED_CONSTEXPR_P (STRIP_TEMPLATE (inherited_ctor));
+ }
/* Add the "this" parameter. */
this_parm = build_this_parm (fn_type, TYPE_UNQUALIFIED);
DECL_CHAIN (this_parm) = DECL_ARGUMENTS (fn);
@@ -1599,6 +1728,9 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
/* Restore PROCESSING_TEMPLATE_DECL. */
processing_template_decl = saved_processing_template_decl;
+ if (inherited_ctor && TREE_CODE (inherited_ctor) == TEMPLATE_DECL)
+ fn = add_inherited_template_parms (fn, inherited_ctor);
+
return fn;
}
@@ -1612,7 +1744,8 @@ defaulted_late_check (tree fn)
tree ctx = DECL_CONTEXT (fn);
special_function_kind kind = special_function_p (fn);
bool fn_const_p = (copy_fn_p (fn) == 2);
- tree implicit_fn = implicitly_declare_fn (kind, ctx, fn_const_p);
+ tree implicit_fn = implicitly_declare_fn (kind, ctx, fn_const_p,
+ NULL, NULL);
if (!same_type_p (TREE_TYPE (TREE_TYPE (fn)),
TREE_TYPE (TREE_TYPE (implicit_fn)))
@@ -1765,7 +1898,7 @@ lazily_declare_fn (special_function_kind sfk, tree type)
}
/* Declare the function. */
- fn = implicitly_declare_fn (sfk, type, const_p);
+ fn = implicitly_declare_fn (sfk, type, const_p, NULL, NULL);
/* [class.copy]/8 If the class definition declares a move constructor or
move assignment operator, the implicitly declared copy constructor is
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index cd328b31c72..f0105604921 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -3026,6 +3026,14 @@ push_class_level_binding_1 (tree name, tree x)
&& TREE_TYPE (decl) == error_mark_node)
decl = TREE_VALUE (decl);
+ if (TREE_CODE (decl) == USING_DECL
+ && TREE_CODE (USING_DECL_SCOPE (decl)) == TEMPLATE_TYPE_PARM
+ && DECL_NAME (decl) == TYPE_IDENTIFIER (USING_DECL_SCOPE (decl)))
+ /* This using-declaration declares constructors that inherit from the
+ constructors for the template parameter. It does not redeclare the
+ name of the template parameter. */
+ return true;
+
if (!check_template_shadow (decl))
return false;
@@ -3218,10 +3226,7 @@ do_class_using_decl (tree scope, tree name)
return NULL_TREE;
}
if (MAYBE_CLASS_TYPE_P (scope) && constructor_name_p (name, scope))
- {
- error ("%<%T::%D%> names constructor", scope, name);
- return NULL_TREE;
- }
+ maybe_warn_cpp0x (CPP0X_INHERITING_CTORS);
if (constructor_name_p (name, current_class_type))
{
error ("%<%T::%D%> names constructor in %qT",
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index a7939c87647..853d789f987 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -23252,15 +23252,17 @@ cp_parser_optional_template_keyword (cp_parser *parser)
{
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
{
- /* The `template' keyword can only be used within templates;
+ /* In C++98 the `template' keyword can only be used within templates;
outside templates the parser can always figure out what is a
- template and what is not. */
- if (!processing_template_decl)
+ template and what is not. In C++11, per the resolution of DR 468,
+ `template' is allowed in cases where it is not strictly necessary. */
+ if (!processing_template_decl
+ && pedantic && cxx_dialect == cxx98)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
- error_at (token->location,
- "%<template%> (as a disambiguator) is only allowed "
- "within templates");
+ pedwarn (token->location, OPT_Wpedantic,
+ "in C++98 %<template%> (as a disambiguator) is only "
+ "allowed within templates");
/* If this part of the token stream is rescanned, the same
error message would be generated. So, we purge the token
from the stream. */
@@ -23274,7 +23276,6 @@ cp_parser_optional_template_keyword (cp_parser *parser)
return true;
}
}
-
return false;
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d81626cb35e..7e8d8b0880d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3847,17 +3847,16 @@ arg_from_parm_pack_p (tree arg_pack, tree parm_pack)
return false;
}
-/* Within the declaration of a template, return all levels of template
- parameters that apply. The template parameters are represented as
- a TREE_VEC, in the form documented in cp-tree.h for template
- arguments. */
+/* Given a set of template parameters, return them as a set of template
+ arguments. The template parameters are represented as a TREE_VEC, in
+ the form documented in cp-tree.h for template arguments. */
static tree
-current_template_args (void)
+template_parms_to_args (tree parms)
{
tree header;
tree args = NULL_TREE;
- int length = TMPL_PARMS_DEPTH (current_template_parms);
+ int length = TMPL_PARMS_DEPTH (parms);
int l = length;
/* If there is only one level of template parameters, we do not
@@ -3866,7 +3865,7 @@ current_template_args (void)
if (length > 1)
args = make_tree_vec (length);
- for (header = current_template_parms; header; header = TREE_CHAIN (header))
+ for (header = parms; header; header = TREE_CHAIN (header))
{
tree a = copy_node (TREE_VALUE (header));
int i;
@@ -3903,6 +3902,15 @@ current_template_args (void)
return args;
}
+/* Within the declaration of a template, return the currently active
+ template parameters as an argument TREE_VEC. */
+
+static tree
+current_template_args (void)
+{
+ return template_parms_to_args (current_template_parms);
+}
+
/* Update the declared TYPE by doing any lookups which were thought to be
dependent, but are not now that we know the SCOPE of the declarator. */
@@ -4904,6 +4912,29 @@ push_template_decl (tree decl)
return push_template_decl_real (decl, false);
}
+/* FN is an inheriting constructor that inherits from the constructor
+ template INHERITED; turn FN into a constructor template with a matching
+ template header. */
+
+tree
+add_inherited_template_parms (tree fn, tree inherited)
+{
+ tree inner_parms
+ = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (inherited));
+ inner_parms = copy_node (inner_parms);
+ tree parms
+ = tree_cons (size_int (processing_template_decl + 1),
+ inner_parms, current_template_parms);
+ tree tmpl = build_template_decl (fn, parms, /*member*/true);
+ tree args = template_parms_to_args (parms);
+ DECL_TEMPLATE_INFO (fn) = build_template_info (tmpl, args);
+ TREE_TYPE (tmpl) = TREE_TYPE (fn);
+ DECL_TEMPLATE_RESULT (tmpl) = fn;
+ DECL_ARTIFICIAL (tmpl) = true;
+ DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
+ return tmpl;
+}
+
/* Called when a class template TYPE is redeclared with the indicated
template PARMS, e.g.:
@@ -10136,6 +10167,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
maybe_retrofit_in_chrg (r);
if (DECL_CONSTRUCTOR_P (r))
grok_ctor_properties (ctx, r);
+ if (DECL_INHERITED_CTOR_BASE (r))
+ deduce_inheriting_ctor (r);
/* If this is an instantiation of a member template, clone it.
If it isn't, that'll be handled by
clone_constructors_and_destructors. */
@@ -10336,9 +10369,14 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
if (DECL_DEPENDENT_P (t)
|| uses_template_parms (USING_DECL_SCOPE (t)))
{
- r = do_class_using_decl
- (tsubst_copy (USING_DECL_SCOPE (t), args, complain, in_decl),
- tsubst_copy (DECL_NAME (t), args, complain, in_decl));
+ tree scope = USING_DECL_SCOPE (t);
+ tree inst_scope = tsubst_copy (USING_DECL_SCOPE (t), args,
+ complain, in_decl);
+ tree name = tsubst_copy (DECL_NAME (t), args, complain, in_decl);
+ if (TREE_CODE (scope) == TEMPLATE_TYPE_PARM
+ && name == TYPE_IDENTIFIER (scope))
+ name = TYPE_IDENTIFIER (inst_scope);
+ r = do_class_using_decl (inst_scope, name);
if (!r)
r = error_mark_node;
else
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 4beed0073fb..6798c1bf5d4 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2173,16 +2173,30 @@ finish_call_expr (tree fn, VEC(tree,gc) **args, bool disallow_virtual,
{
if (warn_sizeof_pointer_memaccess
&& !VEC_empty(tree, *args)
- && TREE_CODE (VEC_last(tree, *args)) == SIZEOF_EXPR
&& !processing_template_decl)
{
- tree sizeof_arg = VEC_last(tree, *args);
- if (SIZEOF_EXPR_TYPE_P (sizeof_arg))
- sizeof_arg = TREE_TYPE (TREE_OPERAND (sizeof_arg, 0));
- else
- sizeof_arg = TREE_OPERAND (sizeof_arg, 0);
+ location_t sizeof_arg_loc[3];
+ tree sizeof_arg[3];
+ unsigned int i;
+ for (i = 0; i < 3; i++)
+ {
+ tree t;
+
+ sizeof_arg_loc[i] = UNKNOWN_LOCATION;
+ sizeof_arg[i] = NULL_TREE;
+ if (i >= VEC_length (tree, *args))
+ continue;
+ t = VEC_index (tree, *args, i);
+ if (TREE_CODE (t) != SIZEOF_EXPR)
+ continue;
+ if (SIZEOF_EXPR_TYPE_P (t))
+ sizeof_arg[i] = TREE_TYPE (TREE_OPERAND (t, 0));
+ else
+ sizeof_arg[i] = TREE_OPERAND (t, 0);
+ sizeof_arg_loc[i] = EXPR_LOCATION (t);
+ }
sizeof_pointer_memaccess_warning
- (EXPR_LOCATION (VEC_last(tree, *args)), fn, *args,
+ (sizeof_arg_loc, fn, *args,
sizeof_arg, same_type_ignoring_top_level_qualifiers_p);
}
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index a41337c2116..8d555c2e2b1 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -3337,6 +3337,8 @@ special_function_p (const_tree decl)
/* Rather than doing all this stuff with magic names, we should
probably have a field of type `special_function_kind' in
DECL_LANG_SPECIFIC. */
+ if (DECL_INHERITED_CTOR_BASE (decl))
+ return sfk_inheriting_constructor;
if (DECL_COPY_CONSTRUCTOR_P (decl))
return sfk_copy_constructor;
if (DECL_MOVE_CONSTRUCTOR_P (decl))
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 13e75ab9ebf..eaa0935dc98 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2908,6 +2908,10 @@ cp_build_indirect_ref (tree ptr, ref_operator errorstring,
case RO_IMPLICIT_CONVERSION:
error ("invalid use of implicit conversion on pointer to member");
break;
+ case RO_ARROW_STAR:
+ error ("left hand operand of %<->*%> must be a pointer to class, "
+ "but is a pointer to member of type %qT", type);
+ break;
default:
gcc_unreachable ();
}