===================================================================
@@ -774,6 +774,17 @@ complete_or_array_type_p (const_tree typ
&& COMPLETE_TYPE_P (TREE_TYPE (type)));
}
+/* Return true if the argument is a definite type or an array
+ of unknown bound (whose type is incomplete but) whose elements
+ have definite (and complete) type. */
+static inline bool
+definite_or_array_type_p (const_tree type)
+{
+ return (DEFINITE_TYPE_P (type)
+ || (TREE_CODE (type) == ARRAY_TYPE
+ && COMPLETE_TYPE_P (TREE_TYPE (type))));
+}
+
struct visibility_flags
{
unsigned inpragma : 1; /* True when in #pragma GCC visibility. */
===================================================================
@@ -2185,10 +2185,10 @@ #define TYPE_HAS_ARRAY_NEW_OPERATOR(NODE
starting the definition of this type has been seen. */
#define TYPE_BEING_DEFINED(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->being_defined)
-/* Nonzero means that this type is either complete or being defined, so we
+/* Nonzero means that this type is either definite or being defined, so we
can do lookup in it. */
-#define COMPLETE_OR_OPEN_TYPE_P(NODE) \
- (COMPLETE_TYPE_P (NODE) || (CLASS_TYPE_P (NODE) && TYPE_BEING_DEFINED (NODE)))
+#define DEFINITE_OR_OPEN_TYPE_P(NODE) \
+ (DEFINITE_TYPE_P (NODE) || (CLASS_TYPE_P (NODE) && TYPE_BEING_DEFINED (NODE)))
/* Mark bits for repeated base checks. */
#define TYPE_MARKED_P(NODE) TREE_LANG_FLAG_6 (TYPE_CHECK (NODE))
@@ -4992,6 +4992,7 @@ enum tag_types {
none_type = 0, /* Not a tag type. */
record_type, /* "struct" types. */
class_type, /* "class" types. */
+ sizeless_struct_type, /* "__sizeless_struct" types. */
union_type, /* "union" types. */
enum_type, /* "enum" types. */
typename_type, /* "typename" types. */
@@ -7234,10 +7235,12 @@ extern int string_conv_p (const_tree,
extern tree cp_truthvalue_conversion (tree);
extern tree condition_conversion (tree);
extern tree require_complete_type (tree);
-extern tree require_complete_type_sfinae (tree, tsubst_flags_t);
+extern tree require_complete_type_sfinae (tree, tsubst_flags_t,
+ bool = false);
extern tree complete_type (tree);
-extern tree complete_type_or_else (tree, tree);
-extern tree complete_type_or_maybe_complain (tree, tree, tsubst_flags_t);
+extern tree complete_type_or_else (tree, tree, bool = false);
+extern tree complete_type_or_maybe_complain (tree, tree, tsubst_flags_t,
+ bool = false);
inline bool type_unknown_p (const_tree);
enum { ce_derived, ce_type, ce_normal, ce_exact };
extern bool comp_except_specs (const_tree, const_tree, int);
@@ -7654,6 +7657,39 @@ null_node_p (const_tree expr)
return expr == null_node;
}
+/* Do:
+
+ value = require_definite_type_sfinae (value, complain);
+
+ to make sure VALUE does not have an indefinite type. (Void types are
+ always indefinite.) Return error_mark_node if VALUE is not definite. */
+
+inline tree
+require_definite_type_sfinae (tree value, tsubst_flags_t complain)
+{
+ return require_complete_type_sfinae (value, complain, true);
+}
+
+/* Like complete_type, but check whether the result is definite. Return
+ NULL_TREE if the type doesn't meet this condition, and also report an
+ error if COMPLAIN allows. VALUE is used for informative diagnostics. */
+
+inline tree
+definite_type_or_maybe_complain (tree type, tree value,
+ tsubst_flags_t complain)
+{
+ return complete_type_or_maybe_complain (type, value, complain, true);
+}
+
+/* Like complete_type, but report an error and return NULL_TREE if the
+ result isn't a definite type. */
+
+inline tree
+definite_type_or_else (tree type, tree value)
+{
+ return complete_type_or_else (type, value, true);
+}
+
#if CHECKING_P
namespace selftest {
extern void run_cp_tests (void);
===================================================================
@@ -1745,7 +1745,7 @@ reference_binding (tree rto, tree rfrom,
but if TO is an incomplete class, we need to reject this conversion
now to avoid unnecessary instantiation. */
if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto)
- && !COMPLETE_TYPE_P (to))
+ && !DEFINITE_TYPE_P (to))
return NULL;
/* We're generating a temporary now, but don't bind any more in the
@@ -1845,7 +1845,7 @@ implicit_conversion (tree to, tree from,
/* Call reshape_init early to remove redundant braces. */
if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr)
&& CLASS_TYPE_P (to)
- && COMPLETE_TYPE_P (complete_type (to))
+ && DEFINITE_TYPE_P (complete_type (to))
&& !CLASSTYPE_NON_AGGREGATE (to))
{
expr = reshape_init (to, expr, complain);
@@ -2606,6 +2606,8 @@ add_builtin_candidate (struct z_candidat
if (MAYBE_CLASS_TYPE_P (c1) && DERIVED_FROM_P (c2, c1)
&& (TYPE_PTRMEMFUNC_P (type2)
+ /* Correct for sizeless types since we don't allow
+ pointers to member variables for them. */
|| is_complete (TYPE_PTRMEM_POINTED_TO_TYPE (type2))))
break;
}
@@ -6280,6 +6282,7 @@ build_op_delete_call (enum tree_code cod
fnname = ovl_op_identifier (false, code);
if (CLASS_TYPE_P (type)
+ /* OK for sizeless types, which can't be deleted. */
&& COMPLETE_TYPE_P (complete_type (type))
&& !global_p)
/* In [class.free]
@@ -6433,6 +6436,8 @@ build_op_delete_call (enum tree_code cod
with a parameter of type std::size_t is selected. */
else
{
+ /* Doesn't matter for sizeless types, since those can't
+ be in arrays and can't be deleted. */
want_size = COMPLETE_TYPE_P (type);
if (code == VEC_DELETE_EXPR
&& !TYPE_VEC_NEW_USES_COOKIE (type))
@@ -6981,6 +6986,8 @@ convert_like_real (conversion *convs, tr
/* Build up the initializer_list object. Note: fail gracefully
if the object cannot be completed because, for example, no
definition is provided (c++/80956). */
+ /* Not relevant for sizeless type; std::initializer_list can
+ never be sizeless. */
totype = complete_type_or_maybe_complain (totype, NULL_TREE, complain);
if (!totype)
return error_mark_node;
@@ -7290,14 +7297,14 @@ convert_arg_to_ellipsis (tree arg, tsubs
arg = cp_perform_integral_promotions (arg, complain);
}
- arg = require_complete_type_sfinae (arg, complain);
+ arg = require_definite_type_sfinae (arg, complain);
arg_type = TREE_TYPE (arg);
if (arg != error_mark_node
/* In a template (or ill-formed code), we can have an incomplete type
even after require_complete_type_sfinae, in which case we don't know
whether it has trivial copy or not. */
- && COMPLETE_TYPE_P (arg_type)
+ && DEFINITE_TYPE_P (arg_type)
&& !cp_unevaluated_operand)
{
/* [expr.call] 5.2.2/7:
@@ -7344,7 +7351,7 @@ build_x_va_arg (source_location loc, tre
return r;
}
- type = complete_type_or_else (type, NULL_TREE);
+ type = definite_type_or_else (type, NULL_TREE);
if (expr == error_mark_node || !type)
return error_mark_node;
@@ -8650,7 +8657,7 @@ maybe_warn_class_memaccess (location_t l
a complete class type. */
tree desttype = TREE_TYPE (TREE_TYPE (dest));
- if (!desttype || !COMPLETE_TYPE_P (desttype) || !CLASS_TYPE_P (desttype))
+ if (!desttype || !DEFINITE_TYPE_P (desttype) || !CLASS_TYPE_P (desttype))
return;
/* Check to see if the raw memory call is made by a non-static member
@@ -8934,7 +8941,7 @@ build_cxx_call (tree fn, int nargs, tree
prvalue. The type of the prvalue may be incomplete. */
if (!(complain & tf_decltype))
{
- fn = require_complete_type_sfinae (fn, complain);
+ fn = require_definite_type_sfinae (fn, complain);
if (fn == error_mark_node)
return error_mark_node;
@@ -9025,7 +9032,7 @@ build_special_member_call (tree instance
if (TYPE_P (binfo))
{
/* Resolve the name. */
- if (!complete_type_or_maybe_complain (binfo, NULL_TREE, complain))
+ if (!definite_type_or_maybe_complain (binfo, NULL_TREE, complain))
return error_mark_node;
binfo = TYPE_BINFO (binfo);
@@ -9276,7 +9283,7 @@ complain_about_no_candidates_for_method_
vec<tree, va_gc> *user_args)
{
auto_diagnostic_group d;
- if (!COMPLETE_OR_OPEN_TYPE_P (basetype))
+ if (!DEFINITE_OR_OPEN_TYPE_P (basetype))
cxx_incomplete_type_error (instance, basetype);
else if (optype)
error ("no matching function for call to %<%T::operator %T(%A)%#V%>",
===================================================================
@@ -369,6 +369,8 @@ build_base_path (enum tree_code code,
goto indout;
}
+ /* Shouldn't reach here for sizeless types, since they can't have base
+ classes or be used as base classes. */
if (!COMPLETE_TYPE_P (probe))
{
if (complain & tf_error)
@@ -1142,7 +1144,7 @@ add_method (tree type, tree method, bool
current_fns = ovl_insert (method, current_fns, via_using);
- if (!COMPLETE_TYPE_P (type) && !DECL_CONV_FN_P (method)
+ if (!DEFINITE_TYPE_P (type) && !DECL_CONV_FN_P (method)
&& !push_class_level_binding (DECL_NAME (method), current_fns))
return false;
@@ -1642,6 +1644,7 @@ check_bases (tree t,
{
tree basetype = TREE_TYPE (base_binfo);
+ /* Correct for sizeless types, since they can never be base classes. */
gcc_assert (COMPLETE_TYPE_P (basetype));
if (CLASSTYPE_FINAL (basetype))
@@ -3503,6 +3506,8 @@ check_field_decls (tree t, tree *access_
class becomes non-literal. Per Core/1453, volatile non-static
data members and base classes are also not allowed.
Note: if the type is incomplete we will complain later on. */
+ /* Doesn't matter for sizeless types, since they're not literal
+ to start with. */
if (COMPLETE_TYPE_P (type)
&& (!literal_type_p (type) || CP_TYPE_VOLATILE_P (type)))
CLASSTYPE_LITERAL_P (t) = false;
@@ -4307,6 +4312,7 @@ build_base_field (record_layout_info rli
tree t = rli->t;
tree basetype = BINFO_TYPE (binfo);
+ /* Correct for sizeless types, since they can never be base classes. */
if (!COMPLETE_TYPE_P (basetype))
/* This error is now reported in xref_tag, thus giving better
location information. */
@@ -5182,7 +5188,7 @@ type_has_virtual_destructor (tree type)
if (!CLASS_TYPE_P (type))
return false;
- gcc_assert (COMPLETE_TYPE_P (type));
+ gcc_assert (DEFINITE_TYPE_P (type));
dtor = CLASSTYPE_DESTRUCTOR (type);
return (dtor && DECL_VIRTUAL_P (dtor));
}
@@ -5312,7 +5318,7 @@ type_build_dtor_call (tree t)
return true;
inner = strip_array_types (t);
if (!CLASS_TYPE_P (inner) || ANON_AGGR_TYPE_P (inner)
- || !COMPLETE_TYPE_P (inner))
+ || !DEFINITE_TYPE_P (inner))
return false;
if (cxx_dialect < cxx11)
return false;
@@ -6892,7 +6898,7 @@ finish_struct_1 (tree t)
/* A TREE_LIST. The TREE_VALUE of each node is a FUNCTION_DECL. */
tree virtuals = NULL_TREE;
- if (COMPLETE_TYPE_P (t))
+ if (DEFINITE_TYPE_P (t))
{
gcc_assert (MAYBE_CLASS_TYPE_P (t));
error ("redefinition of %q#T", t);
@@ -6910,7 +6916,7 @@ finish_struct_1 (tree t)
CLASSTYPE_EMPTY_P (t) = 1;
CLASSTYPE_NEARLY_EMPTY_P (t) = 1;
CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t) = 0;
- CLASSTYPE_LITERAL_P (t) = true;
+ CLASSTYPE_LITERAL_P (t) = !TYPE_SIZELESS_P (t);
/* Do end-of-class semantic processing: checking the validity of the
bases and members and add implicitly generated methods. */
@@ -8291,7 +8297,7 @@ is_really_empty_class (tree type)
/* CLASSTYPE_EMPTY_P isn't set properly until the class is actually laid
out, but we'd like to be able to check this before then. */
- if (COMPLETE_TYPE_P (type) && is_empty_class (type))
+ if (DEFINITE_TYPE_P (type) && is_empty_class (type))
return true;
for (binfo = TYPE_BINFO (type), i = 0;
===================================================================
@@ -66,7 +66,7 @@ literal_type_p (tree t)
if (CLASS_TYPE_P (t))
{
t = complete_type (t);
- gcc_assert (COMPLETE_TYPE_P (t) || errorcount);
+ gcc_assert (DEFINITE_TYPE_P (t) || errorcount);
return CLASSTYPE_LITERAL_P (t);
}
if (TREE_CODE (t) == ARRAY_TYPE)
@@ -88,7 +88,7 @@ ensure_literal_type_for_constexpr_object
&& !processing_template_decl)
{
tree stype = strip_array_types (type);
- if (CLASS_TYPE_P (stype) && !COMPLETE_TYPE_P (complete_type (stype)))
+ if (CLASS_TYPE_P (stype) && !DEFINITE_TYPE_P (complete_type (stype)))
/* Don't complain here, we'll complain about incompleteness
when we try to initialize the variable. */;
else if (type_uses_auto (type))
@@ -4215,6 +4215,8 @@ cxx_eval_constant_expression (const cons
/* is_really_empty_class doesn't take into account _vptr, so initializing
otherwise empty class with { } would overwrite the initializer that
initialize_vtable created for us. */
+ /* Sizeless structs aren't ever constant expressions, even if they're
+ empty. */
if (COMPLETE_TYPE_P (TREE_TYPE (t))
&& !TYPE_POLYMORPHIC_P (TREE_TYPE (t))
&& is_really_empty_class (TREE_TYPE (t)))
@@ -4264,7 +4266,9 @@ cxx_eval_constant_expression (const cons
/* Defer in case this is only used for its type. */;
else if (TYPE_REF_P (TREE_TYPE (t)))
/* Defer, there's no lvalue->rvalue conversion. */;
- else if (COMPLETE_TYPE_P (TREE_TYPE (t))
+ else if (/* Shouldn't matter for correctness what we do here for sizeless
+ types, since they're always non-literal. */
+ COMPLETE_TYPE_P (TREE_TYPE (t))
&& is_really_empty_class (TREE_TYPE (t)))
{
/* If the class is empty, we aren't actually loading anything. */
@@ -5682,6 +5686,8 @@ #define RECUR(T,RV) \
|| !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (t))
|| (DECL_INITIAL (t)
&& !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t)))
+ /* Shouldn't matter for correctness what we do here for sizeless
+ types, since they're always non-literal. */
&& COMPLETE_TYPE_P (TREE_TYPE (t))
&& !is_really_empty_class (TREE_TYPE (t)))
{
@@ -6019,6 +6025,9 @@ #define RECUR(T,RV) \
might be a constexpr user-defined conversion. */
else if (cxx_dialect >= cxx11
&& (dependent_type_p (TREE_TYPE (t))
+ /* Shouldn't matter what we do here for sizeless types,
+ since they're never literal types. Any user-defined
+ conversion would be an invalid constexpr. */
|| !COMPLETE_TYPE_P (TREE_TYPE (t))
|| literal_type_p (TREE_TYPE (t)))
&& TREE_OPERAND (t, 0))
===================================================================
@@ -2032,6 +2032,8 @@ cxx_omp_finish_clause (tree c, gimple_se
return;
decl = OMP_CLAUSE_DECL (c);
+ /* Correct for sizeless types: we're not changing the OpenMP
+ rules for those. */
decl = require_complete_type (decl);
inner_type = TREE_TYPE (decl);
if (decl == error_mark_node)
@@ -2271,7 +2273,7 @@ cp_fold (tree x)
tree val = get_base_address (op0);
if (val
&& INDIRECT_REF_P (val)
- && COMPLETE_TYPE_P (TREE_TYPE (val))
+ && DEFINITE_TYPE_P (TREE_TYPE (val))
&& TREE_CONSTANT (TREE_OPERAND (val, 0)))
{
val = TREE_OPERAND (val, 0);
===================================================================
@@ -85,7 +85,7 @@ cp_convert_to_pointer (tree type, tree e
if (MAYBE_CLASS_TYPE_P (intype))
{
intype = complete_type (intype);
- if (!COMPLETE_TYPE_P (intype))
+ if (!DEFINITE_TYPE_P (intype))
{
if (complain & tf_error)
error_at (loc, "can%'t convert from incomplete type %qH to %qI",
@@ -1169,10 +1169,10 @@ convert_to_void (tree expr, impl_conv_vo
tree type = TREE_TYPE (expr);
int is_reference = TYPE_REF_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
int is_volatile = TYPE_VOLATILE (type);
- int is_complete = COMPLETE_TYPE_P (complete_type (type));
+ int is_definite = DEFINITE_TYPE_P (complete_type (type));
/* Can't load the value if we don't know the type. */
- if (is_volatile && !is_complete)
+ if (is_volatile && !is_definite)
{
if (complain & tf_warning)
switch (implicit)
@@ -1302,7 +1302,10 @@ convert_to_void (tree expr, impl_conv_vo
gcc_unreachable ();
}
}
- if (is_reference || !is_volatile || !is_complete || TREE_ADDRESSABLE (type))
+ if (is_reference
+ || !is_volatile
+ || !is_definite
+ || TREE_ADDRESSABLE (type))
{
/* Emit a warning (if enabled) when the "effect-less" INDIRECT_REF
operation is stripped off. Note that we don't warn about
@@ -1328,9 +1331,9 @@ convert_to_void (tree expr, impl_conv_vo
{
/* External variables might be incomplete. */
tree type = TREE_TYPE (expr);
- int is_complete = COMPLETE_TYPE_P (complete_type (type));
+ int is_definite = DEFINITE_TYPE_P (complete_type (type));
- if (TYPE_VOLATILE (type) && !is_complete && (complain & tf_warning))
+ if (TYPE_VOLATILE (type) && !is_definite && (complain & tf_warning))
switch (implicit)
{
case ICV_CAST:
@@ -1735,6 +1738,8 @@ build_expr_type_conversion (int desires,
/* The code for conversions from class type is currently only used for
delete expressions. Other expressions are handled by build_new_op. */
+ /* ...shouldn't be relevant for sizeless types in that case, since we
+ can't delete those. */
if (!complete_type_or_maybe_complain (basetype, expr, complain))
return error_mark_node;
if (!TYPE_HAS_CONVERSION (basetype))
===================================================================
@@ -2876,8 +2876,8 @@ redeclaration_error_message (tree newdec
if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
{
- if (COMPLETE_TYPE_P (TREE_TYPE (newdecl))
- && COMPLETE_TYPE_P (TREE_TYPE (olddecl)))
+ if (DEFINITE_TYPE_P (TREE_TYPE (newdecl))
+ && DEFINITE_TYPE_P (TREE_TYPE (olddecl)))
return G_("redefinition of %q#D");
return NULL;
}
@@ -3851,7 +3851,7 @@ make_typename_type (tree context, tree n
{
if (complain & tf_error)
{
- if (!COMPLETE_TYPE_P (context))
+ if (!DEFINITE_TYPE_P (context))
cxx_incomplete_type_error (NULL_TREE, context);
else
error (want_template ? G_("no class template named %q#T in %q#T")
@@ -4740,6 +4740,9 @@ fixup_anonymous_aggr (tree t)
}
}
}
+ if (TYPE_SIZELESS_P (t) && !TYPE_SIZELESS_P (DECL_CONTEXT (TYPE_NAME (t))))
+ error ("%q#T cannot have anonymous sizeless fields",
+ DECL_CONTEXT (TYPE_NAME (t)));
}
/* Warn for an attribute located at LOCATION that appertains to the
@@ -5103,7 +5106,7 @@ start_decl (const cp_declarator *declara
warning_at (DECL_SOURCE_LOCATION (decl), 0,
"inline function %qD given attribute noinline", decl);
- if (TYPE_P (context) && COMPLETE_TYPE_P (complete_type (context)))
+ if (TYPE_P (context) && DEFINITE_TYPE_P (complete_type (context)))
{
bool this_tmpl = (processing_template_decl
> template_class_depth (context));
@@ -5254,7 +5257,7 @@ start_decl (const cp_declarator *declara
start_decl_1 (tree decl, bool initialized)
{
tree type;
- bool complete_p;
+ bool definite_p;
bool aggregate_definition_p;
gcc_assert (!processing_template_decl);
@@ -5265,31 +5268,44 @@ start_decl_1 (tree decl, bool initialize
gcc_assert (VAR_P (decl));
type = TREE_TYPE (decl);
- complete_p = COMPLETE_TYPE_P (type);
+ definite_p = DEFINITE_TYPE_P (type);
aggregate_definition_p = MAYBE_CLASS_TYPE_P (type) && !DECL_EXTERNAL (decl);
/* If an explicit initializer is present, or if this is a definition
- of an aggregate, then we need a complete type at this point.
- (Scalars are always complete types, so there is nothing to
- check.) This code just sets COMPLETE_P; errors (if necessary)
+ of an aggregate, then we need a definite type at this point.
+ (Scalars are always definite types, so there is nothing to
+ check.) This code just sets DEFINITE_P; errors (if necessary)
are issued below. */
if ((initialized || aggregate_definition_p)
- && !complete_p
- && COMPLETE_TYPE_P (complete_type (type)))
+ && !definite_p
+ && DEFINITE_TYPE_P (complete_type (type)))
{
- complete_p = true;
+ definite_p = true;
/* We will not yet have set TREE_READONLY on DECL if the type
- was "const", but incomplete, before this point. But, now, we
- have a complete type, so we can try again. */
+ was "const", but indefinite, before this point. But, now, we
+ have a definite type, so we can try again. */
cp_apply_type_quals_to_decl (cp_type_quals (type), decl);
}
- if (initialized)
+ if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+ && TYPE_SIZELESS_P (type))
+ {
+ if (DECL_THREAD_LOCAL_P (decl))
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "sizeless variable %q#D cannot have thread-local"
+ " storage duration", decl);
+ else
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "sizeless variable %q#D cannot have static storage"
+ " duration", decl);
+ type = TREE_TYPE (decl) = error_mark_node;
+ }
+ else if (initialized)
/* Is it valid for this decl to have an initializer at all? */
{
- /* Don't allow initializations for incomplete types except for
+ /* Don't allow initializations for indefinite types except for
arrays which might be completed by the initialization. */
- if (complete_p)
+ if (definite_p)
; /* A complete type is ok. */
else if (type_uses_auto (type))
; /* An auto type is ok. */
@@ -5298,6 +5314,7 @@ start_decl_1 (tree decl, bool initialize
error ("variable %q#D has initializer but incomplete type", decl);
type = TREE_TYPE (decl) = error_mark_node;
}
+ /* Correct for sizeless types, which aren't allowed in arrays. */
else if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (type))))
{
if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))
@@ -5305,7 +5322,7 @@ start_decl_1 (tree decl, bool initialize
/* else we already gave an error in start_decl. */
}
}
- else if (aggregate_definition_p && !complete_p)
+ else if (aggregate_definition_p && !definite_p)
{
if (type_uses_auto (type))
gcc_assert (CLASS_PLACEHOLDER_TEMPLATE (type));
@@ -5537,7 +5554,7 @@ layout_var_decl (tree decl)
complete_type (type);
if (!DECL_SIZE (decl)
&& TREE_TYPE (decl) != error_mark_node
- && complete_or_array_type_p (type))
+ && definite_or_array_type_p (type))
layout_decl (decl, 0);
if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE)
@@ -6254,6 +6271,7 @@ check_array_initializer (tree decl, tree
/* The array type itself need not be complete, because the
initializer may tell us how many elements are in the array.
But, the elements of the array must be complete. */
+ /* Correct for sizeless types, which aren't allowed in arrays. */
if (!COMPLETE_TYPE_P (complete_type (element_type)))
{
if (decl)
@@ -6265,6 +6283,7 @@ check_array_initializer (tree decl, tree
}
/* A compound literal can't have variable size. */
if (init && !decl
+ /* Correct for sizeless types, which aren't used in arrays. */
&& ((COMPLETE_TYPE_P (type) && !TREE_CONSTANT (TYPE_SIZE (type)))
|| !TREE_CONSTANT (TYPE_SIZE (element_type))))
{
@@ -6320,7 +6339,7 @@ check_initializer (tree decl, tree init,
if (check_array_initializer (decl, type, init))
return NULL_TREE;
}
- else if (!COMPLETE_TYPE_P (type))
+ else if (!DEFINITE_TYPE_P (type))
{
error_at (DECL_SOURCE_LOCATION (decl),
"%q#D has incomplete type", decl);
@@ -7093,7 +7112,7 @@ cp_finish_decl (tree decl, tree init, bo
type, and that type has not been defined yet, delay emitting
the debug information for it, as we will emit it later. */
if (TYPE_MAIN_DECL (TREE_TYPE (decl)) == decl
- && !COMPLETE_TYPE_P (TREE_TYPE (decl)))
+ && !DEFINITE_TYPE_P (TREE_TYPE (decl)))
TYPE_DECL_SUPPRESS_DEBUG (decl) = 1;
rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl),
@@ -7423,6 +7442,7 @@ get_tuple_size (tree type)
/*context*/std_node,
/*entering_scope*/false, tf_none);
inst = complete_type (inst);
+ /* Correct for sizeless types in std::tuple_size is always a sized class. */
if (inst == error_mark_node || !COMPLETE_TYPE_P (inst))
return NULL_TREE;
tree val = lookup_qualified_name (inst, value_identifier,
@@ -7614,7 +7634,7 @@ cp_finish_decomp (tree decl, tree first,
type = complete_type (TREE_TYPE (type));
if (type == error_mark_node)
goto error_out;
- if (!COMPLETE_TYPE_P (type))
+ if (!DEFINITE_TYPE_P (type))
{
error_at (loc, "structured binding refers to incomplete type %qT",
type);
@@ -7788,7 +7808,7 @@ cp_finish_decomp (tree decl, tree first,
error_at (loc, "cannot decompose lambda closure type %qT", type);
goto error_out;
}
- else if (processing_template_decl && !COMPLETE_TYPE_P (type))
+ else if (processing_template_decl && !DEFINITE_TYPE_P (type))
pedwarn (loc, 0, "structured binding refers to incomplete class type %qT",
type);
else
@@ -9517,6 +9537,8 @@ check_static_variable_definition (tree d
;
else if (cxx_dialect >= cxx11 && !INTEGRAL_OR_ENUMERATION_TYPE_P (type))
{
+ /* Correct for sizeless types, which aren't allowed to have
+ static storage duration. */
if (!COMPLETE_TYPE_P (type))
error_at (DECL_SOURCE_LOCATION (decl),
"in-class initialization of static data member %q#D of "
@@ -11731,11 +11753,11 @@ grokdeclarator (const cp_declarator *dec
"extra qualification %<%T::%> on member %qs",
ctype, name);
}
- else if (/* If the qualifying type is already complete, then we
+ else if (/* If the qualifying type is already definite, then we
can skip the following checks. */
- !COMPLETE_TYPE_P (ctype)
+ !DEFINITE_TYPE_P (ctype)
&& (/* If the function is being defined, then
- qualifying type must certainly be complete. */
+ qualifying type must certainly be definite. */
funcdef_flag
/* A friend declaration of "T::f" is OK, even if
"T" is a template parameter. But, if this
@@ -11743,14 +11765,14 @@ grokdeclarator (const cp_declarator *dec
must be a class. */
|| (!friendp && !CLASS_TYPE_P (ctype))
/* For a declaration, the type need not be
- complete, if either it is dependent (since there
- is no meaningful definition of complete in that
+ definite, if either it is dependent (since there
+ is no meaningful definition of definite in that
case) or the qualifying class is currently being
defined. */
|| !(dependent_type_p (ctype)
|| currently_open_class (ctype)))
- /* Check that the qualifying type is complete. */
- && !complete_type_or_else (ctype, NULL_TREE))
+ /* Check that the qualifying type is definite. */
+ && !definite_type_or_else (ctype, NULL_TREE))
return error_mark_node;
else if (TREE_CODE (type) == FUNCTION_TYPE)
{
@@ -12265,6 +12287,13 @@ grokdeclarator (const cp_declarator *dec
return error_mark_node;
}
+ if (virtualp && TYPE_SIZELESS_P (ctype))
+ {
+ error_at (declspecs->locations[ds_virtual],
+ "sizeless types cannot have virtual functions");
+ return error_mark_node;
+ }
+
if (virtualp
&& identifier_p (unqualified_id)
&& IDENTIFIER_NEWDEL_OP_P (unqualified_id))
@@ -12383,10 +12412,16 @@ grokdeclarator (const cp_declarator *dec
}
else if (!staticp && !dependent_type_p (type)
&& !COMPLETE_TYPE_P (complete_type (type))
+ /* Sizeless fields are OK in sizeless structs. */
+ && (!ctype
+ || !TYPE_SIZELESS_P (ctype)
+ || !DEFINITE_TYPE_P (type))
&& (!complete_or_array_type_p (type)
|| initialized == 0))
{
if (TREE_CODE (type) != ARRAY_TYPE
+ /* Correct for sizeless types, which aren't allowed in
+ arrays. */
|| !COMPLETE_TYPE_P (TREE_TYPE (type)))
{
if (unqualified_id)
@@ -12785,7 +12820,7 @@ require_complete_types_for_parms (tree p
if (dependent_type_p (TREE_TYPE (parms)))
continue;
if (!VOID_TYPE_P (TREE_TYPE (parms))
- && complete_type_or_else (TREE_TYPE (parms), parms))
+ && definite_type_or_else (TREE_TYPE (parms), parms))
{
relayout_decl (parms);
DECL_ARG_TYPE (parms) = type_passed_as (TREE_TYPE (parms));
@@ -13573,6 +13608,8 @@ grok_op_properties (tree decl, bool comp
class_type);
/* Don't force t to be complete here. */
else if (MAYBE_CLASS_TYPE_P (t)
+ /* Correct for sizeless type because they will never
+ be bases or have bases. */
&& COMPLETE_TYPE_P (t)
&& DERIVED_FROM_P (t, class_type))
warning_at (loc, OPT_Wclass_conversion,
@@ -13653,6 +13690,8 @@ tag_name (enum tag_types code)
return "union";
case enum_type:
return "enum";
+ case sizeless_struct_type:
+ return "struct";
case typename_type:
return "typename";
default:
@@ -13880,6 +13919,7 @@ xref_tag_1 (enum tag_types tag_code, tre
{
case record_type:
case class_type:
+ case sizeless_struct_type:
code = RECORD_TYPE;
break;
case union_type:
@@ -13961,6 +14001,8 @@ xref_tag_1 (enum tag_types tag_code, tre
/* And push it into current scope. */
scope = ts_current;
}
+ if (tag_code == sizeless_struct_type)
+ TYPE_SIZELESS_P (t) = true;
t = pushtag (name, t, scope);
}
}
@@ -14083,6 +14125,7 @@ xref_basetypes (tree ref, tree base_list
&& CLASS_TYPE_P (basetype) && TYPE_BEING_DEFINED (basetype))
cxx_incomplete_type_diagnostic (NULL_TREE, basetype, DK_PEDWARN);
if (!dependent_type_p (basetype)
+ /* OK for sizeless types, which can never be bases. */
&& !complete_type_or_else (basetype, NULL))
/* An incomplete type. Remove it from the list. */
*basep = TREE_CHAIN (*basep);
@@ -14126,6 +14169,11 @@ xref_basetypes (tree ref, tree base_list
error ("derived union %qT invalid", ref);
return;
}
+ if (TYPE_SIZELESS_P (ref))
+ {
+ error ("sizeless type %qT cannot have base classes", ref);
+ return;
+ }
}
if (max_bases > 1)
@@ -14662,7 +14710,7 @@ finish_enum_value_list (tree enumtype)
TYPE_VALUES (t) = TYPE_VALUES (enumtype);
if (at_class_scope_p ()
- && COMPLETE_TYPE_P (current_class_type)
+ && DEFINITE_TYPE_P (current_class_type)
&& UNSCOPED_ENUM_P (enumtype))
{
insert_late_enum_def_bindings (current_class_type, enumtype);
@@ -14951,7 +14999,7 @@ check_function_type (tree decl, tree cur
if (dependent_type_p (return_type)
|| type_uses_auto (return_type))
return;
- if (!COMPLETE_OR_VOID_TYPE_P (return_type))
+ if (!DEFINITE_OR_VOID_TYPE_P (return_type))
{
tree args = TYPE_ARG_TYPES (fntype);
@@ -15641,7 +15689,7 @@ begin_destructor_body (void)
issued an error message. We still want to try to process the
body of the function, but initialize_vtbl_ptrs will crash if
TYPE_BINFO is NULL. */
- if (COMPLETE_TYPE_P (current_class_type))
+ if (DEFINITE_TYPE_P (current_class_type))
{
compound_stmt = begin_compound_stmt (0);
/* Make all virtual function table pointers in non-virtual base
@@ -16239,7 +16287,7 @@ maybe_register_incomplete_var (tree var)
inner_type = TREE_TYPE (inner_type);
inner_type = TYPE_MAIN_VARIANT (inner_type);
- if ((!COMPLETE_TYPE_P (inner_type) && CLASS_TYPE_P (inner_type))
+ if ((!DEFINITE_TYPE_P (inner_type) && CLASS_TYPE_P (inner_type))
/* RTTI TD entries are created while defining the type_info. */
|| (TYPE_LANG_SPECIFIC (inner_type)
&& TYPE_BEING_DEFINED (inner_type)))
===================================================================
@@ -684,7 +684,7 @@ check_classfn (tree ctype, tree function
if (!matched)
{
- if (!COMPLETE_TYPE_P (ctype))
+ if (!DEFINITE_TYPE_P (ctype))
cxx_incomplete_type_error (function, ctype);
else
{
@@ -1403,6 +1403,8 @@ cp_check_const_attributes (tree attribut
cp_omp_mappable_type (tree type)
{
/* Mappable type has to be complete. */
+ /* Correct for sizeless types, since we're not changing the OpenMP
+ rules at this stage. */
if (type == error_mark_node || !COMPLETE_TYPE_P (type))
return false;
/* Arrays have mappable type if the elements have mappable type. */
===================================================================
@@ -660,6 +660,8 @@ class_key_or_enum_as_string (tree t)
}
else if (TREE_CODE (t) == UNION_TYPE)
return "union";
+ else if (TYPE_SIZELESS_P (t))
+ return "__sizeless_struct";
else if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t))
return "class";
else
@@ -4246,7 +4248,7 @@ qualified_name_lookup_error (tree scope,
; /* We already complained. */
else if (TYPE_P (scope))
{
- if (!COMPLETE_TYPE_P (scope))
+ if (!DEFINITE_TYPE_P (scope))
error_at (location, "incomplete type %qT used in nested name specifier",
scope);
else if (TREE_CODE (decl) == TREE_LIST)
===================================================================
@@ -793,6 +793,7 @@ complete_ptr_ref_or_void_ptr_p (tree typ
int is_ptr;
/* Check complete. */
+ /* Correct for sizeless types, which cannot be thrown. */
type = complete_type_or_else (type, from);
if (!type)
return 0;
@@ -805,6 +806,7 @@ complete_ptr_ref_or_void_ptr_p (tree typ
if (is_ptr && VOID_TYPE_P (core))
/* OK */;
+ /* Correct for sizeless types, which cannot be thrown. */
else if (!complete_type_or_else (core, from))
return 0;
}
===================================================================
@@ -40,7 +40,7 @@ cplus_expand_constant (tree cst)
member = PTRMEM_CST_MEMBER (cst);
/* We can't lower this until the class is complete. */
- if (!COMPLETE_TYPE_P (DECL_CONTEXT (member)))
+ if (!DEFINITE_TYPE_P (DECL_CONTEXT (member)))
return cst;
if (TREE_CODE (member) == FIELD_DECL)
===================================================================
@@ -555,7 +555,7 @@ do_friend (tree ctype, tree declarator,
to be a friend, so we do lookup here even if CTYPE is in
the process of being defined. */
if (class_template_depth
- || COMPLETE_OR_OPEN_TYPE_P (ctype))
+ || DEFINITE_OR_OPEN_TYPE_P (ctype))
{
if (DECL_TEMPLATE_INFO (decl))
/* DECL is a template specialization. No need to
===================================================================
@@ -388,7 +388,7 @@ build_value_init (tree type, tsubst_flag
tree
build_value_init_noctor (tree type, tsubst_flags_t complain)
{
- if (!COMPLETE_TYPE_P (type))
+ if (!DEFINITE_TYPE_P (type))
{
if (complain & tf_error)
error ("value-initialization of incomplete type %qT", type);
@@ -1279,7 +1279,7 @@ emit_mem_initializers (tree mem_inits)
/* We will already have issued an error message about the fact that
the type is incomplete. */
- if (!COMPLETE_TYPE_P (current_class_type))
+ if (!DEFINITE_TYPE_P (current_class_type))
return;
if (mem_inits
@@ -2150,7 +2150,7 @@ build_offset_ref (tree type, tree member
gcc_assert (!DECL_P (member) || TREE_USED (member));
type = TYPE_MAIN_VARIANT (type);
- if (!COMPLETE_OR_OPEN_TYPE_P (complete_type (type)))
+ if (!DEFINITE_OR_OPEN_TYPE_P (complete_type (type)))
{
if (complain & tf_error)
error ("incomplete type %qT does not have member %qD", type, member);
@@ -2212,6 +2212,14 @@ build_offset_ref (tree type, tree member
}
else if (address_p && TREE_CODE (member) == FIELD_DECL)
{
+ if (TYPE_SIZELESS_P (type))
+ {
+ if (complain & tf_error)
+ error ("cannot take address of member of sizeless type %qT",
+ type);
+ return error_mark_node;
+ }
+
/* We need additional test besides the one in
check_accessibility_of_qualified_id in case it is
a pointer to non-static member. */
@@ -3775,6 +3783,8 @@ build_new (vec<tree, va_gc> **placement,
/* The type allocated must be complete. If the new-type-id was
"T[N]" then we are just checking that "T" is complete here, but
that is equivalent, since the value of "N" doesn't matter. */
+ /* Correct for sizeless types, which cannot be created via
+ operator new. */
if (!complete_type_or_maybe_complain (type, NULL_TREE, complain))
return error_mark_node;
@@ -3833,7 +3843,15 @@ build_vec_delete_1 (tree base, tree maxi
if (base == error_mark_node || maxindex == error_mark_node)
return error_mark_node;
- if (!COMPLETE_TYPE_P (type))
+ if (TYPE_SIZELESS_P (type))
+ {
+ if (complain & tf_error)
+ error ("cannot delete objects of sizeless type %qT", type);
+ /* This size won't actually be used. */
+ size_exp = size_one_node;
+ goto no_destructor;
+ }
+ else if (!COMPLETE_TYPE_P (type))
{
if (complain & tf_warning)
{
@@ -4717,7 +4735,13 @@ build_delete (tree otype, tree addr, spe
if (!VOID_TYPE_P (type))
{
complete_type (type);
- if (!COMPLETE_TYPE_P (type))
+ if (deleting && TYPE_SIZELESS_P (type))
+ {
+ if (complain & tf_error)
+ error ("cannot delete objects of sizeless type %qT", type);
+ return error_mark_node;
+ }
+ else if (!DEFINITE_TYPE_P (type))
{
if (complain & tf_warning)
{
===================================================================
@@ -198,7 +198,7 @@ lambda_function (tree lambda)
gcc_assert (LAMBDA_TYPE_P (type));
/* Don't let debug_tree cause instantiation. */
if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)
- && !COMPLETE_OR_OPEN_TYPE_P (type))
+ && !DEFINITE_OR_OPEN_TYPE_P (type))
return NULL_TREE;
lambda = lookup_member (type, call_op_identifier,
/*protect=*/0, /*want_type=*/false,
@@ -590,6 +590,8 @@ add_capture (tree lambda, tree id, tree
{
/* Capture by copy requires a complete type. */
type = complete_type (type);
+ /* Correct for sizeless types, which need to be captured by
+ reference instead. */
if (!COMPLETE_TYPE_P (type))
{
error ("capture by copy of incomplete type %qT", type);
@@ -644,7 +646,7 @@ add_capture (tree lambda, tree id, tree
if (current_class_type
&& current_class_type == LAMBDA_EXPR_CLOSURE (lambda))
{
- if (COMPLETE_TYPE_P (current_class_type))
+ if (DEFINITE_TYPE_P (current_class_type))
internal_error ("trying to capture %qD in instantiation of "
"generic lambda", id);
finish_member_declaration (member);
@@ -783,7 +785,7 @@ lambda_expr_this_capture (tree lambda, b
/* Lambda in an NSDMI. We don't have a function to look up
'this' in, but we can find (or rebuild) the fake one from
inject_this_parameter. */
- if (!containing_function && !COMPLETE_TYPE_P (closure))
+ if (!containing_function && !DEFINITE_TYPE_P (closure))
/* If we're parsing a lambda in a non-local class,
we can find the fake 'this' in scope_chain. */
init = scope_chain->x_current_class_ptr;
===================================================================
@@ -1200,7 +1200,7 @@ fields_linear_search (tree klass, tree n
tree
search_anon_aggr (tree anon, tree name, bool want_type)
{
- gcc_assert (COMPLETE_TYPE_P (anon));
+ gcc_assert (DEFINITE_TYPE_P (anon));
tree ret = get_class_binding_direct (anon, name, want_type);
return ret;
}
@@ -1224,7 +1224,7 @@ get_class_binding_direct (tree klass, tr
tree val = NULL_TREE;
vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (klass);
- if (COMPLETE_TYPE_P (klass) && member_vec)
+ if (DEFINITE_TYPE_P (klass) && member_vec)
{
val = member_vec_binary_search (member_vec, lookup);
if (!val)
@@ -1288,7 +1288,7 @@ get_class_binding (tree klass, tree name
{
klass = complete_type (klass);
- if (COMPLETE_TYPE_P (klass))
+ if (DEFINITE_TYPE_P (klass))
{
/* Lazily declare functions, if we're going to search these. */
if (IDENTIFIER_CTOR_P (name))
@@ -1325,16 +1325,16 @@ get_class_binding (tree klass, tree name
tree *
find_member_slot (tree klass, tree name)
{
- bool complete_p = COMPLETE_TYPE_P (klass);
+ bool definite_p = DEFINITE_TYPE_P (klass);
vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (klass);
if (!member_vec)
{
vec_alloc (member_vec, 8);
CLASSTYPE_MEMBER_VEC (klass) = member_vec;
- if (complete_p)
+ if (definite_p)
{
- /* If the class is complete but had no member_vec, we need
+ /* If the class is definite but had no member_vec, we need
to add the TYPE_FIELDS into it. We're also most likely
to be adding ctors & dtors, so ask for 6 spare slots (the
abstract cdtors and their clones). */
@@ -1369,12 +1369,12 @@ find_member_slot (tree klass, tree name)
return slot;
}
- if (complete_p && fn_name > name)
+ if (definite_p && fn_name > name)
break;
}
/* No slot found, add one if the class is complete. */
- if (complete_p)
+ if (definite_p)
{
/* Do exact allocation, as we don't expect to add many. */
gcc_assert (name != conv_op_identifier);
@@ -1393,7 +1393,7 @@ find_member_slot (tree klass, tree name)
tree *
add_member_slot (tree klass, tree name)
{
- gcc_assert (!COMPLETE_TYPE_P (klass));
+ gcc_assert (!DEFINITE_TYPE_P (klass));
vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (klass);
vec_safe_push (member_vec, NULL_TREE);
@@ -6484,7 +6484,7 @@ maybe_process_template_type_declaration
{
finish_member_declaration (CLASSTYPE_TI_TEMPLATE (type));
- if (!COMPLETE_TYPE_P (current_class_type))
+ if (!DEFINITE_TYPE_P (current_class_type))
{
maybe_add_class_template_decl_list (current_class_type,
type, /*friend_p=*/0);
@@ -6665,7 +6665,7 @@ do_pushtag (tree name, tree type, tag_sc
}
if (b->kind == sk_class
- && !COMPLETE_TYPE_P (current_class_type))
+ && !DEFINITE_TYPE_P (current_class_type))
{
maybe_add_class_template_decl_list (current_class_type,
type, /*friend_p=*/0);
===================================================================
@@ -940,6 +940,7 @@ cp_keyword_starts_decl_specifier_p (enum
case RID_ENUM:
case RID_CLASS:
case RID_STRUCT:
+ case RID_SIZELESS_STRUCT:
case RID_UNION:
case RID_TYPENAME:
/* Simple type specifiers. */
@@ -3415,7 +3416,7 @@ cp_parser_diagnose_invalid_type_name (cp
else if (TYPE_P (parser->scope))
{
auto_diagnostic_group d;
- if (!COMPLETE_TYPE_P (parser->scope))
+ if (!DEFINITE_TYPE_P (parser->scope))
cxx_incomplete_type_error (location_of (id), NULL_TREE,
parser->scope);
else if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
@@ -6468,7 +6469,7 @@ cp_parser_nested_name_specifier_opt (cp_
if (TYPE_P (new_scope)
/* Since checking types for dependency can be expensive,
avoid doing it if the type is already complete. */
- && !COMPLETE_TYPE_P (new_scope)
+ && !DEFINITE_TYPE_P (new_scope)
/* Do not try to complete dependent types. */
&& !dependent_type_p (new_scope))
{
@@ -6476,7 +6477,7 @@ cp_parser_nested_name_specifier_opt (cp_
/* If it is a typedef to current class, use the current
class instead, as the typedef won't have any names inside
it yet. */
- if (!COMPLETE_TYPE_P (new_scope)
+ if (!DEFINITE_TYPE_P (new_scope)
&& currently_open_class (new_scope))
new_scope = TYPE_MAIN_VARIANT (new_scope);
}
@@ -7522,7 +7523,7 @@ cp_parser_postfix_dot_deref_expression (
&& !currently_open_class (scope))
{
scope = complete_type (scope);
- if (!COMPLETE_TYPE_P (scope)
+ if (!DEFINITE_TYPE_P (scope)
&& cp_parser_dot_deref_incomplete (&scope, &postfix_expression,
&dependent_p))
return error_mark_node;
@@ -12134,7 +12135,7 @@ cp_parser_perform_range_for_lookup (tree
return error_mark_node;
}
- if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (range))))
+ if (!DEFINITE_TYPE_P (complete_type (TREE_TYPE (range))))
{
error ("range-based %<for%> expression of type %qT "
"has incomplete type", TREE_TYPE (range));
@@ -16899,6 +16900,7 @@ cp_parser_type_specifier (cp_parser* par
elaborated-type-specifier. */
case RID_CLASS:
case RID_STRUCT:
+ case RID_SIZELESS_STRUCT:
case RID_UNION:
if ((flags & CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS))
goto elaborated_type_specifier;
@@ -23343,7 +23345,7 @@ cp_parser_class_head (cp_parser* parser,
/* If this type was already complete, and we see another definition,
that's an error. */
- if (type != error_mark_node && COMPLETE_TYPE_P (type))
+ if (type != error_mark_node && DEFINITE_TYPE_P (type))
{
error_at (type_start_token->location, "redefinition of %q#T",
type);
@@ -28844,6 +28846,8 @@ cp_parser_token_is_class_key (cp_token*
return record_type;
case RID_UNION:
return union_type;
+ case RID_SIZELESS_STRUCT:
+ return sizeless_struct_type;
default:
return none_type;
@@ -28878,11 +28882,15 @@ cp_parser_check_class_key (enum tag_type
{
if (type == error_mark_node)
return;
- if ((TREE_CODE (type) == UNION_TYPE) != (class_key == union_type))
+ if (((TREE_CODE (type) == UNION_TYPE) != (class_key == union_type))
+ || ((TREE_CODE (type) == RECORD_TYPE && TYPE_SIZELESS_P (type))
+ != (class_key == sizeless_struct_type)))
{
if (permerror (input_location, "%qs tag used in naming %q#T",
class_key == union_type ? "union"
- : class_key == record_type ? "struct" : "class",
+ : class_key == record_type ? "struct"
+ : class_key == sizeless_struct_type ? "__sizeless_struct"
+ : "class",
type))
inform (DECL_SOURCE_LOCATION (TYPE_NAME (type)),
"%q#T was previously declared here", type);
===================================================================
@@ -843,7 +843,7 @@ maybe_new_partial_specialization (tree t
//
// Here, S<T*> is an implicit instantiation of S whose type
// is incomplete.
- if (CLASSTYPE_IMPLICIT_INSTANTIATION (type) && !COMPLETE_TYPE_P (type))
+ if (CLASSTYPE_IMPLICIT_INSTANTIATION (type) && !DEFINITE_TYPE_P (type))
return type;
// It can also be the case that TYPE is a completed specialization.
@@ -1020,7 +1020,7 @@ maybe_process_partial_specialization (tr
and `C<T>::D' may not exist. */
if (CLASSTYPE_IMPLICIT_INSTANTIATION (context)
- && !COMPLETE_TYPE_P (type))
+ && !DEFINITE_TYPE_P (type))
{
tree t;
tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
@@ -1044,7 +1044,7 @@ maybe_process_partial_specialization (tr
{
tree inst = TREE_VALUE (t);
if (CLASSTYPE_TEMPLATE_SPECIALIZATION (inst)
- || !COMPLETE_OR_OPEN_TYPE_P (inst))
+ || !DEFINITE_OR_OPEN_TYPE_P (inst))
{
/* We already have a full specialization of this partial
instantiation, or a full specialization has been
@@ -5029,7 +5029,7 @@ process_partial_specialization (tree dec
/* We should only get here once. */
if (TREE_CODE (decl) == TYPE_DECL)
- gcc_assert (!COMPLETE_TYPE_P (type));
+ gcc_assert (!DEFINITE_TYPE_P (type));
// Build the template decl.
tree tmpl = build_template_decl (decl, current_template_parms,
@@ -5066,7 +5066,7 @@ process_partial_specialization (tree dec
{
tree instance = TREE_VALUE (inst);
if (TYPE_P (instance)
- ? (COMPLETE_TYPE_P (instance)
+ ? (DEFINITE_TYPE_P (instance)
&& CLASSTYPE_IMPLICIT_INSTANTIATION (instance))
: DECL_TEMPLATE_INSTANTIATION (instance))
{
@@ -9464,6 +9464,7 @@ lookup_template_class_1 (tree d1, tree a
t = make_class_type (TREE_CODE (template_type));
CLASSTYPE_DECLARED_CLASS (t)
= CLASSTYPE_DECLARED_CLASS (template_type);
+ TYPE_SIZELESS_P (t) = TYPE_SIZELESS_P (template_type);
SET_CLASSTYPE_IMPLICIT_INSTANTIATION (t);
/* A local class. Make sure the decl gets registered properly. */
@@ -10508,10 +10509,10 @@ tsubst_friend_function (tree decl, tree
--processing_template_decl;
if (!dependent_p
- && !complete_type_or_else (context, NULL_TREE))
+ && !definite_type_or_else (context, NULL_TREE))
return error_mark_node;
- if (COMPLETE_TYPE_P (context))
+ if (DEFINITE_TYPE_P (context))
{
tree fn = new_friend;
/* do_friend adds the TEMPLATE_DECL for any member friend
@@ -10625,7 +10626,7 @@ can_complete_type_without_circularity (t
{
if (type == NULL_TREE || type == error_mark_node)
return 0;
- else if (COMPLETE_TYPE_P (type))
+ else if (DEFINITE_TYPE_P (type))
return 1;
else if (TREE_CODE (type) == ARRAY_TYPE)
return can_complete_type_without_circularity (TREE_TYPE (type));
@@ -10868,7 +10869,7 @@ instantiate_class_template_1 (tree type)
if (type == error_mark_node)
return error_mark_node;
- if (COMPLETE_OR_OPEN_TYPE_P (type)
+ if (DEFINITE_OR_OPEN_TYPE_P (type)
|| uses_template_parms (type))
return type;
@@ -10909,9 +10910,9 @@ instantiate_class_template_1 (tree type)
args = CLASSTYPE_TI_ARGS (type);
}
- /* If the template we're instantiating is incomplete, then clearly
+ /* If the template we're instantiating is indefinite, then clearly
there's nothing we can do. */
- if (!COMPLETE_TYPE_P (pattern))
+ if (!DEFINITE_TYPE_P (pattern))
{
/* We can try again later. */
TYPE_BEING_DEFINED (type) = 0;
@@ -10971,7 +10972,7 @@ instantiate_class_template_1 (tree type)
instantiate it, and that lookup should instantiate the enclosing
class. */
gcc_assert (!DECL_CLASS_SCOPE_P (TYPE_MAIN_DECL (pattern))
- || COMPLETE_OR_OPEN_TYPE_P (TYPE_CONTEXT (type)));
+ || DEFINITE_OR_OPEN_TYPE_P (TYPE_CONTEXT (type)));
base_list = NULL_TREE;
if (BINFO_N_BASE_BINFOS (pbinfo))
@@ -11212,7 +11213,9 @@ instantiate_class_template_1 (tree type)
if (can_complete_type_without_circularity (rtype))
complete_type (rtype);
- if (!complete_or_array_type_p (rtype))
+ if (TYPE_SIZELESS_P (type)
+ ? !definite_or_array_type_p (rtype)
+ : !complete_or_array_type_p (rtype))
{
/* If R's type couldn't be completed and
it isn't a flexible array member (whose
@@ -14857,7 +14860,7 @@ tsubst (tree t, tree args, tsubst_flags_
point, so here CTX really should have complete type, unless
it's a partial instantiation. */
ctx = complete_type (ctx);
- if (!COMPLETE_TYPE_P (ctx))
+ if (!DEFINITE_TYPE_P (ctx))
{
if (complain & tf_error)
cxx_incomplete_type_error (NULL_TREE, ctx);
@@ -23299,7 +23302,7 @@ do_type_instantiation (tree t, tree stor
complete_type (t);
- if (!COMPLETE_TYPE_P (t))
+ if (!DEFINITE_TYPE_P (t))
{
if (complain & tf_error)
error ("explicit instantiation of %q#T before definition of template",
@@ -24194,7 +24197,7 @@ instantiate_pending_templates (int retri
if (TYPE_P (instantiation))
{
- if (!COMPLETE_TYPE_P (instantiation))
+ if (!DEFINITE_TYPE_P (instantiation))
{
instantiate_class_template (instantiation);
if (CLASSTYPE_TEMPLATE_INSTANTIATION (instantiation))
@@ -24208,11 +24211,11 @@ instantiate_pending_templates (int retri
/*defer_ok=*/false,
/*expl_inst_class_mem_p=*/false);
- if (COMPLETE_TYPE_P (instantiation))
+ if (DEFINITE_TYPE_P (instantiation))
reconsider = 1;
}
- complete = COMPLETE_TYPE_P (instantiation);
+ complete = DEFINITE_TYPE_P (instantiation);
}
else
{
===================================================================
@@ -281,6 +281,7 @@ get_tinfo_decl_dynamic (tree exp, tsubst
/* For UNKNOWN_TYPEs call complete_type_or_else to get diagnostics. */
if (CLASS_TYPE_P (type) || type == unknown_type_node
|| type == init_list_type_node)
+ /* Correct for sizeless types, which have no typeid. */
type = complete_type_or_maybe_complain (type, exp, complain);
if (!type)
@@ -314,6 +315,7 @@ typeid_ok_p (void)
return false;
}
+ /* Correct for sizeless types, for which typeid is not allowed. */
if (!COMPLETE_TYPE_P (const_type_info_type_node))
{
gcc_rich_location richloc (input_location);
@@ -523,6 +525,7 @@ get_typeid (tree type, tsubst_flags_t co
/* For UNKNOWN_TYPEs call complete_type_or_else to get diagnostics. */
if (CLASS_TYPE_P (type) || type == unknown_type_node
|| type == init_list_type_node)
+ /* Correct for sizeless types, which have no typeid. */
type = complete_type_or_maybe_complain (type, NULL_TREE, complain);
if (!type)
@@ -575,6 +578,7 @@ build_dynamic_cast_1 (tree type, tree ex
errstr = _("target is not pointer or reference to class");
goto fail;
}
+ /* Correct for sizeless types, which can't be used with dynamic_cast. */
if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (type))))
{
errstr = _("target is not pointer or reference to complete type");
@@ -607,6 +611,7 @@ build_dynamic_cast_1 (tree type, tree ex
errstr = _("source is not a pointer to class");
goto fail;
}
+ /* Correct for sizeless types, which can't be used with dynamic_cast. */
if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (exprtype))))
{
errstr = _("source is a pointer to incomplete type");
@@ -625,6 +630,7 @@ build_dynamic_cast_1 (tree type, tree ex
errstr = _("source is not of class type");
goto fail;
}
+ /* Correct for sizeless types, which can't be used with dynamic_cast. */
if (!COMPLETE_TYPE_P (complete_type (exprtype)))
{
errstr = _("source is of incomplete class type");
@@ -944,6 +950,8 @@ tinfo_base_init (tinfo_s *ti, tree targe
/*tag_scope=*/ts_current, false);
pop_abi_namespace ();
+ /* Correct for sizeless types, which can't have base classes or
+ virtual functions. */
if (!COMPLETE_TYPE_P (real_type))
{
/* We never saw a definition of this type, so we need to
===================================================================
@@ -202,7 +202,7 @@ lookup_base (tree t, tree base, base_acc
/* If BASE is incomplete, it can't be a base of T--and instantiating it
might cause an error. */
- if (t_binfo && CLASS_TYPE_P (base) && COMPLETE_OR_OPEN_TYPE_P (base))
+ if (t_binfo && CLASS_TYPE_P (base) && DEFINITE_OR_OPEN_TYPE_P (base))
{
struct lookup_base_data_s data;
@@ -252,6 +252,8 @@ lookup_base (tree t, tree base, base_acc
there's no need to issue another error here, and
there's no implicit typedef to use in the code that
follows, so we skip the check. */
+ /* Correct for sizeless types, which don't have base classes
+ and can't be used as base classes. */
&& COMPLETE_TYPE_P (base)
&& !accessible_base_p (t, base, !(access & ba_ignore_scope)))
{
===================================================================
@@ -3887,6 +3887,7 @@ finish_underlying_type (tree type)
return underlying_type;
}
+ /* Correct for sizeless types; only relevant for enums. */
if (!complete_type_or_else (type, NULL_TREE))
return error_mark_node;
@@ -3915,6 +3916,7 @@ finish_underlying_type (tree type)
tree
calculate_direct_bases (tree type, tsubst_flags_t complain)
{
+ /* Part of a parameter pack, so probably correct for sizeless types. */
if (!complete_type_or_maybe_complain (type, NULL_TREE, complain)
|| !NON_UNION_CLASS_TYPE_P (type))
return make_tree_vec (0);
@@ -3981,6 +3983,7 @@ calculate_bases_helper (tree type)
tree
calculate_bases (tree type, tsubst_flags_t complain)
{
+ /* Part of a parameter pack, so probably correct for sizeless types. */
if (!complete_type_or_maybe_complain (type, NULL_TREE, complain)
|| !NON_UNION_CLASS_TYPE_P (type))
return make_tree_vec (0);
@@ -4088,6 +4091,7 @@ finish_offsetof (tree object_ptr, tree e
}
if (REFERENCE_REF_P (expr))
expr = TREE_OPERAND (expr, 0);
+ /* Cannot use offsetof for sizeless types. */
if (!complete_type_or_else (TREE_TYPE (TREE_TYPE (object_ptr)), object_ptr))
return error_mark_node;
if (warn_invalid_offsetof
@@ -7321,10 +7325,14 @@ finish_omp_clauses (tree clauses, enum c
if (need_complete_type || need_copy_assignment)
{
+ /* Correct for sizeless types: we're not changing the OpenMP
+ rules for those. */
t = require_complete_type (t);
if (t == error_mark_node)
remove = true;
else if (TYPE_REF_P (TREE_TYPE (t))
+ /* OK for sizeless types: keeping OpenMP rules unchanged
+ for now. */
&& !complete_type_or_else (TREE_TYPE (TREE_TYPE (t)), t))
remove = true;
}
@@ -7374,6 +7382,8 @@ finish_omp_clauses (tree clauses, enum c
Save the results, because later we won't be in the right context
for making these queries. */
if (CLASS_TYPE_P (inner_type)
+ /* Correct for sizeless types: we're not changing the OpenMP
+ rules for those. */
&& COMPLETE_TYPE_P (inner_type)
&& (need_default_ctor || need_copy_ctor
|| need_copy_assignment || need_dtor)
@@ -7555,6 +7565,8 @@ finish_omp_threadprivate (tree vars)
error ("%qE declared %<threadprivate%> after first use", v);
else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v))
error ("automatic variable %qE cannot be %<threadprivate%>", v);
+ /* Correct for sizeless types: we're not changing the OpenMP
+ rules for those. */
else if (! COMPLETE_TYPE_P (complete_type (TREE_TYPE (v))))
error ("%<threadprivate%> %qE has incomplete type", v);
else if (TREE_STATIC (v) && TYPE_P (CP_DECL_CONTEXT (v))
@@ -9105,13 +9117,14 @@ check_trait_type (tree type)
&& check_trait_type (TREE_CHAIN (type)));
if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type)
+ /* Correct for sizeless types, which aren't allowed in arrays. */
&& COMPLETE_TYPE_P (TREE_TYPE (type)))
return true;
if (VOID_TYPE_P (type))
return true;
- return !!complete_type_or_else (strip_array_types (type), NULL_TREE);
+ return !!definite_type_or_else (strip_array_types (type), NULL_TREE);
}
/* Process a trait expression. */
@@ -9172,7 +9185,7 @@ finish_trait_expr (cp_trait_kind kind, t
case CPTK_IS_BASE_OF:
if (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
&& !same_type_ignoring_top_level_qualifiers_p (type1, type2)
- && !complete_type_or_else (type2, NULL_TREE))
+ && !definite_type_or_else (type2, NULL_TREE))
/* We already issued an error. */
return error_mark_node;
break;
@@ -9245,7 +9258,7 @@ apply_deduced_return_type (tree fco, tre
return;
if (!processing_template_decl && !VOID_TYPE_P (return_type)
- && !complete_type_or_else (return_type, NULL_TREE))
+ && !definite_type_or_else (return_type, NULL_TREE))
return;
/* We already have a DECL_RESULT from start_preparsed_function.
===================================================================
@@ -646,7 +646,7 @@ build_cplus_new (tree type, tree init, t
tree rval = build_aggr_init_expr (type, init);
tree slot;
- if (!complete_type_or_maybe_complain (type, init, complain))
+ if (!definite_type_or_maybe_complain (type, init, complain))
return error_mark_node;
/* Make sure that we're not trying to create an instance of an
@@ -1061,6 +1061,7 @@ build_cplus_array_type (tree elt_type, t
= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (elt_type));
if (!dependent && t == TYPE_MAIN_VARIANT (t)
+ /* Correct for sizeless types, which aren't allowed in arrays. */
&& !COMPLETE_TYPE_P (t) && COMPLETE_TYPE_P (elt_type))
{
/* The element type has been completed since the last time we saw
@@ -1648,7 +1649,7 @@ strip_typedefs (tree t, bool *remove_att
}
gcc_assert (!typedef_variant_p (result));
- if (COMPLETE_TYPE_P (result) && !COMPLETE_TYPE_P (t))
+ if (DEFINITE_TYPE_P (result) && !DEFINITE_TYPE_P (t))
/* If RESULT is complete and T isn't, it's likely the case that T
is a variant of RESULT which hasn't been updated yet. Skip the
attribute handling. */;
@@ -4063,7 +4064,7 @@ type_has_nontrivial_copy_init (const_tre
if (CLASS_TYPE_P (t))
{
- gcc_assert (COMPLETE_TYPE_P (t));
+ gcc_assert (DEFINITE_TYPE_P (t));
if (TYPE_HAS_COMPLEX_COPY_CTOR (t)
|| TYPE_HAS_COMPLEX_MOVE_CTOR (t))
@@ -4350,22 +4351,22 @@ record_has_unique_obj_representations (c
else if (!type_has_unique_obj_representations (TREE_TYPE (field)))
return false;
- offset_int cur = 0;
+ poly_offset_int cur = 0;
for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
{
- offset_int fld = wi::to_offset (DECL_FIELD_OFFSET (field));
+ poly_offset_int fld = wi::to_poly_offset (DECL_FIELD_OFFSET (field));
offset_int bitpos = wi::to_offset (DECL_FIELD_BIT_OFFSET (field));
fld = fld * BITS_PER_UNIT + bitpos;
- if (cur != fld)
+ if (maybe_ne (cur, fld))
return false;
if (DECL_SIZE (field))
{
- offset_int size = wi::to_offset (DECL_SIZE (field));
+ poly_offset_int size = wi::to_poly_offset (DECL_SIZE (field));
cur += size;
}
}
- if (cur != wi::to_offset (sz))
+ if (maybe_ne (cur, wi::to_poly_offset (sz)))
return false;
return true;
===================================================================
@@ -66,13 +66,18 @@ static int convert_arguments (tree, vec<
static bool is_std_move_p (tree);
static bool is_std_forward_p (tree);
-/* Do `exp = require_complete_type (exp);' to make sure exp
- does not have an incomplete type. (That includes void types.)
- Returns error_mark_node if the VALUE does not have
- complete type when this function returns. */
+/* Do:
+
+ value = require_complete_type_sfinae (value, complain, allow_sizeless_p);
+
+ to make sure VALUE does not have an incomplete type or indefinite type;
+ ALLOW_SIZELESS_P selects the latter over the former. (Void types are
+ both incomplete and indefinite.) Return error_mark_node if VALUE
+ does not meet the condition. */
tree
-require_complete_type_sfinae (tree value, tsubst_flags_t complain)
+require_complete_type_sfinae (tree value, tsubst_flags_t complain,
+ bool allow_sizeless_p)
{
tree type;
@@ -88,10 +93,11 @@ require_complete_type_sfinae (tree value
return error_mark_node;
/* First, detect a valid value with a complete type. */
- if (COMPLETE_TYPE_P (type))
+ if (allow_sizeless_p ? DEFINITE_TYPE_P (type) : COMPLETE_TYPE_P (type))
return value;
- if (complete_type_or_maybe_complain (type, value, complain))
+ if (complete_type_or_maybe_complain (type, value, complain,
+ allow_sizeless_p))
return value;
else
return error_mark_node;
@@ -116,12 +122,13 @@ complete_type (tree type)
at some point. */
return error_mark_node;
- if (type == error_mark_node || COMPLETE_TYPE_P (type))
+ if (type == error_mark_node || DEFINITE_TYPE_P (type))
;
else if (TREE_CODE (type) == ARRAY_TYPE)
{
tree t = complete_type (TREE_TYPE (type));
unsigned int needs_constructing, has_nontrivial_dtor;
+ /* Correct for sizeless types, which aren't allowed in arrays. */
if (COMPLETE_TYPE_P (t) && !dependent_type_p (type))
layout_type (type);
needs_constructing
@@ -140,18 +147,23 @@ complete_type (tree type)
return type;
}
-/* Like complete_type, but issue an error if the TYPE cannot be completed.
- VALUE is used for informative diagnostics.
- Returns NULL_TREE if the type cannot be made complete. */
+/* Like complete_type, but check whether the result is definite or complete;
+ ALLOW_SIZELESS_P selects the former over the latter. Return NULL_TREE if
+ the type doesn't meet this condition, and also report an error if
+ COMPLAIN allows. VALUE is used for informative diagnostics. */
tree
-complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain)
+complete_type_or_maybe_complain (tree type, tree value,
+ tsubst_flags_t complain,
+ bool allow_sizeless_p)
{
type = complete_type (type);
if (type == error_mark_node)
/* We already issued an error. */
return NULL_TREE;
- else if (!COMPLETE_TYPE_P (type))
+ else if (allow_sizeless_p
+ ? !DEFINITE_TYPE_P (type)
+ : !COMPLETE_TYPE_P (type))
{
if (complain & tf_error)
cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
@@ -161,10 +173,15 @@ complete_type_or_maybe_complain (tree ty
return type;
}
+/* Like complete_type, but check whether the result is definite or complete;
+ ALLOW_SIZELESS_P selects the former over the latter. Report an error
+ and return NULL_TREE if the type doesn't meet this condition. */
+
tree
-complete_type_or_else (tree type, tree value)
+complete_type_or_else (tree type, tree value, bool allow_sizeless_p)
{
- return complete_type_or_maybe_complain (type, value, tf_warning_or_error);
+ return complete_type_or_maybe_complain (type, value, tf_warning_or_error,
+ allow_sizeless_p);
}
@@ -1633,6 +1650,10 @@ cxx_sizeof_or_alignof_type (tree type, e
compute the value, we'll likely end up with SAVE_EXPRs, which
the template substitution machinery does not expect to see. */
|| (processing_template_decl
+ /* Correct for sizeless types, since (a) it's an error
+ to use them with sizeof and alignof, reported by
+ c_sizeof_or_alignof_type and (b) this code is geared
+ around arrays, which are never sizeless. */
&& COMPLETE_TYPE_P (type)
&& TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST))
{
@@ -1659,6 +1680,8 @@ cxx_sizeof_nowarn (tree type)
|| VOID_TYPE_P (type)
|| TREE_CODE (type) == ERROR_MARK)
return size_one_node;
+ /* Correct for sizeless types, whose size should never be measured
+ by the frontend. */
else if (!COMPLETE_TYPE_P (type))
return size_zero_node;
else
@@ -2109,7 +2132,7 @@ decay_conversion (tree exp,
if (!CLASS_TYPE_P (type) && cv_qualified_p (type))
exp = build_nop (cv_unqualified (type), exp);
- if (!complete_type_or_maybe_complain (type, exp, complain))
+ if (!definite_type_or_maybe_complain (type, exp, complain))
return error_mark_node;
return exp;
@@ -2366,7 +2389,7 @@ build_class_member_access_expr (cp_expr
complete type). */
object_type = TREE_TYPE (object);
if (!currently_open_class (object_type)
- && !complete_type_or_maybe_complain (object_type, object, complain))
+ && !definite_type_or_maybe_complain (object_type, object, complain))
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
@@ -2902,7 +2925,7 @@ finish_class_member_access_expr (cp_expr
The type of the first expression shall be "class object" (of a
complete type). */
if (!currently_open_class (object_type)
- && !complete_type_or_maybe_complain (object_type, object, complain))
+ && !definite_type_or_maybe_complain (object_type, object, complain))
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
@@ -3409,6 +3432,7 @@ cp_build_array_ref (location_t loc, tree
address arithmetic on its address.
Likewise an array of elements of variable size. */
if (TREE_CODE (idx) != INTEGER_CST
+ /* Correct for sizeless types, which aren't allowed in arrays. */
|| (COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (array)))
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))))
!= INTEGER_CST)))
@@ -3453,6 +3477,7 @@ cp_build_array_ref (location_t loc, tree
|= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
TREE_THIS_VOLATILE (rval)
|= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
+ /* Correct for sizeless types, which aren't allowed in arrays. */
ret = require_complete_type_sfinae (rval, complain);
protected_set_expr_location (ret, loc);
if (non_lvalue)
@@ -3554,7 +3579,7 @@ get_member_function_from_ptrfunc (tree *
/* True if we know that the dynamic type of the object doesn't have
virtual functions, so we can assume the PFN field is a pointer. */
- nonvirtual = (COMPLETE_TYPE_P (basetype)
+ nonvirtual = (DEFINITE_TYPE_P (basetype)
&& !TYPE_POLYMORPHIC_P (basetype)
&& resolves_to_fixed_type_p (instance_ptr, 0));
@@ -3998,7 +4023,7 @@ convert_arguments (tree typelist, vec<tr
/* Formal parm type is specified by a function prototype. */
tree parmval;
- if (!COMPLETE_TYPE_P (complete_type (type)))
+ if (!DEFINITE_TYPE_P (complete_type (type)))
{
if (complain & tf_error)
{
@@ -4029,7 +4054,7 @@ convert_arguments (tree typelist, vec<tr
/* Don't do ellipsis conversion for __built_in_constant_p
as this will result in spurious errors for non-trivial
types. */
- val = require_complete_type_sfinae (val, complain);
+ val = require_definite_type_sfinae (val, complain);
else
val = convert_arg_to_ellipsis (val, complain);
@@ -5573,6 +5598,7 @@ pointer_diff (location_t loc, tree op0,
tree restype = ptrdiff_type_node;
tree target_type = TREE_TYPE (ptrtype);
+ /* Can't subtract pointers to sizeless types. */
if (!complete_type_or_else (target_type, NULL_TREE))
return error_mark_node;
@@ -5637,6 +5663,8 @@ pointer_diff (location_t loc, tree op0,
op0 = build2_loc (loc, POINTER_DIFF_EXPR, inttype, op0, op1);
/* This generates an error if op1 is a pointer to an incomplete type. */
+ /* Correct for sizeless types, which can't be used with pointer
+ arithmetic. */
if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
{
if (complain & tf_error)
@@ -5699,7 +5727,7 @@ build_x_unary_op (location_t loc, enum t
if (code == ADDR_EXPR
&& TREE_CODE (xarg) != TEMPLATE_ID_EXPR
&& ((CLASS_TYPE_P (TREE_TYPE (xarg))
- && !COMPLETE_TYPE_P (complete_type (TREE_TYPE (xarg))))
+ && !DEFINITE_TYPE_P (complete_type (TREE_TYPE (xarg))))
|| (TREE_CODE (xarg) == OFFSET_REF)))
/* Don't look for a function. */;
else
@@ -7552,6 +7580,8 @@ build_reinterpret_cast_1 (tree type, tre
&& (complain & tf_warning)
&& !VOID_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (intype)) != FUNCTION_TYPE
+ /* Correct for sizeless types, which have no explicit alignment
+ at the language level. */
&& COMPLETE_TYPE_P (TREE_TYPE (type))
&& COMPLETE_TYPE_P (TREE_TYPE (intype))
&& min_align_of_type (TREE_TYPE (type))
@@ -8142,7 +8172,7 @@ cp_build_modify_expr (location_t loc, tr
}
else
{
- lhs = require_complete_type_sfinae (lhs, complain);
+ lhs = require_definite_type_sfinae (lhs, complain);
if (lhs == error_mark_node)
return error_mark_node;
@@ -8933,7 +8963,7 @@ convert_for_assignment (tree type, tree
&& TYPE_PTR_P (type)
&& CLASS_TYPE_P (TREE_TYPE (rhstype))
&& CLASS_TYPE_P (TREE_TYPE (type))
- && !COMPLETE_TYPE_P (TREE_TYPE (rhstype)))
+ && !DEFINITE_TYPE_P (TREE_TYPE (rhstype)))
inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL
(TREE_TYPE (rhstype))),
"class type %qT is incomplete", TREE_TYPE (rhstype));
@@ -9821,6 +9851,8 @@ ptr_reasonably_similar (const_tree to, c
{
/* When either type is incomplete avoid DERIVED_FROM_P,
which may call complete_type (c++/57942). */
+ /* COMPARE_STRICT is correct for sizeless types, since they
+ cannot have bases. */
bool b = !COMPLETE_TYPE_P (to) || !COMPLETE_TYPE_P (from);
return comptypes
(TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from),
@@ -9982,7 +10014,7 @@ cp_apply_type_quals_to_decl (int type_qu
/* If the type has (or might have) a mutable component, that component
might be modified. */
- if (TYPE_HAS_MUTABLE_P (type) || !COMPLETE_TYPE_P (type))
+ if (TYPE_HAS_MUTABLE_P (type) || !DEFINITE_TYPE_P (type))
type_quals &= ~TYPE_QUAL_CONST;
c_apply_type_quals_to_decl (type_quals, decl);
===================================================================
@@ -177,7 +177,7 @@ static GTY (()) hash_table<abstract_type
static int abstract_virtuals_error_sfinae (tree, tree, abstract_class_use, tsubst_flags_t);
-/* This function is called after TYPE is completed, and will check if there
+/* This function is called after TYPE is fully-defined, and will check if there
are pending declarations for which we still need to verify the abstractness
of TYPE, and emit a diagnostic (through abstract_virtuals_error) if TYPE
turned out to be incomplete. */
@@ -188,7 +188,7 @@ complete_type_check_abstract (tree type)
struct pending_abstract_type *pat;
location_t cur_loc = input_location;
- gcc_assert (COMPLETE_TYPE_P (type));
+ gcc_assert (DEFINITE_TYPE_P (type));
if (!abstract_pending_vars)
return;
@@ -268,7 +268,7 @@ abstract_virtuals_error_sfinae (tree dec
so that we can check again once it is completed. This makes sense
only for objects for which we have a declaration or at least a
name. */
- if (!COMPLETE_TYPE_P (type) && (complain & tf_error))
+ if (!DEFINITE_TYPE_P (type) && (complain & tf_error))
{
struct pending_abstract_type *pat;
@@ -1032,7 +1032,7 @@ digest_init_r (tree type, tree init, int
/* We must strip the outermost array type when completing the type,
because the its bounds might be incomplete at the moment. */
- if (!complete_type_or_maybe_complain (code == ARRAY_TYPE
+ if (!definite_type_or_maybe_complain (code == ARRAY_TYPE
? TREE_TYPE (type) : type, NULL_TREE,
complain))
return error_mark_node;
@@ -1970,6 +1970,8 @@ build_m_component_ref (tree datum, tree
type = TYPE_PTRMEM_POINTED_TO_TYPE (ptrmem_type);
ctype = complete_type (TYPE_PTRMEM_CLASS_TYPE (ptrmem_type));
+ /* Correct for sizeless types, which don't have bases and can't be
+ used as bases. */
if (!COMPLETE_TYPE_P (ctype))
{
if (!same_type_p (ctype, objtype))
@@ -2167,7 +2169,7 @@ build_functional_cast (tree exp, tree pa
then the slot being initialized will be filled in. */
- if (!complete_type_or_maybe_complain (type, NULL_TREE, complain))
+ if (!definite_type_or_maybe_complain (type, NULL_TREE, complain))
return error_mark_node;
if (abstract_virtuals_error_sfinae (ACU_CAST, type, complain))
return error_mark_node;
@@ -2248,6 +2250,7 @@ add_exception_specifier (tree list, tree
but it seems more reasonable to only require this on definitions
and calls. So just give a pedwarn at this point; we will give an
error later if we hit one of those two cases. */
+ /* Correct for sizeless types, which can't be thrown. */
if (!COMPLETE_TYPE_P (complete_type (core)))
diag_type = DK_PEDWARN; /* pedwarn */
}
@@ -2359,6 +2362,7 @@ require_complete_eh_spec_types (tree fnt
raises = TREE_CHAIN (raises))
{
tree type = TREE_VALUE (raises);
+ /* Correct for sizeless types, which can't be thrown. */
if (type && !COMPLETE_TYPE_P (type))
{
if (decl)
===================================================================
@@ -0,0 +1,793 @@
+// { dg-options "-Wconditionally-supported -Wdelete-incomplete -Wclass-memaccess" }
+
+typedef __SIZE_TYPE__ size_t;
+
+inline void *operator new (size_t, void *__p) throw() { return __p; }
+
+// Invalid mixtures of tags.
+
+struct initially_struct;
+__sizeless_struct initially_struct; // { dg-error {'__sizeless_struct' tag used in naming 'struct initially_struct'} }
+
+class initially_class;
+__sizeless_struct initially_class; // { dg-error {'__sizeless_struct' tag used in naming 'struct initially_class'} }
+
+union initially_union;
+__sizeless_struct initially_union; // { dg-error {'__sizeless_struct' tag used in naming 'union initially_union'} }
+
+__sizeless_struct initially_sizeless;
+__sizeless_struct initially_sizeless;
+struct initially_sizeless; // { dg-error {'struct' tag used in naming '__sizeless_struct initially_sizeless'} }
+class initially_sizeless; // { dg-error {'class' tag used in naming '__sizeless_struct initially_sizeless'} }
+union initially_sizeless; // { dg-error {'union' tag used in naming '__sizeless_struct initially_sizeless'} }
+enum initially_sizeless; // { dg-error {'initially_sizeless' referred to as enum} }
+
+// Simple __sizeless_struct definitions.
+
+__sizeless_struct ta { int a; };
+__sizeless_struct tb { int a; }; // { dg-message {note: class type 'tb' is incomplete} "don't want this message" { xfail *-*-* } }
+typedef __sizeless_struct { int a; } tc;
+__sizeless_struct td { td (int); void f (); };
+__sizeless_struct te { te *f (); int x; };
+__sizeless_struct tf { ~tf (); tf &operator= (const tf &); };
+__sizeless_struct tg
+{
+#if __cplusplus >= 201103L
+ tg () = default;
+#else
+ tg () {}
+#endif
+ tg (const tg &);
+
+ static int exists;
+};
+__sizeless_struct th
+{
+#if __cplusplus >= 201103L
+ th &operator= (const th &) = delete;
+#else
+ private:
+ th &operator= (const th &);
+#endif
+ public:
+ operator int () const;
+ tb *operator& () const;
+
+ typedef int my_int;
+};
+
+__sizeless_struct ti {
+ int i[2];
+};
+
+__sizeless_struct empty {};
+
+__sizeless_struct range {
+ ta *const *begin () const { return a; }
+ ta *const *end () const { return a + 4; }
+ ta *a[4];
+};
+
+// Invalid redefinitions.
+
+__sizeless_struct redef1 { int x; };
+__sizeless_struct redef1 { int y; }; // { dg-error {redefinition of '__sizeless_struct redef1'} }
+
+__sizeless_struct indestructible {
+#if __cplusplus >= 201103L
+ ~indestructible () = delete;
+#endif
+};
+
+#if __cplusplus >= 201103L
+__sizeless_struct sizeless_nsdmi {
+ ta ta1 = {};
+ ta ta2 = [=] () { return ta1; }();
+};
+#endif
+
+// Sizeless objects with global scope.
+
+ta global_ta; // { dg-error {sizeless variable 'ta global_ta' cannot have static storage duration} }
+static ta local_ta; // { dg-error {sizeless variable 'ta local_ta' cannot have static storage duration} }
+extern ta extern_ta; // { dg-error {sizeless variable 'ta extern_ta' cannot have static storage duration} }
+__thread ta tls_ta; // { dg-error {sizeless variable 'ta tls_ta' cannot have thread-local storage duration} }
+
+// Inheriting sizeless types
+
+struct inherit_ta1 : public ta {}; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+struct inherit_ta2 : protected ta {}; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+struct inherit_ta3 : private ta {}; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+struct inherit_ta4 : virtual public ta {}; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+class inherit_ta5 : public ta {}; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+__sizeless_struct inherit_ta6 : public ta {}; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+
+// Inheritance in sizeless types.
+
+struct sized_base { int a; };
+
+__sizeless_struct inherit_sized1 : public sized_base {}; // { dg-error {sizeless type 'inherit_sized1' cannot have base classes} }
+__sizeless_struct inherit_sized2 : protected sized_base {}; // { dg-error {sizeless type 'inherit_sized2' cannot have base classes} }
+__sizeless_struct inherit_sized3 : private sized_base {}; // { dg-error {sizeless type 'inherit_sized3' cannot have base classes} }
+__sizeless_struct inherit_sized4 : virtual public sized_base {}; // { dg-error {sizeless type 'inherit_sized4' cannot have base classes} }
+
+// Virtual methods in sizeless types.
+
+__sizeless_struct with_virtuals {
+ virtual ~with_virtuals (); // { dg-error {sizeless types cannot have virtual functions} }
+ virtual void f1 (); // { dg-error {sizeless types cannot have virtual functions} }
+ virtual void f2 () = 0; // { dg-error {sizeless types cannot have virtual functions} }
+ virtual void f3 () const; // { dg-error {sizeless types cannot have virtual functions} }
+#if __cplusplus >= 201103L
+ virtual void f4 () override; // { dg-error {sizeless types cannot have virtual functions} "" { target c++11 } }
+ void f5 () override; // { dg-error {'void with_virtuals::f5\(\)' marked 'override', but does not override} "" { target c++11 } }
+#endif
+};
+
+// Sizeless fields.
+
+struct struct1 {
+ ta a; // { dg-error {field 'a' has incomplete type} }
+ __sizeless_struct { int i; }; // { dg-error {'struct struct1' cannot have anonymous sizeless fields} }
+ __sizeless_struct { int i; } named; // { dg-error {field 'named' has incomplete type} }
+
+ __sizeless_struct nested { int i; };
+};
+
+union union1 {
+ ta a; // { dg-error {field 'a' has incomplete type} }
+ __sizeless_struct { int i; }; // { dg-error {'union union1' cannot have anonymous sizeless fields} }
+ __sizeless_struct { int i; } named; // { dg-error {field 'named' has incomplete type} }
+
+ __sizeless_struct nested { int i; };
+};
+
+// Sizeless fields in templated structures.
+
+template<typename T>
+struct templated_struct1 {
+ ta a; // { dg-error {field 'a' has incomplete type} }
+ __sizeless_struct { int i; }; // { dg-error {'struct templated_struct1<T>' cannot have anonymous sizeless fields} }
+ __sizeless_struct { int i; } named;
+
+ __sizeless_struct nested { int i; };
+};
+
+template<typename T>
+struct templated_struct2 {
+ __sizeless_struct { int i; } named; // { dg-error {'templated_struct2<T>::named' has incomplete type} }
+};
+
+template struct templated_struct2<int>;
+
+template<typename T>
+struct templated_struct3 {
+ T a; // { dg-error {'templated_struct3<T>::a' has incomplete type} }
+};
+
+template struct templated_struct3<ta>;
+
+// Nested aggregates.
+
+__sizeless_struct multilevel {
+ ta a1, a2;
+ struct { int i1; };
+ union { int i2; };
+ __sizeless_struct { ta a3; };
+};
+
+template<int N>
+__sizeless_struct templated_sizeless1 {
+ int x[N]; // { dg-error {size of array is negative} }
+};
+
+typedef __sizeless_struct templated_sizeless1<1> template_sizeless1_typedef;
+template __sizeless_struct templated_sizeless1<2>;
+template __sizeless_struct templated_sizeless1<-1>; // { dg-message {required from here} }
+
+#if __cplusplus >= 201103L
+template<int N> using typedef_sizeless1 = ta;
+template<int N> using typedef_sizeless1 = ta; // { dg-error {redefinition of 'template<int N> using typedef_sizeless1 = ta'} "" { target c++11 } }
+#endif
+
+template<typename T1, typename T2>
+__sizeless_struct templated_sizeless2 {};
+template<typename T1, typename T2>
+__sizeless_struct templated_sizeless2<T1, T2 *> {};
+void use_templated_sizeless2 () { templated_sizeless2<int *, int *> x; }
+template<typename T1, typename T2>
+__sizeless_struct templated_sizeless2<T1 *, T2> {}; // { dg-error {declaration of '__sizeless_struct templated_sizeless2<T1\*, T2>' ambiguates earlier template instantiation for '__sizeless_struct templated_sizeless2<int\*, int\*>'} }
+
+template<typename T>
+__sizeless_struct templated_sizeless3
+{
+ typename T::nested member;
+};
+template __sizeless_struct templated_sizeless3<struct1>;
+
+template<typename T>
+__sizeless_struct templated_sizeless4
+{
+ typedef T type;
+};
+
+template<typename T>
+struct typename_static_member_user
+{
+ static typename templated_sizeless4<T>::type static_member;
+};
+template struct typename_static_member_user<int>;
+
+template<typename T1>
+__sizeless_struct templated_sizeless5
+{
+ template<typename T2>
+ __sizeless_struct nested
+ {
+ T1 x;
+ T2 y;
+ };
+};
+
+template __sizeless_struct templated_sizeless5<int>::nested<float>;
+
+template<>
+template<typename T2>
+__sizeless_struct templated_sizeless5<int>::nested // { dg-error {specialization 'templated_sizeless5<int>::nested<T2>' after instantiation 'templated_sizeless5<int>::nested<float>'} }
+{
+};
+
+// Use of 'friend'.
+
+class friend_of_td
+{
+ friend void td::f ();
+ int x;
+};
+
+template<typename T>
+class templated_friend_of_td
+{
+ friend void td::f ();
+ int x;
+};
+template class templated_friend_of_td<int>;
+
+// Pointers to sizeless types.
+
+ta *global_ta_ptr;
+
+// Types nested in sizeless types.
+
+typename th::my_int global_int1;
+typename th::my_float global_float1; // { dg-error {'my_float' in '__sizeless_struct th' does not name a type} }
+
+// Static members of sizeless types.
+
+int ta::a; // { dg-error {'int ta::a' is not a static data member of '__sizeless_struct ta'} }
+int tg::exists;
+int tg::doesnt_exist; // { dg-error {'int tg::doesnt_exist' is not a static data member of '__sizeless_struct tg'} }
+
+// Member pointers.
+
+int ta::*ta_memptr1;
+int ta::*ta_memptr2 = &ta::a; // { dg-error {cannot take address of member of sizeless type 'ta'} }
+int ta::*ta_memptr3 = &ta::ta::a; // { dg-error {cannot take address of member of sizeless type 'ta'} }
+void (td::*td_memptr1) (void);
+void (td::*td_memptr2) (void) = &td::f;
+void (td::*td_memptr3) (void) = &td::td::f;
+
+// Sizeless arguments and return values.
+
+void ext_consume_ta (ta);
+void ext_consume_const_int_ref (const int &);
+void ext_consume_varargs (int, ...);
+ta ext_produce_ta ();
+
+// Sizeless types in throw specifications.
+
+#if __cplusplus < 201103L
+void thrower1 () throw (ta); // { dg-warning {invalid use of incomplete type '__sizeless_struct ta'} "" { target c++98_only } }
+void thrower2 () throw (ta); // { dg-warning {invalid use of incomplete type '__sizeless_struct ta'} "" { target c++98_only } }
+void thrower3 () throw (ta); // { dg-warning {invalid use of incomplete type '__sizeless_struct ta'} "" { target c++98_only } }
+#endif
+
+#if __cplusplus >= 201103L
+constexpr int
+constexpr_fn1 ()
+{
+ return ({ ta ta1 = { 100 }; ta1.a; }); // { dg-error {variable 'ta1' of non-literal type 'ta' in 'constexpr' function} "" { target c++11 } }
+}
+
+constexpr int
+constexpr_fn2 (ta ta1) // { dg-error {invalid type for parameter 1} "" { target c++11 } }
+{
+ return ta1.a;
+}
+
+constexpr int
+constexpr_fn3 (empty empty1) // { dg-error {invalid type for parameter 1} "" { target c++11 } }
+{
+ return 0;
+}
+
+constexpr ta
+constexpr_fn4 () // { dg-error {invalid return type 'ta' of 'constexpr' function} "" { target c++11 } }
+{
+ return ta ();
+}
+#endif
+
+// Main tests for statements and expressions.
+
+void
+statements (int n)
+{
+ // Local declarations.
+
+ ta ta1, ta2;
+ tb tb1;
+ td td1 (1);
+ td td2; // { dg-error {no matching function for call to 'td::td\(\)'} }
+ tf tf1;
+ tg tg1;
+ th th1;
+ { templated_sizeless1<2> x; }
+ { indestructible x; } // { dg-error {use of deleted function 'indestructible::~indestructible\(\)'} "" { target c++11 } }
+ volatile ta volatile_ta1;
+#if __cplusplus >= 201103L
+ sizeless_nsdmi nsdmi1;
+#endif
+
+ // Layout queries.
+
+ sizeof (ta); // { dg-error {invalid application of 'sizeof' to incomplete type} }
+ sizeof (ta1); // { dg-error {invalid application of 'sizeof' to incomplete type} }
+ sizeof (ext_produce_ta ()); // { dg-error {invalid application of 'sizeof' to incomplete type} }
+ __alignof (ta); // { dg-error {invalid application of '__alignof__' to incomplete type} }
+ __alignof (ext_produce_ta ()); // { dg-error {invalid application of '__alignof__' to incomplete type} }
+
+ // Initialization.
+
+ int init_int1 = ta1; // { dg-error {cannot convert 'ta' to 'int' in initialization} }
+ int init_int2 = { ta1 }; // { dg-error {cannot convert 'ta' to 'int' in initialization} }
+ int init_int3 = th1;
+
+ ta init_ta1 (ta1);
+ ta init_ta2 (tb1); // { dg-error {no matching function for call to 'ta::ta\(tb&\)'} }
+ ta init_ta3 = ta1;
+ ta init_ta4 = tb1; // { dg-error {conversion from 'tb' to non-scalar type 'ta' requested} }
+ ta init_ta5 = 0; // { dg-error {conversion from 'int' to non-scalar type 'ta' requested} }
+ ta init_ta6 = {};
+ ta init_ta7 = { 0 };
+ ta init_ta8 = { n };
+ ta init_ta9 = { 0, 1 }; // { dg-error {too many initializers for 'ta'} }
+ ta init_ta10 = { tb1 }; // { dg-error {cannot convert 'tb' to 'int' in initialization} }
+
+ td init_td1 (td1);
+ td init_td2 (1, 2); // { dg-error {no matching function for call to 'td::td\(int, int\)'} }
+ td init_td3 (ta1); // { dg-error {no matching function for call to 'td::td\(ta&\)'} }
+ td init_td4 = {}; // { dg-error {could not convert} }
+ // { dg-error {in C\+\+98 'init_td4' must be initialized by constructor, not by '{...}'} "" { target c++98_only } .-1 }
+ td init_td5 = { 1 }; // { dg-error {in C\+\+98 'init_td5' must be initialized by constructor, not by '{...}'} "" { target c++98_only } }
+ td init_td6 = { 1, 2 }; // { dg-error {could not convert} }
+ // { dg-error {in C\+\+98 'init_td6' must be initialized by constructor, not by '{...}'} "" { target c++98_only } .-1 }
+ td init_td7 = { init_td1 }; // { dg-error {in C\+\+98 'init_td7' must be initialized by constructor, not by '{...}'} "" { target c++98_only } }
+
+ tg init_tg1 (tg1);
+ tg init_tg2 = { init_tg1 }; // { dg-error {in C\+\+98 'init_tg2' must be initialized by constructor, not by '{...}'} "" { target c++98_only } }
+ tg init_tg3 = { ta1 }; // { dg-error {could not convert} }
+ // { dg-error {in C\+\+98 'init_tg3' must be initialized by constructor, not by '{...}'} "" { target c++98_only } .-1 }
+ tg init_tg4 = {}; // { dg-error {in C\+\+98 'init_tg4' must be initialized by constructor, not by '{...}'} "" { target c++98_only } }
+
+ multilevel init_multilevel1 = { ta1, ta1, 1, 2, ta1 };
+ multilevel init_multilevel2 = { 1, 2, 3, 4, 5 };
+
+ // Constructor calls.
+
+ (0, ta ());
+ (0, ta (0)); // { dg-error {no matching function for call to 'ta::ta\(int\)'} }
+ (0, ta (ta1));
+ (0, ta (tb1)); // { dg-error {no matching function for call to 'ta::ta\(tb\&\)'} }
+
+ (0, td ()); // { dg-error {no matching function for call to 'td::td\(\)'} }
+ (0, td (1));
+ (0, td (td1));
+
+ // constexprs.
+
+#if __cplusplus >= 201103L
+ constexpr ta constexpr_ta1 = {}; // { dg-error {the type 'const ta' of 'constexpr' variable 'constexpr_ta1' is not literal} "" { target c++11 } }
+ constexpr empty constexpr_empty1 = {}; // { dg-error {the type 'const empty' of 'constexpr' variable 'constexpr_empty1' is not literal} "" { target c++11 } }
+#endif
+
+ // Lvalue reference binding.
+
+ ta &lvalue_ref_ta1 = ta1;
+ ta &lvalue_ref_ta2 = ext_produce_ta (); // { dg-error {cannot bind non-const lvalue reference of type 'ta&' to an rvalue of type 'ta'} }
+ ta &lvalue_ref_ta3 = tb1; // { dg-error {invalid initialization of reference of type 'ta&' from expression of type 'tb'} }
+
+ const ta &const_lvalue_ref_ta1 = ta1;
+ const ta &const_lvalue_ref_ta2 = ext_produce_ta ();
+ const ta &const_lvalue_ref_ta3 = tb1; // { dg-error {invalid initialization of reference of type 'const ta&' from expression of type 'tb'} }
+
+ td &lvalue_ref_td1 = 1; // { dg-error {cannot bind non-const lvalue reference of type 'td&' to an rvalue of type 'td'} }
+ td &lvalue_ref_td2 = ta1; // { dg-error {invalid initialization of reference of type 'td&' from expression of type 'ta'} }
+
+ const td &const_lvalue_ref_td1 = 1;
+ const td &const_lvalue_ref_td2 = ta1; // { dg-error {invalid initialization of reference of type 'const td&' from expression of type 'ta'} }
+
+ // Compound literals.
+
+ (int) { ta1 }; // { dg-error {cannot convert 'ta' to 'int' in initialization} }
+
+ // Assignment.
+
+ n = ta1; // { dg-error {cannot convert 'ta' to 'int' in assignment} }
+
+ ta1 = 0; // { dg-error {no match for 'operator=' in 'ta1 = 0' \(operand types are 'ta' and 'int'\)} }
+ ta1 = ta2;
+ ta1 = tb1; // { dg-error {no match for 'operator=' in 'ta1 = tb1' \(operand types are 'ta' and 'tb'\)} }
+
+ td1 = 0;
+ td1 = init_td1;
+ td1 = ta1; // { dg-error {no match for 'operator=' in 'td1 = ta1' \(operand types are 'td' and 'ta'\)} }
+
+ th1 = th1; // { dg-error {'th& th::operator=\(const th&\)' is private within this context} "" { target c++98_only } }
+ // { dg-error {use of deleted function 'th& th::operator=\(const th&\)'} "" { target c++11 } .-1 }
+
+ // Casting.
+
+ (ta) ta1;
+ (void) ta1;
+ (void) volatile_ta1;
+ (void) *&volatile_ta1;
+
+ // Addressing and dereferencing.
+
+ ta *ta_ptr = &ta1;
+ tb *tb_ptr = &th1;
+ th *th_ptr = &th1; // { dg-error {cannot convert 'tb\*' to 'th\*' in initialization} }
+
+ // Pointer arithmetic.
+
+ ++ta_ptr; // { dg-error {cannot increment a pointer to incomplete type 'ta'} }
+ --ta_ptr; // { dg-error {cannot decrement a pointer to incomplete type 'ta'} }
+ ta_ptr++; // { dg-error {cannot increment a pointer to incomplete type 'ta'} }
+ ta_ptr--; // { dg-error {cannot decrement a pointer to incomplete type 'ta'} }
+ ta_ptr += 0; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+ ta_ptr += 1; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+ ta_ptr -= 0; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+ ta_ptr -= 1; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+ ta_ptr - ta_ptr; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+ ta &ta_ref1 = ta_ptr[0]; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+ ta &ta_ref2 = ta_ptr[1]; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+
+ // New and delete.
+
+ new ta; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+ new ta (); // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+ new td (1); // { dg-error {invalid use of incomplete type '__sizeless_struct td'} }
+ new tg (); // { dg-error {invalid use of incomplete type '__sizeless_struct tg'} }
+
+ new (global_ta_ptr) ta; // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+ new (global_ta_ptr) ta (); // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+
+ delete ta_ptr; // { dg-error {cannot delete objects of sizeless type 'ta'} }
+ delete[] ta_ptr; // { dg-error {cannot delete objects of sizeless type 'ta'} }
+
+ // Member access.
+
+ ta1.a = 1;
+ ta1.b = 1; // { dg-error {'__sizeless_struct ta' has no member named 'b'} }
+ ta_ptr->a = 1;
+ (void) &ta::b; // { dg-error {'b' is not a member of 'ta'} }
+
+ // Unary vector arithmetic.
+
+ __real ta1; // { dg-error {no match for '__real__' in '__real__ ta1'} }
+ __imag ta1; // { dg-error {no match for '__imag__' in '__imag__ ta1'} }
+
+ // Conditional expressions.
+
+ 0 ? ta1 : ta1;
+
+ // Function arguments.
+
+ ext_consume_ta (ta1);
+ ext_consume_ta (tb1); // { dg-error {could not convert 'tb1' from 'tb' to 'ta'} }
+ ext_consume_const_int_ref (ta1); // { dg-error {invalid initialization of reference of type 'const int&' from expression of type 'ta'} }
+ ext_consume_const_int_ref (th1);
+ ext_consume_varargs (ta1); // { dg-error {cannot convert 'ta' to 'int'} }
+ ext_consume_varargs (1, ta1);
+ ext_consume_varargs (1, tg1); // { dg-warning {passing objects of non-trivially-copyable type '__sizeless_struct tg'} }
+ (td1.*td_memptr3) ();
+
+ // Function returns.
+
+ ext_produce_ta ();
+ ta1 = ext_produce_ta ();
+ tb1 = ext_produce_ta (); // { dg-error {no match for 'operator=' in 'tb1 = ext_produce_ta\(\)'} }
+
+ // Use of 'auto'.
+
+#if __cplusplus >= 201103L
+ auto auto_ta1 = ta1;
+ auto auto_ta2 = ext_produce_ta ();
+#endif
+
+ // Varargs processing.
+
+ __builtin_va_list valist;
+ __builtin_va_arg (valist, ta);
+
+ // Use in atomics.
+
+ __sync_lock_test_and_set (global_ta_ptr, 0); // { dg-error {operand type '[^']*'[^\n]* is incompatible with argument 1} }
+
+ __builtin_memset (&ta1, 0, 100);
+ __builtin_memset (&td1, 0, 100); // { dg-warning {clearing an object of non-trivial type '__sizeless_struct td'} }
+ __builtin_memset (&tg1, 0, 100); // { dg-warning {clearing an object of non-trivial type '__sizeless_struct tg'} }
+
+ // Other built-ins.
+
+ __builtin_launder (ta1); // { dg-error {non-pointer argument to '__builtin_launder'} }
+
+ // Lambdas.
+
+#if __cplusplus >= 201103L
+ [ta1] () {}; // { dg-error {capture by copy of incomplete type 'ta'} "" { target c++11 } }
+ [=] () { &ta1; }; // { dg-error {capture by copy of incomplete type 'ta'} "" { target c++11 } }
+ [&ta1] () { ta1 = ta2; }; // { dg-error {'ta2' is not captured} "" { target c++11 } }
+ [&ta1, &ta2] () { ta1 = ta2; };
+ [&] () { ta1 = ta2; };
+ [] () { return ext_produce_ta (); } ();
+#endif
+
+ // Exceptions.
+
+ throw td (1); // { dg-error {invalid use of incomplete type '__sizeless_struct td'} }
+ try {} catch (ta x) {} // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} }
+#if __cplusplus < 201103L
+ thrower2 (); // { dg-error {call to function 'void thrower2\(\)' which throws incomplete type '__sizeless_struct ta'} "" { target c++98_only } }
+#endif
+
+ // Ranges.
+
+#if __cplusplus >= 201103L
+ for (auto x : empty ()) {} // { dg-error {'begin' was not declared in this scope} "" { target c++11 } }
+ // { dg-error {'end' was not declared in this scope} "" { target c++11 } .-1 }
+ for (auto x : range ()) {}
+#endif
+
+ // Use in goto.
+
+ goto *ta1; // { dg-error {cannot convert 'ta1' from type 'ta' to type 'void\*'} }
+
+ // Use in traits. Doesn't use static_assert so that tests work with C++98.
+
+ { typedef int f[__has_nothrow_assign (ta) ? 1 : -1]; }
+ { typedef int f[__has_nothrow_assign (td) ? 1 : -1]; }
+ { typedef int f[!__has_nothrow_assign (tf) ? 1 : -1]; }
+ { typedef int f[__has_nothrow_assign (tg) ? 1 : -1]; }
+#if __cplusplus >= 201103L
+ { typedef int f[__has_nothrow_assign (th) ? 1 : -1]; }
+#else
+ { typedef int f[!__has_nothrow_assign (th) ? 1 : -1]; }
+#endif
+
+ { typedef int f[__has_trivial_assign (ta) ? 1 : -1]; }
+ { typedef int f[__has_trivial_assign (td) ? 1 : -1]; }
+ { typedef int f[!__has_trivial_assign (tf) ? 1 : -1]; }
+ { typedef int f[__has_trivial_assign (tg) ? 1 : -1]; }
+#if __cplusplus >= 201103L
+ { typedef int f[__has_trivial_assign (th) ? 1 : -1]; }
+#else
+ { typedef int f[!__has_trivial_assign (th) ? 1 : -1]; }
+#endif
+
+ { typedef int f[__has_nothrow_constructor (ta) ? 1 : -1]; }
+ { typedef int f[!__has_nothrow_constructor (td) ? 1 : -1]; }
+ { typedef int f[__has_nothrow_constructor (tf) ? 1 : -1]; }
+#if __cplusplus >= 201103L
+ { typedef int f[__has_nothrow_constructor (tg) ? 1 : -1]; }
+#else
+ { typedef int f[!__has_nothrow_constructor (tg) ? 1 : -1]; }
+#endif
+ { typedef int f[__has_nothrow_constructor (th) ? 1 : -1]; }
+
+ { typedef int f[__has_trivial_constructor (ta) ? 1 : -1]; }
+ { typedef int f[!__has_trivial_constructor (td) ? 1 : -1]; }
+ { typedef int f[__has_trivial_constructor (tf) ? 1 : -1]; }
+#if __cplusplus >= 201103L
+ { typedef int f[__has_trivial_constructor (tg) ? 1 : -1]; }
+#else
+ { typedef int f[!__has_trivial_constructor (tg) ? 1 : -1]; }
+#endif
+ { typedef int f[__has_trivial_constructor (th) ? 1 : -1]; }
+
+ { typedef int f[__has_nothrow_copy (ta) ? 1 : -1]; }
+ { typedef int f[__has_nothrow_copy (td) ? 1 : -1]; }
+ { typedef int f[__has_nothrow_copy (tf) ? 1 : -1]; }
+ { typedef int f[!__has_nothrow_copy (tg) ? 1 : -1]; }
+ { typedef int f[__has_nothrow_copy (th) ? 1 : -1]; }
+
+ { typedef int f[__has_trivial_copy (ta) ? 1 : -1]; }
+ { typedef int f[__has_trivial_copy (td) ? 1 : -1]; }
+ { typedef int f[__has_trivial_copy (tf) ? 1 : -1]; }
+ { typedef int f[!__has_trivial_copy (tg) ? 1 : -1]; }
+ { typedef int f[__has_trivial_copy (th) ? 1 : -1]; }
+
+ { typedef int f[__has_trivial_destructor (ta) ? 1 : -1]; }
+ { typedef int f[__has_trivial_destructor (td) ? 1 : -1]; }
+ { typedef int f[!__has_trivial_destructor (tf) ? 1 : -1]; }
+ { typedef int f[__has_trivial_destructor (tg) ? 1 : -1]; }
+ { typedef int f[__has_trivial_destructor (th) ? 1 : -1]; }
+
+ { typedef int f[__has_unique_object_representations (ta) ? 1 : -1]; }
+ { typedef int f[!__has_virtual_destructor (ta) ? 1 : -1]; }
+ { typedef int f[!__is_abstract (ta) ? 1 : -1]; }
+ { typedef int f[__is_aggregate (ta) ? 1 : -1]; }
+ { typedef int f[__is_base_of (ta, ta) ? 1 : -1]; }
+ { typedef int f[!__is_base_of (tb, ta) ? 1 : -1]; }
+ { typedef int f[__is_class (ta) ? 1 : -1]; }
+ { typedef int f[!__is_empty (ta) ? 1 : -1]; }
+ { typedef int f[!__is_enum (ta) ? 1 : -1]; }
+ { typedef int f[!__is_final (ta) ? 1 : -1]; }
+ { typedef int f[__is_pod (ta) ? 1 : -1]; }
+ { typedef int f[!__is_polymorphic (ta) ? 1 : -1]; }
+ { typedef int f[__is_same_as (ta, ta) ? 1 : -1]; }
+ { typedef int f[!__is_same_as (ta, int) ? 1 : -1]; }
+ { typedef int f[__is_trivial (ta) ? 1 : -1]; }
+ { typedef int f[!__is_union (ta) ? 1 : -1]; }
+ { typedef int f[!__is_literal_type (ta) ? 1 : -1]; }
+
+ { typedef int f[__is_trivially_copyable (ta) ? 1 : -1]; }
+ { typedef int f[!__is_trivially_copyable (tg) ? 1 : -1]; }
+
+ { typedef int f[!__is_trivially_assignable (ta, int) ? 1 : -1]; }
+ { typedef int f[__is_trivially_assignable (ta, ta) ? 1 : -1]; }
+ { typedef int f[!__is_trivially_assignable (ta, tb) ? 1 : -1]; }
+
+ { typedef int f[!__is_trivially_assignable (td, int) ? 1 : -1]; }
+ { typedef int f[!__is_trivially_assignable (td, ta) ? 1 : -1]; }
+ { typedef int f[__is_trivially_assignable (td, td) ? 1 : -1]; }
+
+ { typedef int f[!__is_trivially_assignable (tf, tf) ? 1 : -1]; }
+
+ { typedef int f[!__is_trivially_assignable (th, th) ? 1 : -1]; } // { dg-error {'th& th::operator=\(const th&\)' is private within this context} "" { target c++98_only } }
+
+ { typedef int f[!__is_assignable (ta, int) ? 1 : -1]; }
+ { typedef int f[__is_assignable (ta, ta) ? 1 : -1]; }
+ { typedef int f[!__is_assignable (ta, tb) ? 1 : -1]; }
+
+ { typedef int f[__is_assignable (td, int) ? 1 : -1]; }
+ { typedef int f[!__is_assignable (td, ta) ? 1 : -1]; }
+ { typedef int f[__is_assignable (td, td) ? 1 : -1]; }
+
+ { typedef int f[__is_assignable (tf, tf) ? 1 : -1]; }
+
+#if __cplusplus >= 201103L
+ { typedef int f[!__is_assignable (th, th) ? 1 : -1]; }
+#else
+ { typedef int f[__is_assignable (th, th) ? 1 : -1]; } // { dg-error {'th& th::operator=\(const th&\)' is private within this context} "" { target c++98_only } }
+#endif
+
+ { typedef int f[__is_trivially_constructible (ta) ? 1 : -1]; }
+ { typedef int f[!__is_trivially_constructible (ta, int) ? 1 : -1]; }
+ { typedef int f[__is_trivially_constructible (ta, ta) ? 1 : -1]; }
+ { typedef int f[!__is_trivially_constructible (ta, tb) ? 1 : -1]; }
+
+ { typedef int f[!__is_trivially_constructible (td) ? 1 : -1]; }
+ { typedef int f[!__is_trivially_constructible (td, int) ? 1 : -1]; }
+ { typedef int f[!__is_trivially_constructible (td, int, int) ? 1 : -1]; }
+ { typedef int f[!__is_trivially_constructible (td, ta) ? 1 : -1]; }
+ { typedef int f[__is_trivially_constructible (td, td) ? 1 : -1]; }
+
+#if __cplusplus >= 201103L
+ { typedef int f[__is_trivially_constructible (tg) ? 1 : -1]; }
+#else
+ { typedef int f[!__is_trivially_constructible (tg) ? 1 : -1]; }
+#endif
+ { typedef int f[!__is_trivially_constructible (tg, tg) ? 1 : -1]; }
+
+ { typedef int f[__is_constructible (ta) ? 1 : -1]; }
+ { typedef int f[!__is_constructible (ta, int) ? 1 : -1]; }
+ { typedef int f[__is_constructible (ta, ta) ? 1 : -1]; }
+ { typedef int f[!__is_constructible (ta, tb) ? 1 : -1]; }
+
+ { typedef int f[!__is_constructible (td) ? 1 : -1]; }
+ { typedef int f[__is_constructible (td, int) ? 1 : -1]; }
+ { typedef int f[!__is_constructible (td, int, int) ? 1 : -1]; }
+ { typedef int f[!__is_constructible (td, ta) ? 1 : -1]; }
+ { typedef int f[__is_constructible (td, td) ? 1 : -1]; }
+
+ { typedef int f[__is_constructible (tg) ? 1 : -1]; }
+ { typedef int f[__is_constructible (tg, tg) ? 1 : -1]; }
+}
+
+// Member function definitions
+
+void
+td::f ()
+{
+ friend_of_td friend1;
+ friend1.x = 0;
+ templated_friend_of_td<int> friend2;
+ friend2.x = 0;
+}
+
+te *
+te::f ()
+{
+ x += 1;
+ if (x & 3)
+ f ();
+ return this;
+}
+
+void te::no_such_fn () {} // { dg-error {no declaration matches 'void te::no_such_fn\(\)'} }
+
+// Function parameters in definitions.
+
+void
+unnamed_st1 (ta)
+{
+}
+
+void
+named_st1 (ta param1)
+{
+ ta ta1 = param1;
+}
+
+// Function return values in definitions.
+
+ta
+ret_st1 (ta param)
+{
+ return param;
+}
+
+ta
+bad_ret_st1 (tb param)
+{
+ return param; // { dg-error {could not convert 'param' from 'tb' to 'ta'} }
+}
+
+#if __cplusplus >= 201103L
+ti
+ret_ti ()
+{
+ return { 1, 2 };
+}
+#endif
+
+#if __cplusplus < 201103L
+void thrower3 () throw (ta) {} // { dg-error {invalid use of incomplete type '__sizeless_struct ta'} "" { target c++98_only } }
+ // { dg-warning {invalid use of incomplete type '__sizeless_struct ta'} "" { target c++98_only } .-1 }
+#endif
+
+// Using "auto" as a return type.
+
+#if __cplusplus >= 201402L
+auto auto_ret_ta (ta *ptr) { return *ptr; }
+const auto &auto_ret_const_ta_ref (ta *ptr) { return *ptr; }
+auto &auto_ret_ta_ref (ta *ptr) { return *ptr; }
+auto &&auto_ret_ta_rvalue_ref (ta *ptr) { return *ptr; }
+#endif
+
+// Invalid destructor calls.
+
+template<typename T>
+void
+destroy_via_x (T t)
+{
+ t.T::~X(); // { dg-error {no type named 'X' in '__sizeless_struct ta'} }
+}
+
+void
+call_destroy_via_x ()
+{
+ destroy_via_x (ta ());
+}
===================================================================
@@ -0,0 +1,2 @@
+__sizeless_struct s {};
+const int foo = __is_literal_type (s);
===================================================================
@@ -0,0 +1,22 @@
+// { dg-options "-std=c++17" }
+
+__sizeless_struct sizeless_pair {
+ int a, b;
+};
+
+void
+f (sizeless_pair pair)
+{
+ { auto [i] = pair; } // { dg-error {only 1 name provided for structured binding} }
+ { auto [i, j] = pair; }
+ { auto [i, j, k] = pair; } // { dg-error {3 names provided for structured binding} }
+ { auto &[i, j] = pair; }
+}
+
+template<int N>
+int
+templated_f (sizeless_pair pair)
+{
+ auto [i, j] = pair;
+ return i + j + N;
+}
===================================================================
@@ -0,0 +1,20 @@
+// { dg-do run }
+
+__sizeless_struct s
+{
+#if __cplusplus >= 201103L
+ int x = 12345;
+#else
+ s () : x (12345) {}
+ int x;
+#endif
+};
+
+int
+main ()
+{
+ s s1;
+ if (s1.x != 12345)
+ __builtin_abort ();
+ return 0;
+}
===================================================================
@@ -0,0 +1,12 @@
+// { dg-do run }
+
+struct t {
+ ~t () { __builtin_exit (0); }
+};
+
+__sizeless_struct s {
+ ~s () {}
+ t t1;
+};
+
+int main () { s (); __builtin_abort (); }
===================================================================
@@ -0,0 +1,14 @@
+// { dg-options "-fdump-tree-gimple" }
+
+__sizeless_struct s
+{
+ int x;
+};
+
+__INTPTR_TYPE__
+foo ()
+{
+ return (__INTPTR_TYPE__) &((s *) 0)->x;
+}
+
+// { dg-final { scan-tree-dump-not {->x} "gimple" } }
===================================================================
@@ -0,0 +1,20 @@
+// { dg-run }
+
+__sizeless_struct s
+{
+ s () { x = 0; }
+ void f () { x = 1000; }
+ int x;
+};
+
+void (s::*f_ptr) (void) = &s::f;
+
+int
+main ()
+{
+ s s1;
+ (s1.*f_ptr) ();
+ if (s1.x != 1000)
+ __builtin_abort ();
+ return 0;
+}