diff mbox series

[09/10] C support for sizeless types

Message ID 877eiji8d0.fsf@arm.com
State New
Headers show
Series Splitting the C and C++ concept of "complete type" | expand

Commit Message

Richard Sandiford Oct. 15, 2018, 2:37 p.m. UTC
This patch adds support for sizeless types to C, along the lines
described in the covering RFC.  The patch is actually a squash
of 26 patches that I've attached as a tarball, with each patch
building up the support piece-by-piece.  The individual patches
say which part of the standard they relate to and add associated
tests to gcc.dg/sizeless-1.c.

2018-10-15  Richard Sandiford  <richard.sandiford@arm.com>

gcc/c-family/
	* c-common.h (RID_SIZELESS_STRUCT): New rid enum.
	(DEFINITE_OR_VOID_TYPE_P): New macro.
	(DEFINITE_OR_UNBOUND_ARRAY_TYPE_P): Likewise.
	* c-common.c (c_common_reswords): Add __sizeless_struct.
	(complete_size_in_bytes): New function.
	(pointer_int_sum): Use it instead of size_in_bytes_loc.
	(c_alignof_expr): Pass sizeless types directly to c_alignof.

gcc/c/
	* c-tree.h (C_TYPE_INCOMPLETE_VARS): Rename to...
	(C_TYPE_INDEFINITE_VARS): ...this.
	(start_struct, parser_xref_tag): Add a bool parameter.
	(require_complete_type): Add a default false parameter.
	(require_definite_type): New function.
	* c-decl.c (pushdecl): Use DEFINITE_TYPE_P instead of
	COMPLETE_TYPE_P.  Update after above name change.
	(lookup_tag): Add a sizeless_p parameter.  Check that it
	matches the TYPE_SIZELESS_P field of any existing type with
	the same name.
	(shadow_tag_warned): Update call accordingly.
	(start_decl): Require variables to have definite rather than
	complete type.  Don't reject initializers for variable-sized
	objects with sizeless type.
	(finish_decl): Reject sizeless objects with static or
	thread-local storage duration.
	(build_compound_literal): Require compound literals to have
	definite rather than complete type.
	(grokdeclarator): Likewise fields.
	(grokparms): Likewise function parameters.
	(parser_xref_tag): Add a sizeless_p parameter.  Update call to
	lookup_tag.  Initialize TYPE_SIZELESS_P when creating a new type.
	(start_struct): Likewise.
	(xref_tag): Update call to parser_xref_tag.
	(finish_struct): Reject flexible array members in sizeless
	structures.  Reject sizeless fields in sized aggregates.
	Update after above name change.
	(start_enum): Update call to lookup_tag.
	(start_function): Require the return type to be definite rather
	than complete.
	(store_parm_decls_oldstyle): Likewise function parameters.
	* c-parser.c (c_parser_declspecs): Handle RID_SIZELESS_STRUCT.
	(c_parser_struct_or_union_specifier): Likewise.  Update calls
	to start_struct and parser_xref_tag.
	(c_parser_enum_specifier): Update call to parser_xref_tag.
	(c_parser_generic_selection): Require the type in a _Generic
	association to be definite rather than complete.
	(c_parser_objc_selector): Handle RID_SIZELESS_STRUCT (but
	commented out).
	(c_parser_omp_threadprivate): Add a comment.
	* c-typeck.c (require_complete_type): Add an allow_sizeless_p
	parameter.
	(default_conversion): Require the type to be definite rather than
	complete when processing the expression being converted.
	(build_component_ref): Likewise when processing member accesses.
	(build_indirect_ref): Likewise when processing pointer dereferences.
	(build_function_call_vec): Likewise when processing the return
	type of a function call.
	(convert_arguments): Likewise when processing the types of the
	formal and actual parameters.
	(build_unary_op): Likewise when processing the operand of a
	unary operation.
	(build_c_cast): Likewise when processing the value being cast.
	(build_modify_expr): Likewise when processing the lhs of an
	assignment.
	(convert_for_assignment): Likewise when processing the rhs
	of an assignment.
	(c_process_expr_stmt): Likewise when processing the type of
	a statement expression.
	(c_build_va_arg): Likewise when processing the second argument
	of a va_arg call.
	(c_build_qualified_type): Update after above name change.

gcc/objc/
	* objc-runtime-shared-support.c (objc_start_struct): Update call
	to start_struct.

gcc/objcp/
	* objcp-decl.h (start_struct): Add a sizeless_p parameter.

gcc/testsuite/
	* gcc.dg/sizeless-1.c: New test.
diff mbox series

Patch

Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	2018-10-15 14:13:28.592266684 +0100
+++ gcc/c-family/c-common.h	2018-10-15 14:13:32.988230244 +0100
@@ -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.  */
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	2018-10-15 14:08:44.946617301 +0100
+++ gcc/c-family/c-common.c	2018-10-15 14:13:32.988230244 +0100
@@ -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));
 
Index: gcc/c/c-tree.h
===================================================================
--- gcc/c/c-tree.h	2018-08-28 11:25:45.530886001 +0100
+++ gcc/c/c-tree.h	2018-10-15 14:13:32.996230178 +0100
@@ -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);
Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	2018-10-05 13:46:08.319810858 +0100
+++ gcc/c/c-decl.c	2018-10-15 14:13:32.992230210 +0100
@@ -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);
Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	2018-10-05 13:46:08.319810858 +0100
+++ gcc/c/c-parser.c	2018-10-15 14:13:32.996230178 +0100
@@ -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
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	2018-10-05 13:46:08.319810858 +0100
+++ gcc/c/c-typeck.c	2018-10-15 14:13:32.996230178 +0100
@@ -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);
Index: gcc/objc/objc-runtime-shared-support.c
===================================================================
--- gcc/objc/objc-runtime-shared-support.c	2018-05-02 08:37:33.373752352 +0100
+++ gcc/objc/objc-runtime-shared-support.c	2018-10-15 14:13:32.996230178 +0100
@@ -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.  */
Index: gcc/objcp/objcp-decl.h
===================================================================
--- gcc/objcp/objcp-decl.h	2018-05-02 08:37:54.209555320 +0100
+++ gcc/objcp/objcp-decl.h	2018-10-15 14:13:32.996230178 +0100
@@ -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)
Index: gcc/testsuite/gcc.dg/sizeless-1.c
===================================================================
--- /dev/null	2018-09-14 11:16:31.122530289 +0100
+++ gcc/testsuite/gcc.dg/sizeless-1.c	2018-10-15 14:13:32.996230178 +0100
@@ -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} } */
+}