===================================================================
@@ -104,6 +104,7 @@ enum rid
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
RID_BUILTIN_TGMATH,
RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
+ RID_SIZELESS_STRUCT,
/* TS 18661-3 keywords, in the same sequence as the TI_* values. */
RID_FLOAT16,
@@ -750,10 +751,18 @@ #define C_TYPE_OBJECT_OR_INCOMPLETE_P(ty
#define COMPLETE_OR_VOID_TYPE_P(NODE) \
(COMPLETE_TYPE_P (NODE) || VOID_TYPE_P (NODE))
+/* Nonzero if this type is definite or is cv void. */
+#define DEFINITE_OR_VOID_TYPE_P(NODE) \
+ (DEFINITE_TYPE_P (NODE) || VOID_TYPE_P (NODE))
+
/* Nonzero if this type is complete or is an array with unspecified bound. */
#define COMPLETE_OR_UNBOUND_ARRAY_TYPE_P(NODE) \
(COMPLETE_TYPE_P (TREE_CODE (NODE) == ARRAY_TYPE ? TREE_TYPE (NODE) : (NODE)))
+/* Nonzero if this type is definite or is an array with unspecified bound. */
+#define DEFINITE_OR_UNBOUND_ARRAY_TYPE_P(NODE) \
+ (DEFINITE_TYPE_P (TREE_CODE (NODE) == ARRAY_TYPE ? TREE_TYPE (NODE) : (NODE)))
+
/* Return true if the argument is a complete type or an array
of unknown bound (whose type is incomplete but) whose elements
have complete type. */
===================================================================
@@ -425,6 +425,7 @@ const struct c_common_resword c_common_r
{ "__restrict__", RID_RESTRICT, 0 },
{ "__signed", RID_SIGNED, 0 },
{ "__signed__", RID_SIGNED, 0 },
+ { "__sizeless_struct", RID_SIZELESS_STRUCT, 0 },
{ "__thread", RID_THREAD, 0 },
{ "__transaction_atomic", RID_TRANSACTION_ATOMIC, 0 },
{ "__transaction_relaxed", RID_TRANSACTION_RELAXED, 0 },
@@ -3067,6 +3068,32 @@ shorten_compare (location_t loc, tree *o
return NULL_TREE;
}
+/* Return the size nominally occupied by an object of type TYPE
+ when it resides in memory. The value is measured in units of bytes,
+ and its data type is that normally used for type sizes
+ (which is the first type created by make_signed_type or
+ make_unsigned_type).
+
+ Return error_mark_node if TYPE is incomplete, and in addition
+ raise an error if COMPLAIN is true. LOC is the location to use
+ for reporting error messages. */
+
+tree
+complete_size_in_bytes (location_t loc, const_tree type, bool complain)
+{
+ if (type == error_mark_node)
+ return error_mark_node;
+
+ if (!COMPLETE_TYPE_P (type))
+ {
+ if (complain)
+ lang_hooks.types.incomplete_type_error (loc, NULL_TREE, type);
+ return error_mark_node;
+ }
+
+ return TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type));
+}
+
/* Return a tree for the sum or difference (RESULTCODE says which)
of pointer PTROP and integer INTOP. */
@@ -3098,7 +3125,16 @@ pointer_int_sum (location_t loc, enum tr
size_exp = integer_one_node;
}
else
- size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type));
+ {
+ size_exp = complete_size_in_bytes (loc, TREE_TYPE (result_type),
+ complain);
+ if (size_exp == error_mark_node)
+ {
+ if (!complain)
+ return size_exp;
+ size_exp = integer_one_node;
+ }
+ }
/* We are manipulating pointer values, so we don't need to warn
about relying on undefined signed overflow. We disable the
@@ -3663,6 +3699,10 @@ c_alignof_expr (location_t loc, tree exp
{
tree t;
+ if (TREE_TYPE (expr) != error_mark_node
+ && TYPE_SIZELESS_P (TREE_TYPE (expr)))
+ return c_alignof (loc, TREE_TYPE (expr));
+
if (VAR_OR_FUNCTION_DECL_P (expr))
t = size_int (DECL_ALIGN_UNIT (expr));
===================================================================
@@ -38,9 +38,9 @@ #define C_TYPE_FIELDS_VOLATILE(TYPE) TRE
nonzero if the definition of the type has already started. */
#define C_TYPE_BEING_DEFINED(TYPE) TYPE_LANG_FLAG_0 (TYPE)
-/* In an incomplete RECORD_TYPE or UNION_TYPE, a list of variable
+/* In an indefinite RECORD_TYPE or UNION_TYPE, a list of variable
declarations whose type would be completed by completing that type. */
-#define C_TYPE_INCOMPLETE_VARS(TYPE) TYPE_VFIELD (TYPE)
+#define C_TYPE_INDEFINITE_VARS(TYPE) TYPE_VFIELD (TYPE)
/* In an IDENTIFIER_NODE, nonzero if this identifier is actually a
keyword. C_RID_CODE (node) is then the RID_* value of the keyword. */
@@ -574,14 +574,15 @@ extern tree start_enum (location_t, stru
extern bool start_function (struct c_declspecs *, struct c_declarator *, tree);
extern tree start_decl (struct c_declarator *, struct c_declspecs *, bool,
tree);
-extern tree start_struct (location_t, enum tree_code, tree,
+extern tree start_struct (location_t, enum tree_code, bool, tree,
struct c_struct_parse_info **);
extern void store_parm_decls (void);
extern void store_parm_decls_from (struct c_arg_info *);
extern void temp_store_parm_decls (tree, tree);
extern void temp_pop_parm_decls (void);
extern tree xref_tag (enum tree_code, tree);
-extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree);
+extern struct c_typespec parser_xref_tag (location_t, enum tree_code,
+ bool, tree);
extern struct c_parm *build_c_parm (struct c_declspecs *, tree,
struct c_declarator *, location_t);
extern struct c_declarator *build_attrs_declarator (tree,
@@ -626,7 +627,7 @@ extern bool c_vla_unspec_p (tree x, tree
extern struct c_switch *c_switch_stack;
extern tree c_objc_common_truthvalue_conversion (location_t, tree);
-extern tree require_complete_type (location_t, tree);
+extern tree require_complete_type (location_t, tree, bool = false);
extern bool same_translation_unit_p (const_tree, const_tree);
extern int comptypes (tree, tree);
extern int comptypes_check_different_types (tree, tree, bool *);
@@ -774,6 +775,19 @@ set_c_expr_source_range (c_expr *expr,
/* In c-fold.c */
extern vec<tree> incomplete_record_decls;
+/* Do `exp = require_definite_type (loc, exp);' to make sure exp
+ does not have an indefinite type; i.e. to make sure that the
+ definition of the type has been seen and completely processed.
+ Void types are always indefinite (and thus incomplete).
+
+ LOC is the location of the use. */
+
+inline tree
+require_definite_type (location_t loc, tree value)
+{
+ return require_complete_type (loc, value, true);
+}
+
#if CHECKING_P
namespace selftest {
extern void run_c_tests (void);
===================================================================
@@ -3113,7 +3113,7 @@ pushdecl (tree x)
slot (e.g. "f(void a, ...)") - that doesn't count as an
incomplete type. */
if (TREE_TYPE (x) != error_mark_node
- && !COMPLETE_TYPE_P (TREE_TYPE (x)))
+ && !DEFINITE_TYPE_P (TREE_TYPE (x)))
{
tree element = TREE_TYPE (x);
@@ -3124,9 +3124,9 @@ pushdecl (tree x)
if (RECORD_OR_UNION_TYPE_P (element)
&& (TREE_CODE (x) != TYPE_DECL
|| TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE)
- && !COMPLETE_TYPE_P (element))
- C_TYPE_INCOMPLETE_VARS (element)
- = tree_cons (NULL_TREE, x, C_TYPE_INCOMPLETE_VARS (element));
+ && !DEFINITE_TYPE_P (element))
+ C_TYPE_INDEFINITE_VARS (element)
+ = tree_cons (NULL_TREE, x, C_TYPE_INDEFINITE_VARS (element));
}
return x;
}
@@ -3928,13 +3928,14 @@ c_check_switch_jump_warnings (struct c_s
If THISLEVEL_ONLY is nonzero, searches only the current_scope.
CODE says which kind of type the caller wants;
it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE.
+ SIZELESS_P is true if the type should be sizeless rather than sized.
If PLOC is not NULL and this returns non-null, it sets *PLOC to the
location where the tag was defined.
If the wrong kind of type is found, an error is reported. */
static tree
-lookup_tag (enum tree_code code, tree name, bool thislevel_only,
- location_t *ploc)
+lookup_tag (enum tree_code code, bool sizeless_p, tree name,
+ bool thislevel_only, location_t *ploc)
{
struct c_binding *b = I_TAG_BINDING (name);
bool thislevel = false;
@@ -3944,7 +3945,9 @@ lookup_tag (enum tree_code code, tree na
/* We only care about whether it's in this level if
thislevel_only was set or it might be a type clash. */
- if (thislevel_only || TREE_CODE (b->decl) != code)
+ bool clash_p = (TREE_CODE (b->decl) != code
+ || TYPE_SIZELESS_P (b->decl) != sizeless_p);
+ if (thislevel_only || clash_p)
{
/* For our purposes, a tag in the external scope is the same as
a tag in the file scope. (Primarily relevant to Objective-C
@@ -3958,7 +3961,7 @@ lookup_tag (enum tree_code code, tree na
if (thislevel_only && !thislevel)
return NULL_TREE;
- if (TREE_CODE (b->decl) != code)
+ if (clash_p)
{
/* Definition isn't the kind we were looking for. */
pending_invalid_xref = name;
@@ -4346,6 +4349,7 @@ shadow_tag_warned (const struct c_declsp
{
tree value = declspecs->type;
enum tree_code code = TREE_CODE (value);
+ bool sizeless_p = TYPE_SIZELESS_P (value);
if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE)
/* Used to test also that TYPE_SIZE (value) != 0.
@@ -4412,7 +4416,7 @@ shadow_tag_warned (const struct c_declsp
else
{
pending_invalid_xref = NULL_TREE;
- t = lookup_tag (code, name, true, NULL);
+ t = lookup_tag (code, sizeless_p, name, true, NULL);
if (t == NULL_TREE)
{
@@ -4759,12 +4763,13 @@ start_decl (struct c_declarator *declara
We already gave a warning, so we don't need another one. */
if (TREE_TYPE (decl) == error_mark_node)
initialized = false;
- else if (COMPLETE_TYPE_P (TREE_TYPE (decl)))
+ else if (DEFINITE_TYPE_P (TREE_TYPE (decl)))
{
- /* A complete type is ok if size is fixed. */
+ /* A definite type is ok if size is fixed. */
- if (TREE_CODE (TYPE_SIZE (TREE_TYPE (decl))) != INTEGER_CST
- || C_DECL_VARIABLE_SIZE (decl))
+ if (!TYPE_SIZELESS_P (TREE_TYPE (decl))
+ && (TREE_CODE (TYPE_SIZE (TREE_TYPE (decl))) != INTEGER_CST
+ || C_DECL_VARIABLE_SIZE (decl)))
{
error ("variable-sized object may not be initialized");
initialized = false;
@@ -5046,6 +5051,19 @@ finish_decl (tree decl, location_t init_
&& COMPLETE_TYPE_P (TREE_TYPE (decl)))
layout_decl (decl, 0);
+ if (TREE_TYPE (decl) != error_mark_node
+ && TYPE_SIZELESS_P (type)
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+ {
+ if (DECL_THREAD_LOCAL_P (decl))
+ error ("sizeless variable %q+D cannot have thread-local"
+ " storage duration", decl);
+ else
+ error ("sizeless variable %q+D cannot have static storage"
+ " duration", decl);
+ TREE_TYPE (decl) = error_mark_node;
+ }
+
if (DECL_SIZE (decl) == NULL_TREE
/* Don't give an error if we already gave one earlier. */
&& TREE_TYPE (decl) != error_mark_node
@@ -5384,7 +5402,7 @@ build_compound_literal (location_t loc,
TREE_TYPE (DECL_INITIAL (decl)) = type;
}
- if (type == error_mark_node || !COMPLETE_TYPE_P (type))
+ if (type == error_mark_node || !DEFINITE_TYPE_P (type))
{
c_incomplete_type_error (loc, NULL_TREE, type);
return error_mark_node;
@@ -6913,7 +6931,7 @@ grokdeclarator (const struct c_declarato
type = build_pointer_type (type);
}
else if (TREE_CODE (type) != ERROR_MARK
- && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type))
+ && !DEFINITE_OR_UNBOUND_ARRAY_TYPE_P (type))
{
if (name)
error_at (loc, "field %qE has incomplete type", name);
@@ -7252,7 +7270,7 @@ grokparms (struct c_arg_info *arg_info,
if (type == error_mark_node)
continue;
- if (!COMPLETE_TYPE_P (type))
+ if (!DEFINITE_TYPE_P (type))
{
if (funcdef_flag)
{
@@ -7499,10 +7517,13 @@ get_parm_info (bool ellipsis, tree expr)
/* Get the struct, enum or union (CODE says which) with tag NAME.
Define the tag as a forward-reference with location LOC if it is
not defined. Return a c_typespec structure for the type
- specifier. */
+ specifier.
+
+ SIZELESS_P says whether the type described by CODE is sizeless. */
struct c_typespec
-parser_xref_tag (location_t loc, enum tree_code code, tree name)
+parser_xref_tag (location_t loc, enum tree_code code, bool sizeless_p,
+ tree name)
{
struct c_typespec ret;
tree ref;
@@ -7514,7 +7535,7 @@ parser_xref_tag (location_t loc, enum tr
/* If a cross reference is requested, look up the type
already defined for this tag and return it. */
- ref = lookup_tag (code, name, false, &refloc);
+ ref = lookup_tag (code, sizeless_p, name, false, &refloc);
/* If this is the right type of tag, return what we found.
(This reference will be shadowed by shadow_tag later if appropriate.)
If this is the wrong type of tag, do not return it. If it was the
@@ -7568,6 +7589,7 @@ parser_xref_tag (location_t loc, enum tr
the forward-reference will be altered into a real type. */
ref = make_node (code);
+ TYPE_SIZELESS_P (ref) = sizeless_p;
if (code == ENUMERAL_TYPE)
{
/* Give the type a default layout like unsigned int
@@ -7594,13 +7616,15 @@ parser_xref_tag (location_t loc, enum tr
tree
xref_tag (enum tree_code code, tree name)
{
- return parser_xref_tag (input_location, code, name).spec;
+ /* At present, this function only needs to support sized types. */
+ return parser_xref_tag (input_location, code, false, name).spec;
}
/* Make sure that the tag NAME is defined *in the current scope*
at least as a forward reference.
LOC is the location of the struct's definition.
CODE says which kind of tag NAME ought to be.
+ SIZELESS_P says whether the associated type should be sizeless.
This stores the current value of the file static STRUCT_PARSE_INFO
in *ENCLOSING_STRUCT_PARSE_INFO, and points STRUCT_PARSE_INFO at a
@@ -7608,7 +7632,7 @@ xref_tag (enum tree_code code, tree name
STRUCT_PARSE_INFO is restored in finish_struct. */
tree
-start_struct (location_t loc, enum tree_code code, tree name,
+start_struct (location_t loc, enum tree_code code, bool sizeless_p, tree name,
struct c_struct_parse_info **enclosing_struct_parse_info)
{
/* If there is already a tag defined at this scope
@@ -7618,7 +7642,7 @@ start_struct (location_t loc, enum tree_
location_t refloc = UNKNOWN_LOCATION;
if (name != NULL_TREE)
- ref = lookup_tag (code, name, true, &refloc);
+ ref = lookup_tag (code, sizeless_p, name, true, &refloc);
if (ref && TREE_CODE (ref) == code)
{
if (TYPE_STUB_DECL (ref))
@@ -7654,6 +7678,7 @@ start_struct (location_t loc, enum tree_
if (ref == NULL_TREE || TREE_CODE (ref) != code)
{
ref = make_node (code);
+ TYPE_SIZELESS_P (ref) = sizeless_p;
pushtag (loc, name, ref);
}
@@ -8118,7 +8143,13 @@ finish_struct (location_t loc, tree t, t
&& TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
&& TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE)
{
- if (TREE_CODE (t) == UNION_TYPE)
+ if (TYPE_SIZELESS_P (t))
+ {
+ error_at (DECL_SOURCE_LOCATION (x),
+ "flexible array member in sizeless struct");
+ TREE_TYPE (x) = error_mark_node;
+ }
+ else if (TREE_CODE (t) == UNION_TYPE)
{
error_at (DECL_SOURCE_LOCATION (x),
"flexible array member in union");
@@ -8144,6 +8175,19 @@ finish_struct (location_t loc, tree t, t
pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic,
"invalid use of structure with flexible array member");
+ if (TREE_TYPE (x) != error_mark_node
+ && TYPE_SIZELESS_P (TREE_TYPE (x))
+ && !TYPE_SIZELESS_P (t))
+ {
+ if (DECL_NAME (x))
+ error_at (DECL_SOURCE_LOCATION (x),
+ "field %qD has sizeless type", x);
+ else
+ error_at (DECL_SOURCE_LOCATION (x),
+ "unnamed field has sizeless type");
+ TREE_TYPE (x) = error_mark_node;
+ }
+
if (DECL_NAME (x)
|| RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)))
saw_named_field = true;
@@ -8262,14 +8306,14 @@ finish_struct (location_t loc, tree t, t
}
}
- /* Note: C_TYPE_INCOMPLETE_VARS overloads TYPE_VFIELD which is used
+ /* Note: C_TYPE_INDEFINITE_VARS overloads TYPE_VFIELD which is used
in dwarf2out via rest_of_decl_compilation below and means
something totally different. Since we will be clearing
- C_TYPE_INCOMPLETE_VARS shortly after we iterate through them,
+ C_TYPE_INDEFINITE_VARS shortly after we iterate through them,
clear it ahead of time and avoid problems in dwarf2out. Ideally,
- C_TYPE_INCOMPLETE_VARS should use some language specific
+ C_TYPE_INDEFINITE_VARS should use some language specific
node. */
- tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t));
+ tree indefinite_vars = C_TYPE_INDEFINITE_VARS (TYPE_MAIN_VARIANT (t));
for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
{
TYPE_FIELDS (x) = TYPE_FIELDS (t);
@@ -8277,7 +8321,7 @@ finish_struct (location_t loc, tree t, t
C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t);
C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t);
C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t);
- C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE;
+ C_TYPE_INDEFINITE_VARS (x) = NULL_TREE;
}
/* If this was supposed to be a transparent union, but we can't
@@ -8300,7 +8344,7 @@ finish_struct (location_t loc, tree t, t
/* If this structure or union completes the type of any previous
variable declaration, lay it out and output its rtl. */
- for (x = incomplete_vars; x; x = TREE_CHAIN (x))
+ for (x = indefinite_vars; x; x = TREE_CHAIN (x))
{
tree decl = TREE_VALUE (x);
if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
@@ -8413,7 +8457,7 @@ start_enum (location_t loc, struct c_enu
forward reference. */
if (name != NULL_TREE)
- enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc);
+ enumtype = lookup_tag (ENUMERAL_TYPE, false, name, true, &enumloc);
if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE)
{
@@ -8788,7 +8832,7 @@ start_function (struct c_declspecs *decl
announce_function (decl1);
- if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1))))
+ if (!DEFINITE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1))))
{
error_at (loc, "return type is an incomplete type");
/* Make it return void instead. */
@@ -9141,7 +9185,7 @@ store_parm_decls_oldstyle (tree fndecl,
continue;
if (TREE_TYPE (parm) != error_mark_node
- && !COMPLETE_TYPE_P (TREE_TYPE (parm)))
+ && !DEFINITE_TYPE_P (TREE_TYPE (parm)))
{
error_at (DECL_SOURCE_LOCATION (parm),
"parameter %qD has incomplete type", parm);
===================================================================
@@ -2761,6 +2761,7 @@ c_parser_declspecs (c_parser *parser, st
declspecs_add_type (loc, specs, t);
break;
case RID_STRUCT:
+ case RID_SIZELESS_STRUCT:
case RID_UNION:
if (!typespec_ok)
goto out;
@@ -3023,7 +3024,7 @@ c_parser_enum_specifier (c_parser *parse
ret.expr_const_operands = true;
return ret;
}
- ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident);
+ ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, false, ident);
/* In ISO C, enumerated types can be referred to only if already
defined. */
if (pedantic && !COMPLETE_TYPE_P (ret.spec))
@@ -3083,8 +3084,12 @@ c_parser_struct_or_union_specifier (c_pa
location_t struct_loc;
location_t ident_loc = UNKNOWN_LOCATION;
enum tree_code code;
+ bool sizeless_p = false;
switch (c_parser_peek_token (parser)->keyword)
{
+ case RID_SIZELESS_STRUCT:
+ sizeless_p = true;
+ /* Fall through. */
case RID_STRUCT:
code = RECORD_TYPE;
break;
@@ -3113,7 +3118,8 @@ c_parser_struct_or_union_specifier (c_pa
/* Parse a struct or union definition. Start the scope of the
tag before parsing components. */
struct c_struct_parse_info *struct_info;
- tree type = start_struct (struct_loc, code, ident, &struct_info);
+ tree type = start_struct (struct_loc, code, sizeless_p, ident,
+ &struct_info);
tree postfix_attrs;
/* We chain the components in reverse order, then put them in
forward order at the end. Each struct-declaration may
@@ -3230,7 +3236,7 @@ c_parser_struct_or_union_specifier (c_pa
ret.expr_const_operands = true;
return ret;
}
- ret = parser_xref_tag (ident_loc, code, ident);
+ ret = parser_xref_tag (ident_loc, code, sizeless_p, ident);
return ret;
}
@@ -7615,7 +7621,7 @@ c_parser_generic_selection (c_parser *pa
if (TREE_CODE (assoc.type) == FUNCTION_TYPE)
error_at (assoc.type_location,
"%<_Generic%> association has function type");
- else if (!COMPLETE_TYPE_P (assoc.type))
+ else if (!DEFINITE_TYPE_P (assoc.type))
error_at (assoc.type_location,
"%<_Generic%> association has incomplete type");
@@ -10536,6 +10542,10 @@ c_parser_objc_selector (c_parser *parser
{
case RID_ENUM:
case RID_STRUCT:
+#if 0
+ /* Deliberately excluded from ObjC support. */
+ case RID_SIZELESS_STRUCT:
+#endif
case RID_UNION:
case RID_IF:
case RID_ELSE:
@@ -18277,6 +18287,8 @@ c_parser_omp_threadprivate (c_parser *pa
error_at (loc, "automatic variable %qE cannot be %<threadprivate%>", v);
else if (TREE_TYPE (v) == error_mark_node)
;
+ /* For now we continue to require sized types here, so test
+ COMPLETE_TYPE_P rather than DEFINITE_TYPE_P. */
else if (! COMPLETE_TYPE_P (TREE_TYPE (v)))
error_at (loc, "%<threadprivate%> %qE has incomplete type", v);
else
===================================================================
@@ -189,10 +189,11 @@ static void free_all_tagged_tu_seen_up_t
/* Do `exp = require_complete_type (loc, exp);' to make sure exp
does not have an incomplete type. (That includes void types.)
- LOC is the location of the use. */
+ LOC is the location of the use. ALLOW_SIZELESS_P is true if
+ fully-defined sizeless types are OK. */
tree
-require_complete_type (location_t loc, tree value)
+require_complete_type (location_t loc, tree value, bool allow_sizeless_p)
{
tree type = TREE_TYPE (value);
@@ -200,7 +201,7 @@ require_complete_type (location_t loc, t
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;
c_incomplete_type_error (loc, value, type);
@@ -2176,7 +2177,7 @@ default_conversion (tree exp)
return error_mark_node;
}
- exp = require_complete_type (EXPR_LOC_OR_LOC (exp, input_location), exp);
+ exp = require_definite_type (EXPR_LOC_OR_LOC (exp, input_location), exp);
if (exp == error_mark_node)
return error_mark_node;
@@ -2398,7 +2399,7 @@ build_component_ref (location_t loc, tre
if (code == RECORD_TYPE || code == UNION_TYPE)
{
- if (!COMPLETE_TYPE_P (type))
+ if (!DEFINITE_TYPE_P (type))
{
c_incomplete_type_error (loc, NULL_TREE, type);
return error_mark_node;
@@ -2548,7 +2549,7 @@ build_indirect_ref (location_t loc, tree
ref = build1 (INDIRECT_REF, t, pointer);
- if (!COMPLETE_OR_VOID_TYPE_P (t) && TREE_CODE (t) != ARRAY_TYPE)
+ if (!DEFINITE_OR_VOID_TYPE_P (t) && TREE_CODE (t) != ARRAY_TYPE)
{
if (!C_TYPE_ERROR_REPORTED (TREE_TYPE (ptr)))
{
@@ -3156,7 +3157,7 @@ build_function_call_vec (location_t loc,
"function with qualified void return type called");
return result;
}
- return require_complete_type (loc, result);
+ return require_definite_type (loc, result);
}
/* Like build_function_call_vec, but call also resolve_overloaded_builtin. */
@@ -3312,7 +3313,7 @@ convert_arguments (location_t loc, vec<l
val = c_fully_fold (val, false, NULL);
STRIP_TYPE_NOPS (val);
- val = require_complete_type (ploc, val);
+ val = require_definite_type (ploc, val);
/* Some floating-point arguments must be promoted to double when
no type is specified by a prototype. This applies to
@@ -3342,7 +3343,7 @@ convert_arguments (location_t loc, vec<l
{
/* Formal parm type is specified by a function prototype. */
- if (type == error_mark_node || !COMPLETE_TYPE_P (type))
+ if (type == error_mark_node || !DEFINITE_TYPE_P (type))
{
error_at (ploc, "type of formal parameter %d is incomplete",
parmnum + 1);
@@ -4230,7 +4231,7 @@ build_unary_op (location_t location, enu
arg = remove_c_maybe_const_expr (arg);
if (code != ADDR_EXPR)
- arg = require_complete_type (location, arg);
+ arg = require_definite_type (location, arg);
typecode = TREE_CODE (TREE_TYPE (arg));
if (typecode == ERROR_MARK)
@@ -5596,7 +5597,7 @@ build_c_cast (location_t loc, tree type,
if (!VOID_TYPE_P (type))
{
- value = require_complete_type (loc, value);
+ value = require_definite_type (loc, value);
if (value == error_mark_node)
return error_mark_node;
}
@@ -5876,7 +5877,7 @@ build_modify_expr (location_t location,
bool is_atomic_op;
/* Types that aren't fully specified cannot be used in assignments. */
- lhs = require_complete_type (location, lhs);
+ lhs = require_definite_type (location, lhs);
/* Avoid duplicate error messages from operands that had errors. */
if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
@@ -6553,7 +6554,7 @@ #define WARNING_FOR_QUALIFIERS(LOCATION,
error_at (location, "void value not ignored as it ought to be");
return error_mark_node;
}
- rhs = require_complete_type (location, rhs);
+ rhs = require_definite_type (location, rhs);
if (rhs == error_mark_node)
return error_mark_node;
@@ -10785,7 +10786,7 @@ c_process_expr_stmt (location_t loc, tre
verify_sequence_points (expr);
if (TREE_TYPE (expr) != error_mark_node
- && !COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (expr))
+ && !DEFINITE_OR_VOID_TYPE_P (TREE_TYPE (expr))
&& TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
error_at (loc, "expression statement has incomplete type");
@@ -14367,7 +14368,7 @@ c_build_qualified_type (tree type, int t
type main variant. */
if (RECORD_OR_UNION_TYPE_P (var_type)
&& TYPE_MAIN_VARIANT (var_type) != var_type)
- C_TYPE_INCOMPLETE_VARS (var_type) = 0;
+ C_TYPE_INDEFINITE_VARS (var_type) = 0;
return var_type;
}
@@ -14386,7 +14387,7 @@ c_build_va_arg (location_t loc1, tree ex
error_at (loc1, "cannot use %<va_arg%> with reverse storage order");
return error_mark_node;
}
- else if (!COMPLETE_TYPE_P (type))
+ else if (!DEFINITE_TYPE_P (type))
{
error_at (loc2, "second argument to %<va_arg%> is of incomplete "
"type %qT", type);
===================================================================
@@ -69,7 +69,8 @@ objc_start_struct (tree name)
{
gcc_assert (!objc_building_struct);
objc_building_struct = true;
- return start_struct (input_location, RECORD_TYPE, name, &objc_struct_info);
+ return start_struct (input_location, RECORD_TYPE, false, name,
+ &objc_struct_info);
}
/* Finish building a struct for objc. */
===================================================================
@@ -37,7 +37,7 @@ extern tree objcp_end_compound_stmt (tre
invoke the original C++ functions if needed). */
#ifdef OBJCP_REMAP_FUNCTIONS
-#define start_struct(loc, code, name, struct_info) \
+#define start_struct(loc, code, sizeless_p, name, struct_info) \
objcp_start_struct (loc, code, name)
#define finish_struct(loc, t, fieldlist, attributes, struct_info) \
objcp_finish_struct (loc, t, fieldlist, attributes)
===================================================================
@@ -0,0 +1,269 @@
+/* { dg-options "-std=gnu99" } */
+
+struct initially_struct;
+__sizeless_struct initially_struct; /* { dg-error {'initially_struct' defined as wrong kind of tag} } */
+
+union initially_union;
+__sizeless_struct initially_union; /* { dg-error {'initially_union' defined as wrong kind of tag} } */
+
+enum initially_enum { AN_ENUM_VALUE };
+__sizeless_struct initially_enum; /* { dg-error {'initially_enum' defined as wrong kind of tag} } */
+
+__sizeless_struct initially_sizeless;
+struct initially_sizeless; /* { dg-error {'initially_sizeless' defined as wrong kind of tag} } */
+union initially_sizeless; /* { dg-error {'initially_sizeless' defined as wrong kind of tag} } */
+enum initially_sizeless { ANOTHER_ENUM_VALUE }; /* { dg-error {'initially_sizeless' defined as wrong kind of tag} } */
+
+typedef __sizeless_struct { int a; } ta;
+typedef __sizeless_struct { int a; } tb;
+typedef __sizeless_struct { int a, b; } tc;
+
+typedef __sizeless_struct ta_wrapper { ta a1, a2; } ta_wrapper;
+
+__sizeless_struct struct_in_sizeless {
+ struct { ta a; }; /* { dg-error {field 'a' has sizeless type} } */
+ struct { int b; };
+};
+__sizeless_struct union_in_sizeless {
+ union { ta a; }; /* { dg-error {field 'a' has sizeless type} } */
+ union { int b; };
+};
+__sizeless_struct sizeless_in_sizeless {
+ __sizeless_struct { ta a; };
+};
+
+__sizeless_struct flexible_in_sizeless {
+ int i;
+ int x[]; /* { dg-error {flexible array member in sizeless struct} } */
+};
+
+struct sizeless_in_struct {
+ __sizeless_struct { ta a; }; /* { dg-error {unnamed field has sizeless type} } */
+ __sizeless_struct { int b; }; /* { dg-error {unnamed field has sizeless type} } */
+};
+union sizeless_in_union {
+ __sizeless_struct { ta a; }; /* { dg-error {unnamed field has sizeless type} } */
+ __sizeless_struct { int b; }; /* { dg-error {unnamed field has sizeless type} } */
+};
+
+/* Sizeless objects with global scope. */
+
+ta global_ta; /* { dg-error {sizeless variable 'global_ta' cannot have static storage duration} } */
+static ta local_ta; /* { dg-error {sizeless variable 'local_ta' cannot have static storage duration} } */
+extern ta extern_ta; /* { dg-error {sizeless variable 'extern_ta' cannot have static storage duration} } */
+__thread ta tls_ta; /* { dg-error {sizeless variable 'tls_ta' cannot have thread-local storage duration} } */
+_Atomic ta atomic_ta; /* { dg-error {sizeless variable 'atomic_ta' cannot have static storage duration} } */
+
+/* Sizeless arrays. */
+
+typedef ta array_type[2]; /* { dg-error {array type has incomplete element type 'ta'} } */
+extern ta extern_array[]; /* { dg-error {array type has incomplete element type 'ta'} } */
+
+/* Sizeless fields. */
+
+struct struct1 {
+ ta a; /* { dg-error {field 'a' has sizeless type} } */
+};
+
+union union1 {
+ ta a; /* { dg-error {field 'a' has sizeless type} } */
+};
+
+/* Pointers to sizeless types. */
+
+ta *global_ta_ptr;
+
+/* Sizeless arguments and return values. */
+
+void ext_consume_ta (ta);
+void ext_consume_varargs (int, ...);
+ta ext_produce_ta ();
+
+/* Main tests for statements and expressions. */
+
+void
+statements (int n)
+{
+ /* Local declarations. */
+
+ ta ta1, ta2;
+ tb tb1;
+ tc tc1;
+ static ta local_static_ta; /* { dg-error {sizeless variable 'local_static_ta' cannot have static storage duration} } */
+ extern ta another_extern_ta; /* { dg-error {sizeless variable 'another_extern_ta' cannot have static storage duration} } */
+
+ /* 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|__alignof__)' to incomplete type} } */
+ _Alignof (ta1); /* { dg-error {invalid application of '(_Alignof|__alignof__)' to incomplete type} } */
+ _Alignof (ext_produce_ta ()); /* { dg-error {invalid application of '(_Alignof|__alignof__)' to incomplete type} } */
+
+ /* Initialization. */
+
+ ta init_ta1 = ta1;
+ ta init_ta2 = tb1; /* { dg-error {invalid initializer} } */
+ ta init_ta3 = {};
+ ta init_ta4 = { 1 };
+ ta init_ta5 = { n };
+ ta init_ta6 = { n, n }; /* { dg-warning {excess elements in struct initializer} } */
+
+ int initi_a = ta1; /* { dg-error {incompatible types when initializing type 'int' using type 'ta'} } */
+ int initi_b = { ta1 }; /* { dg-error {incompatible types when initializing type 'int' using type 'ta'} } */
+
+ ta_wrapper init_wrapper1 = {};
+ ta_wrapper init_wrapper2 = { ta1 };
+ ta_wrapper init_wrapper3 = { ta1, ta1 };
+ ta_wrapper init_wrapper4 = { ta1, ta1, ta1 }; /* { dg-warning {excess elements in struct initializer} } */
+
+ /* Compound literals. */
+
+ (ta) {};
+ (ta) { ta1 }; /* { dg-error {incompatible types when initializing type 'int' using type 'ta'} } */
+ (ta) { 1 };
+ (ta) { 1, 2 }; /* { dg-warning {excess elements in struct initializer} } */
+ (tc) { 1, 2 };
+ (tc) { 1, 2, 3 }; /* { dg-warning {excess elements in struct initializer} } */
+
+ (int) { ta1 }; /* { dg-error {incompatible types when initializing type 'int' using type 'ta'} } */
+
+ /* Arrays. */
+
+ ta array[2]; /* { dg-error {array type has incomplete element type 'ta'} } */
+ ta zero_length_array[0]; /* { dg-error {array type has incomplete element type 'ta'} } */
+ ta empty_init_array[] = {}; /* { dg-error {array type has incomplete element type 'ta'} } */
+ /* { dg-error {empty scalar initializer} "" { target *-*-* } .-1 } */
+ typedef ta vla_type[n]; /* { dg-error {array type has incomplete element type 'ta'} } */
+
+ /* Assignment. */
+
+ n = ta1; /* { dg-error {incompatible types when assigning to type 'int' from type 'ta'} } */
+
+ ta1 = 0; /* { dg-error {incompatible types when assigning to type 'ta'[^\n]* from type 'int'} } */
+ ta1 = ta2;
+ ta1 = tb1; /* { dg-error {incompatible types when assigning to type 'ta'[^\n]* from type 'tb'} } */
+
+ /* Casting. */
+
+ (void) ta1;
+ (ta) ta1;
+ (tb) ta1; /* { dg-error {conversion to non-scalar type requested} } */
+
+ /* Addressing and dereferencing. */
+
+ ta *ta_ptr = &ta1;
+ tb *tb_ptr = &ta1; /* { dg-warning {initialization of 'tb \*'[^\n]* from incompatible pointer} } */
+ ta1 = *ta_ptr;
+ ta1 = *tb_ptr; /* { dg-error {incompatible types when assigning to type 'ta'[^\n]* from type 'tb'} } */
+
+ /* Pointer arithmetic. */
+
+ ++ta_ptr; /* { dg-error {increment of pointer to an incomplete type 'ta'} } */
+ --ta_ptr; /* { dg-error {decrement of pointer to an incomplete type 'ta'} } */
+ ta_ptr++; /* { dg-error {increment of pointer to an incomplete type 'ta'} } */
+ ta_ptr--; /* { dg-error {decrement of pointer to an incomplete type 'ta'} } */
+ ta_ptr += 0; /* { dg-error {invalid use of incomplete typedef 'ta'} } */
+ ta_ptr += 1; /* { dg-error {invalid use of incomplete typedef 'ta'} } */
+ ta_ptr -= 0; /* { dg-error {invalid use of incomplete typedef 'ta'} } */
+ ta_ptr -= 1; /* { dg-error {invalid use of incomplete typedef 'ta'} } */
+ ta_ptr - ta_ptr; /* { dg-error {arithmetic on pointer to an incomplete type} } */
+ ta1 = ta_ptr[0]; /* { dg-error {invalid use of incomplete typedef 'ta'} } */
+ ta1 = ta_ptr[1]; /* { dg-error {invalid use of incomplete typedef 'ta'} } */
+
+ /* Component accesses. */
+
+ tc1.a = 1;
+ tc1.b = 1;
+ tc1.c = 1; /* { dg-error {'tc'[^\n]* has no member named 'c'} } */
+ ta_ptr->a = 1;
+ ta_ptr->b = 1; /* { dg-error {'ta'[^\n]* has no member named 'b'} } */
+ int *int_ptr1 = &tc1.a;
+ int *int_ptr2 = &tc1.b;
+ int *int_ptr3 = &ta_ptr->a;
+
+ /* Unary operators. */
+
+ +ta1; /* { dg-error {wrong type argument to unary plus} } */
+ -ta1; /* { dg-error {wrong type argument to unary minus} } */
+ ~ta1; /* { dg-error {wrong type argument to bit-complement} } */
+ !ta1; /* { dg-error {wrong type argument to unary exclamation mark} } */
+ *ta1; /* { dg-error {invalid type argument of unary '\*'} } */
+ __real ta1; /* { dg-error {wrong type argument to __real} } */
+ __imag ta1; /* { dg-error {wrong type argument to __imag} } */
+ ++ta1; /* { dg-error {wrong type argument to increment} } */
+ --ta1; /* { dg-error {wrong type argument to decrement} } */
+ ta1++; /* { dg-error {wrong type argument to increment} } */
+ ta1--; /* { dg-error {wrong type argument to decrement} } */
+
+ /* Conditional expressions. */
+
+ ta1 ? 0 : 0; /* { dg-error {used struct type value where scalar is required} } */
+ 0 ? ta1 : ta1;
+ 0 ? ta1 : tb1; /* { dg-error {type mismatch in conditional expression} } */
+ 0 ? ta1 : 0; /* { dg-error {type mismatch in conditional expression} } */
+ 0 ? 0 : ta1; /* { dg-error {type mismatch in conditional expression} } */
+ 0 ?: ta1; /* { dg-error {type mismatch in conditional expression} } */
+
+ /* Generic associations. */
+
+ _Generic (ta1, default: 100);
+ _Generic (1, ta: 10, default: 20);
+
+ /* Function arguments. */
+
+ ext_consume_ta (ta1);
+ ext_consume_ta (tb1); /* { dg-error {incompatible type for argument 1 of 'ext_consume_ta'} } */
+ ext_consume_varargs (ta1); /* { dg-error {incompatible type for argument 1 of 'ext_consume_varargs'} } */
+ ext_consume_varargs (1, ta1);
+
+ /* Function returns. */
+
+ ext_produce_ta ();
+ ta1 = ext_produce_ta ();
+ tb1 = ext_produce_ta (); /* { dg-error {incompatible types when assigning to type 'tb'[^\n]* from type 'ta'} } */
+
+ /* Varargs processing. */
+
+ __builtin_va_list valist;
+ __builtin_va_arg (valist, ta);
+
+ /* Statement expressions. */
+
+ ({ ta1; });
+ ({ ta another_ta = *ta_ptr; another_ta; });
+
+ /* Use in atomics. */
+
+ __sync_lock_test_and_set (global_ta_ptr, 0); /* { dg-error {operand type '[^']*'[^\n]* is incompatible with argument 1} } */
+}
+
+/* Function parameters in definitions. */
+
+void
+old_style (input_ta)
+ ta input_ta;
+{
+ ta ta1 = input_ta;
+}
+
+void
+new_style_param (ta input_ta)
+{
+ ta ta1 = input_ta;
+}
+
+/* Function return values in definitions in definitions. */
+
+ta
+good_return_ta (ta param)
+{
+ return param;
+}
+
+ta
+bad_return_ta (tb param)
+{
+ return param; /* { dg-error {incompatible types when returning type 'tb'[^\n]* but 'ta'[^\n]* was expected} } */
+}