/* Functions related to building classes and their related objects.
Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
#include "cgraph.h"
#include "tree-dump.h"
#include "splay-tree.h"
+#include "pointer-set.h"
/* The number of nested classes being processed. If we are not in the
scope of any class, this is zero. */
build_base_path (enum tree_code code,
tree expr,
tree binfo,
- int nonnull)
+ int nonnull,
+ tsubst_flags_t complain)
{
tree v_binfo = NULL_TREE;
tree d_binfo = NULL_TREE;
if (want_pointer)
probe = TYPE_MAIN_VARIANT (TREE_TYPE (probe));
+ if (code == PLUS_EXPR
+ && !SAME_BINFO_TYPE_P (BINFO_TYPE (d_binfo), probe))
+ {
+ /* This can happen when adjust_result_of_qualified_name_lookup can't
+ find a unique base binfo in a call to a member function. We
+ couldn't give the diagnostic then since we might have been calling
+ a static member function, so we do it now. */
+ if (complain & tf_error)
+ {
+ tree base = lookup_base (probe, BINFO_TYPE (d_binfo),
+ ba_unique, NULL);
+ gcc_assert (base == error_mark_node);
+ }
+ return error_mark_node;
+ }
+
gcc_assert ((code == MINUS_EXPR
&& SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), probe))
- || (code == PLUS_EXPR
- && SAME_BINFO_TYPE_P (BINFO_TYPE (d_binfo), probe)));
+ || code == PLUS_EXPR);
if (binfo == d_binfo)
/* Nothing to do. */
if (code == MINUS_EXPR && v_binfo)
{
- error ("cannot convert from base %qT to derived type %qT via virtual base %qT",
- BINFO_TYPE (binfo), BINFO_TYPE (d_binfo), BINFO_TYPE (v_binfo));
+ if (complain & tf_error)
+ error ("cannot convert from base %qT to derived type %qT via "
+ "virtual base %qT", BINFO_TYPE (binfo), BINFO_TYPE (d_binfo),
+ BINFO_TYPE (v_binfo));
return error_mark_node;
}
if (!want_pointer)
/* This must happen before the call to save_expr. */
- expr = cp_build_addr_expr (expr, tf_warning_or_error);
+ expr = cp_build_addr_expr (expr, complain);
else
expr = mark_rvalue_use (expr);
offset = BINFO_OFFSET (binfo);
fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
target_type = code == PLUS_EXPR ? BINFO_TYPE (binfo) : BINFO_TYPE (d_binfo);
+ /* TARGET_TYPE has been extracted from BINFO, and, is therefore always
+ cv-unqualified. Extract the cv-qualifiers from EXPR so that the
+ expression returned matches the input. */
+ target_type = cp_build_qualified_type
+ (target_type, cp_type_quals (TREE_TYPE (TREE_TYPE (expr))));
+ ptr_target_type = build_pointer_type (target_type);
/* Do we need to look in the vtable for the real offset? */
virtual_access = (v_binfo && fixed_type_p <= 0);
/* Don't bother with the calculations inside sizeof; they'll ICE if the
- source type is incomplete and the pointer value doesn't matter. */
- if (cp_unevaluated_operand != 0)
+ source type is incomplete and the pointer value doesn't matter. In a
+ template (even in fold_non_dependent_expr), we don't have vtables set
+ up properly yet, and the value doesn't matter there either; we're just
+ interested in the result of overload resolution. */
+ if (cp_unevaluated_operand != 0
+ || (current_function_decl
+ && uses_template_parms (current_function_decl)))
+ {
+ expr = build_nop (ptr_target_type, expr);
+ if (!want_pointer)
+ expr = build_indirect_ref (EXPR_LOCATION (expr), expr, RO_NULL);
+ 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 = build_nop (build_pointer_type (target_type), expr);
+ 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;
field, because other parts of the compiler know that such
expressions are always non-NULL. */
if (!virtual_access && integer_zerop (offset))
- {
- tree class_type;
- /* TARGET_TYPE has been extracted from BINFO, and, is
- therefore always cv-unqualified. Extract the
- cv-qualifiers from EXPR so that the expression returned
- matches the input. */
- class_type = TREE_TYPE (TREE_TYPE (expr));
- target_type
- = cp_build_qualified_type (target_type,
- cp_type_quals (class_type));
- return build_nop (build_pointer_type (target_type), expr);
- }
+ return build_nop (ptr_target_type, expr);
null_test = error_mark_node;
}
/* Now that we've saved expr, build the real null test. */
if (null_test)
{
- tree zero = cp_convert (TREE_TYPE (expr), integer_zero_node);
+ tree zero = cp_convert (TREE_TYPE (expr), nullptr_node);
null_test = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
expr, zero);
}
interesting to the optimizers anyway. */
&& !has_empty)
{
- expr = cp_build_indirect_ref (expr, RO_NULL, tf_warning_or_error);
+ expr = cp_build_indirect_ref (expr, RO_NULL, complain);
expr = build_simple_base_path (expr, binfo);
if (want_pointer)
expr = build_address (expr);
t = TREE_TYPE (TYPE_VFIELD (current_class_type));
t = build_pointer_type (t);
v_offset = convert (t, current_vtt_parm);
- v_offset = cp_build_indirect_ref (v_offset, RO_NULL,
- tf_warning_or_error);
+ v_offset = cp_build_indirect_ref (v_offset, RO_NULL, complain);
}
else
v_offset = build_vfield_ref (cp_build_indirect_ref (expr, RO_NULL,
- tf_warning_or_error),
+ complain),
TREE_TYPE (TREE_TYPE (expr)));
- v_offset = build2 (POINTER_PLUS_EXPR, TREE_TYPE (v_offset),
- v_offset, fold_convert (sizetype, BINFO_VPTR_FIELD (v_binfo)));
+ v_offset = fold_build_pointer_plus (v_offset, BINFO_VPTR_FIELD (v_binfo));
v_offset = build1 (NOP_EXPR,
build_pointer_type (ptrdiff_type_node),
v_offset);
- v_offset = cp_build_indirect_ref (v_offset, RO_NULL, tf_warning_or_error);
+ v_offset = cp_build_indirect_ref (v_offset, RO_NULL, complain);
TREE_CONSTANT (v_offset) = 1;
offset = convert_to_integer (ptrdiff_type_node,
offset = v_offset;
}
- target_type = cp_build_qualified_type
- (target_type, cp_type_quals (TREE_TYPE (TREE_TYPE (expr))));
- ptr_target_type = build_pointer_type (target_type);
if (want_pointer)
target_type = ptr_target_type;
offset = fold_convert (sizetype, offset);
if (code == MINUS_EXPR)
offset = fold_build1_loc (input_location, NEGATE_EXPR, sizetype, offset);
- expr = build2 (POINTER_PLUS_EXPR, ptr_target_type, expr, offset);
+ expr = fold_build_pointer_plus (expr, offset);
}
else
null_test = NULL;
if (!want_pointer)
- expr = cp_build_indirect_ref (expr, RO_NULL, tf_warning_or_error);
+ expr = cp_build_indirect_ref (expr, RO_NULL, complain);
out:
if (null_test)
/* Is this the base field created by build_base_field? */
if (TREE_CODE (field) == FIELD_DECL
&& DECL_FIELD_IS_BASE (field)
- && TREE_TYPE (field) == type)
+ && TREE_TYPE (field) == type
+ /* If we're looking for a field in the most-derived class,
+ also check the field offset; we can have two base fields
+ of the same type if one is an indirect virtual base and one
+ is a direct non-virtual base. */
+ && (BINFO_INHERITANCE_CHAIN (d_binfo)
+ || tree_int_cst_equal (byte_position (field),
+ BINFO_OFFSET (binfo))))
{
/* We don't use build_class_member_access_expr here, as that
has unnecessary checks, and more importantly results in
if (!binfo || binfo == error_mark_node)
return error_mark_node;
- return build_base_path (PLUS_EXPR, object, binfo, nonnull);
+ return build_base_path (PLUS_EXPR, object, binfo, nonnull, complain);
}
/* EXPR is an expression with unqualified class type. BASE is a base
expr_type = TREE_TYPE (expr);
if (!SAME_BINFO_TYPE_P (BINFO_TYPE (base), expr_type))
{
- tree pointer_type;
-
- pointer_type = build_pointer_type (expr_type);
+ /* If this is a non-empty base, use a COMPONENT_REF. */
+ if (!is_empty_class (BINFO_TYPE (base)))
+ return build_simple_base_path (expr, base);
/* We use fold_build2 and fold_convert below to simplify the trees
provided to the optimizers. It is not safe to call these functions
gcc_assert (!processing_template_decl);
expr = cp_build_addr_expr (expr, tf_warning_or_error);
if (!integer_zerop (BINFO_OFFSET (base)))
- expr = fold_build2_loc (input_location,
- POINTER_PLUS_EXPR, pointer_type, expr,
- fold_convert (sizetype, BINFO_OFFSET (base)));
+ expr = fold_build_pointer_plus_loc (input_location,
+ expr, BINFO_OFFSET (base));
expr = fold_convert (build_pointer_type (BINFO_TYPE (base)), expr);
expr = build_fold_indirect_ref_loc (input_location, expr);
}
the abstract. */
void
-set_linkage_according_to_type (tree type, tree decl)
+set_linkage_according_to_type (tree type ATTRIBUTE_UNUSED, tree decl)
{
- /* If TYPE involves a local class in a function with internal
- linkage, then DECL should have internal linkage too. Other local
- classes have no linkage -- but if their containing functions
- have external linkage, it makes sense for DECL to have external
- linkage too. That will allow template definitions to be merged,
- for example. */
- if (no_linkage_check (type, /*relaxed_p=*/true))
- {
- TREE_PUBLIC (decl) = 0;
- DECL_INTERFACE_KNOWN (decl) = 1;
- }
- else
- TREE_PUBLIC (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ determine_visibility (decl);
}
/* Create a VAR_DECL for a primary or secondary vtable for CLASS_TYPE.
if (DECL_CONTEXT (fn) == type)
/* Defer to the local function. */
return false;
- if (DECL_CONTEXT (fn) == DECL_CONTEXT (method))
- error ("repeated using declaration %q+D", using_decl);
- else
- error ("using declaration %q+D conflicts with a previous using declaration",
- using_decl);
}
else
{
/* Add the new binding. */
overload = build_overload (method, current_fns);
+ if (using_decl && TREE_CODE (overload) == OVERLOAD)
+ OVL_USED (overload) = true;
if (conv_p)
TYPE_HAS_CONVERSION (type) = 1;
gcc_assert (!processing_template_decl && decl);
- old_value = lookup_member (t, name, /*protect=*/0, /*want_type=*/false);
+ old_value = lookup_member (t, name, /*protect=*/0, /*want_type=*/false,
+ tf_warning_or_error);
if (old_value)
{
if (is_overloaded_fn (old_value))
int* no_const_asn_ref_p)
{
int i;
- int seen_non_virtual_nearly_empty_base_p;
+ bool seen_non_virtual_nearly_empty_base_p = 0;
+ int seen_tm_mask = 0;
tree base_binfo;
tree binfo;
tree field = NULL_TREE;
- seen_non_virtual_nearly_empty_base_p = 0;
-
if (!CLASSTYPE_NON_STD_LAYOUT (t))
for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
break;
}
}
+
+ /* Don't bother collecting tm attributes if transactional memory
+ support is not enabled. */
+ if (flag_tm)
+ {
+ tree tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (basetype));
+ if (tm_attr)
+ seen_tm_mask |= tm_attr_to_mask (tm_attr);
+ }
+ }
+
+ /* If one of the base classes had TM attributes, and the current class
+ doesn't define its own, then the current class inherits one. */
+ if (seen_tm_mask && !find_tm_attribute (TYPE_ATTRIBUTES (t)))
+ {
+ tree tm_attr = tm_mask_to_attr (seen_tm_mask & -seen_tm_mask);
+ TYPE_ATTRIBUTES (t) = tree_cons (tm_attr, NULL, TYPE_ATTRIBUTES (t));
}
}
else
BV_VCALL_INDEX (*virtuals) = NULL_TREE;
- if (lost)
- BV_LOST_PRIMARY (*virtuals) = true;
+ BV_LOST_PRIMARY (*virtuals) = lost;
}
/* Called from modify_all_vtables via dfs_walk. */
int cant_have_const_cctor,
int cant_have_const_assignment)
{
+ bool move_ok = false;
+
+ if (cxx_dialect >= cxx0x && !CLASSTYPE_DESTRUCTORS (t)
+ && !TYPE_HAS_COPY_CTOR (t) && !TYPE_HAS_COPY_ASSIGN (t)
+ && !type_has_move_constructor (t) && !type_has_move_assign (t))
+ move_ok = true;
+
/* Destructor. */
if (!CLASSTYPE_DESTRUCTORS (t))
{
CLASSTYPE_LAZY_DEFAULT_CTOR (t) = 1;
if (cxx_dialect >= cxx0x)
TYPE_HAS_CONSTEXPR_CTOR (t)
- = synthesized_default_constructor_is_constexpr (t);
+ /* This might force the declaration. */
+ = type_has_constexpr_default_constructor (t);
}
/* [class.ctor]
If a class definition does not explicitly declare a copy
constructor, one is declared implicitly. */
- if (! TYPE_HAS_COPY_CTOR (t) && ! TYPE_FOR_JAVA (t)
- && !type_has_move_constructor (t))
+ if (! TYPE_HAS_COPY_CTOR (t) && ! TYPE_FOR_JAVA (t))
{
TYPE_HAS_COPY_CTOR (t) = 1;
TYPE_HAS_CONST_COPY_CTOR (t) = !cant_have_const_cctor;
CLASSTYPE_LAZY_COPY_CTOR (t) = 1;
- if (cxx_dialect >= cxx0x)
+ if (move_ok)
CLASSTYPE_LAZY_MOVE_CTOR (t) = 1;
}
when it is needed. For now, just record whether or not the type
of the parameter to the assignment operator will be a const or
non-const reference. */
- if (!TYPE_HAS_COPY_ASSIGN (t) && !TYPE_FOR_JAVA (t)
- && !type_has_move_assign (t))
+ if (!TYPE_HAS_COPY_ASSIGN (t) && !TYPE_FOR_JAVA (t))
{
TYPE_HAS_COPY_ASSIGN (t) = 1;
TYPE_HAS_CONST_COPY_ASSIGN (t) = !cant_have_const_assignment;
CLASSTYPE_LAZY_COPY_ASSIGN (t) = 1;
- if (cxx_dialect >= cxx0x)
+ if (move_ok)
CLASSTYPE_LAZY_MOVE_ASSIGN (t) = 1;
}
if (!warned && errorcount > oldcount)
{
inform (DECL_SOURCE_LOCATION (field), "unrestricted unions "
- "only available with -std=c++0x or -std=gnu++0x");
+ "only available with -std=c++11 or -std=gnu++11");
warned = true;
}
}
{
/* `build_class_init_list' does not recognize
non-FIELD_DECLs. */
- if (TREE_CODE (t) == UNION_TYPE && any_default_members != 0)
+ if (TREE_CODE (t) == UNION_TYPE && *any_default_members != 0)
error ("multiple fields in union %qT initialized", t);
*any_default_members = 1;
}
if (TREE_CODE (x) == USING_DECL)
{
- /* Prune the access declaration from the list of fields. */
- *field = DECL_CHAIN (x);
-
/* Save the access declarations for our caller. */
*access_decls = tree_cons (NULL_TREE, x, *access_decls);
-
- /* Since we've reset *FIELD there's no reason to skip to the
- next field. */
- next = field;
continue;
}
CLASSTYPE_NON_AGGREGATE (t) = 1;
/* If at least one non-static data member is non-literal, the whole
- class becomes non-literal. */
- if (!literal_type_p (type))
+ class becomes non-literal. Note: if the type is incomplete we
+ will complain later on. */
+ if (COMPLETE_TYPE_P (type) && !literal_type_p (type))
CLASSTYPE_LITERAL_P (t) = false;
/* A standard-layout class is a class that:
no_const_asn_ref_p,
&any_default_members);
+ /* Now that we've removed bit-field widths from DECL_INITIAL,
+ anything left in DECL_INITIAL is an NSDMI that makes the class
+ non-aggregate. */
+ if (DECL_INITIAL (x))
+ CLASSTYPE_NON_AGGREGATE (t) = true;
+
/* If any field is const, the structure type is pseudo-const. */
if (CP_TYPE_CONST_P (type))
{
" but does not override %<operator=(const %T&)%>", t);
}
+ /* Non-static data member initializers make the default constructor
+ non-trivial. */
+ if (any_default_members)
+ {
+ TYPE_NEEDS_CONSTRUCTING (t) = true;
+ TYPE_HAS_COMPLEX_DFLT (t) = true;
+ }
+
/* If any of the fields couldn't be packed, unset TYPE_PACKED. */
if (cant_pack)
TYPE_PACKED (t) = 0;
clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
}
+/* Subroutine of set_one_vmethod_tm_attributes. Search base classes
+ of TYPE for virtual functions which FNDECL overrides. Return a
+ mask of the tm attributes found therein. */
+
+static int
+look_for_tm_attr_overrides (tree type, tree fndecl)
+{
+ tree binfo = TYPE_BINFO (type);
+ tree base_binfo;
+ int ix, found = 0;
+
+ for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ++ix)
+ {
+ tree o, basetype = BINFO_TYPE (base_binfo);
+
+ if (!TYPE_POLYMORPHIC_P (basetype))
+ continue;
+
+ o = look_for_overrides_here (basetype, fndecl);
+ if (o)
+ found |= tm_attr_to_mask (find_tm_attribute
+ (TYPE_ATTRIBUTES (TREE_TYPE (o))));
+ else
+ found |= look_for_tm_attr_overrides (basetype, fndecl);
+ }
+
+ return found;
+}
+
+/* Subroutine of set_method_tm_attributes. Handle the checks and
+ inheritance for one virtual method FNDECL. */
+
+static void
+set_one_vmethod_tm_attributes (tree type, tree fndecl)
+{
+ tree tm_attr;
+ int found, have;
+
+ found = look_for_tm_attr_overrides (type, fndecl);
+
+ /* If FNDECL doesn't actually override anything (i.e. T is the
+ class that first declares FNDECL virtual), then we're done. */
+ if (found == 0)
+ return;
+
+ tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (TREE_TYPE (fndecl)));
+ have = tm_attr_to_mask (tm_attr);
+
+ /* Intel STM Language Extension 3.0, Section 4.2 table 4:
+ tm_pure must match exactly, otherwise no weakening of
+ tm_safe > tm_callable > nothing. */
+ /* ??? The tm_pure attribute didn't make the transition to the
+ multivendor language spec. */
+ if (have == TM_ATTR_PURE)
+ {
+ if (found != TM_ATTR_PURE)
+ {
+ found &= -found;
+ goto err_override;
+ }
+ }
+ /* If the overridden function is tm_pure, then FNDECL must be. */
+ else if (found == TM_ATTR_PURE && tm_attr)
+ goto err_override;
+ /* Look for base class combinations that cannot be satisfied. */
+ else if (found != TM_ATTR_PURE && (found & TM_ATTR_PURE))
+ {
+ found &= ~TM_ATTR_PURE;
+ found &= -found;
+ error_at (DECL_SOURCE_LOCATION (fndecl),
+ "method overrides both %<transaction_pure%> and %qE methods",
+ tm_mask_to_attr (found));
+ }
+ /* If FNDECL did not declare an attribute, then inherit the most
+ restrictive one. */
+ else if (tm_attr == NULL)
+ {
+ apply_tm_attr (fndecl, tm_mask_to_attr (found & -found));
+ }
+ /* Otherwise validate that we're not weaker than a function
+ that is being overridden. */
+ else
+ {
+ found &= -found;
+ if (found <= TM_ATTR_CALLABLE && have > found)
+ goto err_override;
+ }
+ return;
+
+ err_override:
+ error_at (DECL_SOURCE_LOCATION (fndecl),
+ "method declared %qE overriding %qE method",
+ tm_attr, tm_mask_to_attr (found));
+}
+
+/* For each of the methods in T, propagate a class-level tm attribute. */
+
+static void
+set_method_tm_attributes (tree t)
+{
+ tree class_tm_attr, fndecl;
+
+ /* Don't bother collecting tm attributes if transactional memory
+ support is not enabled. */
+ if (!flag_tm)
+ return;
+
+ /* Process virtual methods first, as they inherit directly from the
+ base virtual function and also require validation of new attributes. */
+ if (TYPE_CONTAINS_VPTR_P (t))
+ {
+ tree vchain;
+ for (vchain = BINFO_VIRTUALS (TYPE_BINFO (t)); vchain;
+ vchain = TREE_CHAIN (vchain))
+ {
+ fndecl = BV_FN (vchain);
+ if (DECL_THUNK_P (fndecl))
+ fndecl = THUNK_TARGET (fndecl);
+ set_one_vmethod_tm_attributes (t, fndecl);
+ }
+ }
+
+ /* If the class doesn't have an attribute, nothing more to do. */
+ class_tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (t));
+ if (class_tm_attr == NULL)
+ return;
+
+ /* Any method that does not yet have a tm attribute inherits
+ the one from the class. */
+ for (fndecl = TYPE_METHODS (t); fndecl; fndecl = TREE_CHAIN (fndecl))
+ {
+ if (!find_tm_attribute (TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
+ apply_tm_attr (fndecl, class_tm_attr);
+ }
+}
+
/* Returns true iff class T has a user-defined constructor other than
the default constructor. */
return false;
}
-/* Returns true iff for class T, a synthesized default constructor
+/* If default-initialization leaves part of TYPE uninitialized, returns
+ a DECL for the field or TYPE itself (DR 253). */
+
+tree
+default_init_uninitialized_part (tree type)
+{
+ tree t, r, binfo;
+ int i;
+
+ type = strip_array_types (type);
+ if (!CLASS_TYPE_P (type))
+ return type;
+ if (type_has_user_provided_default_constructor (type))
+ return NULL_TREE;
+ for (binfo = TYPE_BINFO (type), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, t); ++i)
+ {
+ r = default_init_uninitialized_part (BINFO_TYPE (t));
+ if (r)
+ return r;
+ }
+ for (t = TYPE_FIELDS (type); t; t = DECL_CHAIN (t))
+ if (TREE_CODE (t) == FIELD_DECL
+ && !DECL_ARTIFICIAL (t)
+ && !DECL_INITIAL (t))
+ {
+ r = default_init_uninitialized_part (TREE_TYPE (t));
+ if (r)
+ return DECL_P (r) ? r : t;
+ }
+
+ return NULL_TREE;
+}
+
+/* Returns true iff for class T, a trivial synthesized default constructor
would be constexpr. */
bool
-synthesized_default_constructor_is_constexpr (tree t)
+trivial_default_constructor_is_constexpr (tree t)
{
- /* A defaulted default constructor is constexpr
+ /* A defaulted trivial default constructor is constexpr
if there is nothing to initialize. */
- /* FIXME adjust for non-static data member initializers. */
+ gcc_assert (!TYPE_HAS_COMPLEX_DFLT (t));
return is_really_empty_class (t);
}
return false;
}
if (CLASSTYPE_LAZY_DEFAULT_CTOR (t))
- return synthesized_default_constructor_is_constexpr (t);
+ {
+ if (!TYPE_HAS_COMPLEX_DFLT (t))
+ return trivial_default_constructor_is_constexpr (t);
+ /* Non-trivial, we need to check subobject constructors. */
+ lazily_declare_fn (sfk_constructor, t);
+ }
fns = locate_ctor (t);
return (fns && DECL_DECLARED_CONSTEXPR_P (fns));
}
lazily_declare_fn (sfk_move_assignment, t);
}
- for (fns = lookup_fnfields_slot (t, ansi_assopname (NOP_EXPR));
+ for (fns = lookup_fnfields_slot_nolazy (t, ansi_assopname (NOP_EXPR));
fns; fns = OVL_NEXT (fns))
if (move_fn_p (OVL_CURRENT (fns)))
return true;
return false;
}
+/* Returns true iff class T has a move constructor that was explicitly
+ declared in the class body. Note that this is different from
+ "user-provided", which doesn't include functions that are defaulted in
+ the class. */
+
+bool
+type_has_user_declared_move_constructor (tree t)
+{
+ tree fns;
+
+ if (CLASSTYPE_LAZY_MOVE_CTOR (t))
+ return false;
+
+ if (!CLASSTYPE_METHOD_VEC (t))
+ return false;
+
+ for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+ {
+ tree fn = OVL_CURRENT (fns);
+ if (move_fn_p (fn) && !DECL_ARTIFICIAL (fn))
+ return true;
+ }
+
+ return false;
+}
+
+/* Returns true iff class T has a move assignment operator that was
+ explicitly declared in the class body. */
+
+bool
+type_has_user_declared_move_assign (tree t)
+{
+ tree fns;
+
+ if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
+ return false;
+
+ for (fns = lookup_fnfields_slot_nolazy (t, ansi_assopname (NOP_EXPR));
+ fns; fns = OVL_NEXT (fns))
+ {
+ tree fn = OVL_CURRENT (fns);
+ if (move_fn_p (fn) && !DECL_ARTIFICIAL (fn))
+ return true;
+ }
+
+ return false;
+}
+
/* Nonzero if we need to build up a constructor call when initializing an
object of this class, either because it has a user-provided constructor
or because it doesn't have a default constructor (so we need to give an
static void
finalize_literal_type_property (tree t)
{
+ tree fn;
+
if (cxx_dialect < cxx0x
- || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
- /* FIXME These constraints seem unnecessary; remove from standard.
- || !TYPE_HAS_TRIVIAL_COPY_CTOR (t)
- || TYPE_HAS_COMPLEX_MOVE_CTOR (t)*/ )
+ || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
CLASSTYPE_LITERAL_P (t) = false;
else if (CLASSTYPE_LITERAL_P (t) && !TYPE_HAS_TRIVIAL_DFLT (t)
+ && CLASSTYPE_NON_AGGREGATE (t)
&& !TYPE_HAS_CONSTEXPR_CTOR (t))
CLASSTYPE_LITERAL_P (t) = false;
+
+ if (!CLASSTYPE_LITERAL_P (t))
+ for (fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn))
+ if (DECL_DECLARED_CONSTEXPR_P (fn)
+ && TREE_CODE (fn) != TEMPLATE_DECL
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
+ && !DECL_CONSTRUCTOR_P (fn))
+ {
+ DECL_DECLARED_CONSTEXPR_P (fn) = false;
+ if (!DECL_GENERATED_P (fn))
+ {
+ error ("enclosing class of constexpr non-static member "
+ "function %q+#D is not a literal type", fn);
+ explain_non_literal_class (t);
+ }
+ }
+}
+
+/* T is a non-literal type used in a context which requires a constant
+ expression. Explain why it isn't literal. */
+
+void
+explain_non_literal_class (tree t)
+{
+ static struct pointer_set_t *diagnosed;
+
+ if (!CLASS_TYPE_P (t))
+ return;
+ t = TYPE_MAIN_VARIANT (t);
+
+ if (diagnosed == NULL)
+ diagnosed = pointer_set_create ();
+ if (pointer_set_insert (diagnosed, t) != 0)
+ /* Already explained. */
+ return;
+
+ inform (0, "%q+T is not literal because:", t);
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+ inform (0, " %q+T has a non-trivial destructor", t);
+ else if (CLASSTYPE_NON_AGGREGATE (t)
+ && !TYPE_HAS_TRIVIAL_DFLT (t)
+ && !TYPE_HAS_CONSTEXPR_CTOR (t))
+ {
+ inform (0, " %q+T is not an aggregate, does not have a trivial "
+ "default constructor, and has no constexpr constructor that "
+ "is not a copy or move constructor", t);
+ if (TYPE_HAS_DEFAULT_CONSTRUCTOR (t)
+ && !type_has_user_provided_default_constructor (t))
+ {
+ /* Note that we can't simply call locate_ctor because when the
+ constructor is deleted it just returns NULL_TREE. */
+ tree fns;
+ for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+ {
+ tree fn = OVL_CURRENT (fns);
+ tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
+
+ parms = skip_artificial_parms_for (fn, parms);
+
+ if (sufficient_parms_p (parms))
+ {
+ if (DECL_DELETED_FN (fn))
+ maybe_explain_implicit_delete (fn);
+ else
+ explain_invalid_constexpr_fn (fn);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ tree binfo, base_binfo, field; int i;
+ for (binfo = TYPE_BINFO (t), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree basetype = TREE_TYPE (base_binfo);
+ if (!CLASSTYPE_LITERAL_P (basetype))
+ {
+ inform (0, " base class %qT of %q+T is non-literal",
+ basetype, t);
+ explain_non_literal_class (basetype);
+ return;
+ }
+ }
+ for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
+ {
+ tree ftype;
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+ ftype = TREE_TYPE (field);
+ if (!literal_type_p (ftype))
+ {
+ inform (0, " non-static data member %q+D has "
+ "non-literal type", field);
+ if (CLASS_TYPE_P (ftype))
+ explain_non_literal_class (ftype);
+ }
+ }
+ }
}
/* Check the validity of the bases and members declared in T. Add any
return;
}
+
+/* Allocate and return an instance of struct sorted_fields_type with
+ N fields. */
+
+static struct sorted_fields_type *
+sorted_fields_type_new (int n)
+{
+ struct sorted_fields_type *sft;
+ sft = ggc_alloc_sorted_fields_type (sizeof (struct sorted_fields_type)
+ + n * sizeof (tree));
+ sft->len = n;
+
+ return sft;
+}
+
+
/* Perform processing required when the definition of T (a class type)
is complete. */
}
finish_struct_bits (t);
+ set_method_tm_attributes (t);
/* Complete the rtl for any static member objects of the type we're
working on. */
n_fields = count_fields (TYPE_FIELDS (t));
if (n_fields > 7)
{
- struct sorted_fields_type *field_vec = ggc_alloc_sorted_fields_type
- (sizeof (struct sorted_fields_type) + n_fields * sizeof (tree));
- field_vec->len = n_fields;
+ struct sorted_fields_type *field_vec = sorted_fields_type_new (n_fields);
add_fields_to_record_type (TYPE_FIELDS (t), field_vec, 0);
qsort (field_vec->elts, n_fields, sizeof (tree),
field_decl_cmp);
/* Finish debugging output for this type. */
rest_of_type_compilation (t, ! LOCAL_CLASS_P (t));
+
+ if (TYPE_TRANSPARENT_AGGR (t))
+ {
+ tree field = first_field (t);
+ if (field == NULL_TREE || error_operand_p (field))
+ {
+ error ("type transparent class %qT does not have any fields", t);
+ TYPE_TRANSPARENT_AGGR (t) = 0;
+ }
+ else if (DECL_ARTIFICIAL (field))
+ {
+ if (DECL_FIELD_IS_BASE (field))
+ error ("type transparent class %qT has base classes", t);
+ else
+ {
+ gcc_checking_assert (DECL_VIRTUAL_P (field));
+ error ("type transparent class %qT has virtual functions", t);
+ }
+ TYPE_TRANSPARENT_AGGR (t) = 0;
+ }
+ }
}
/* When T was built up, the member declarations were added in reverse
if (DECL_PURE_VIRTUAL_P (x))
VEC_safe_push (tree, gc, CLASSTYPE_PURE_VIRTUALS (t), x);
complete_vars (t);
+ /* We need to add the target functions to the CLASSTYPE_METHOD_VEC if
+ an enclosing scope is a template class, so that this function be
+ found by lookup_fnfields_1 when the using declaration is not
+ instantiated yet. */
+ for (x = TYPE_FIELDS (t); x; x = DECL_CHAIN (x))
+ if (TREE_CODE (x) == USING_DECL)
+ {
+ tree fn = strip_using_decl (x);
+ if (is_overloaded_fn (fn))
+ for (; fn; fn = OVL_NEXT (fn))
+ add_method (t, OVL_CURRENT (fn), x);
+ }
/* Remember current #pragma pack value. */
TYPE_PRECISION (t) = maximum_field_alignment;
else
error ("trying to finish struct, but kicked out due to previous parse errors");
- check_deferred_constexpr_decls ();
-
if (processing_template_decl && at_function_scope_p ())
add_stmt (build_min (TAG_DEFN, t));
if (nonnull)
*nonnull = 1;
- /* if we're in a ctor or dtor, we know our type. */
- if (DECL_LANG_SPECIFIC (current_function_decl)
- && (DECL_CONSTRUCTOR_P (current_function_decl)
- || DECL_DESTRUCTOR_P (current_function_decl)))
+ /* if we're in a ctor or dtor, we know our type. If
+ current_class_ptr is set but we aren't in a function, we're in
+ an NSDMI (and therefore a constructor). */
+ if (current_scope () != current_function_decl
+ || (DECL_LANG_SPECIFIC (current_function_decl)
+ && (DECL_CONSTRUCTOR_P (current_function_decl)
+ || DECL_DESTRUCTOR_P (current_function_decl))))
{
if (cdtorp)
*cdtorp = 1;
targs = make_tree_vec (DECL_NTPARMS (fn));
if (fn_type_unification (fn, explicit_targs, targs, args, nargs,
target_ret_type, DEDUCE_EXACT,
- LOOKUP_NORMAL))
+ LOOKUP_NORMAL, false))
/* Argument deduction failed. */
continue;
else
{
if (flags & tf_error)
- error ("argument of type %qT does not match %qT",
- TREE_TYPE (rhs), lhstype);
+ error ("cannot convert %qE from type %qT to type %qT",
+ rhs, TREE_TYPE (rhs), lhstype);
return error_mark_node;
}
}
- if (TREE_CODE (rhs) == BASELINK)
+ if (BASELINK_P (rhs))
{
access_path = BASELINK_ACCESS_BINFO (rhs);
rhs = BASELINK_FUNCTIONS (rhs);
/* If there's already a binding for this NAME, then we don't have
anything to worry about. */
if (lookup_member (current_class_type, name,
- /*protect=*/0, /*want_type=*/false))
+ /*protect=*/0, /*want_type=*/false, tf_warning_or_error))
return;
if (!current_class_stack[current_class_depth - 1].names_used)
/* Figure out the position to which the VPTR should point. */
vtbl = build1 (ADDR_EXPR, vtbl_ptr_type_node, orig_vtbl);
- index = size_binop (PLUS_EXPR,
- size_int (non_fn_entries),
- size_int (n_inits));
index = size_binop (MULT_EXPR,
TYPE_SIZE_UNIT (vtable_entry_type),
- index);
- vtbl = build2 (POINTER_PLUS_EXPR, TREE_TYPE (vtbl), vtbl, index);
+ size_int (non_fn_entries + n_inits));
+ vtbl = fold_build_pointer_plus (vtbl, index);
}
if (ctor_vtbl_p)
init = abort_fndecl_addr;
}
}
+ /* Likewise for deleted virtuals. */
+ else if (DECL_DELETED_FN (fn_original))
+ {
+ fn = get_identifier ("__cxa_deleted_virtual");
+ if (!get_global_value_if_present (fn, &fn))
+ fn = push_library_fn (fn, (build_function_type_list
+ (void_type_node, NULL_TREE)),
+ NULL_TREE);
+ if (!TARGET_VTABLE_USES_DESCRIPTORS)
+ init = fold_convert (vfunc_ptr_type_node,
+ build_fold_addr_expr (fn));
+ }
else
{
if (!integer_zerop (delta) || vcall_index)