diff mbox series

[10/10] C++ support for sizeless types

Message ID 8736t7i8bf.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:38 p.m. UTC
This patch adds support for sizeless types to C++, along the lines
described in the covering RFC.  As with the C patch, it's actually a
squash of a series of patches that I've attached as a tarball, with each
patch building up the support piece-by-piece.  The individual patches
have covering notes giving a quick explanation.

Most of the patch is replacing the test for whether a class has been
fully defined (for COMPLETE_TYPE_P) or whether the definition has
been started (COMPLETE_OR_OPEN_TYPE_P) in cases where member lookup
is all that matters.

The patch adds comments explaining why some tests of COMPLETE_TYPE_P
are either correct as-is or why it doesn't matter whether they're
replaced or not.  These were mostly for keeping track while doing
the work; I don't know whether it would make sense to commit them.

I realise this isn't likely to be acceptable in its current state,
not least because it would create a maintenance burden as the language
evolves.  The question is more: what changes would be needed to
make it acceptable?

One option would be to make COMPLETE_TYPE_P mean "the type is fully
defined" and use something else for "the type is fully defined and
has a defined size, alignment and layout".  The problem is that we'll
then err on the side of accepting things for sizeless types rather than
rejecting them, whereas the idea was to make the handling for complete
types conservatively correct.  In other words, the language meaning of
complete type would still be "has sufficient information to determine
the size" while COMPLETE_TYPE_P would mean something else.

Another option would be to remove COMPLETE_TYPE_P altogether and
use a new macro for "is fully defined and has a measurable size".
E.g. we could have:

    TYPE_DEFINITION_STARTED_P (etc.)
    --> what's now COMPLETE_OR_OPEN_TYPE_P

    TYPE_DEFINED_P (or TYPE_FULLY_DEFINED_P, etc.)
    --> what's now COMPLETE_TYPE_P when the size, alignment and
    layout don't matter

    TYPE_SIZE_KNOWN_P (or TYPE_SIZE_DEFINED_P, TYPE_SIZE_COMPLETE_P, etc.)
    --> what's now COMPLETE_TYPE_P when the size, alignment or
    layout does matter.

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

gcc/c-family/
	* c-common.h (definite_or_array_type_p): New function.

gcc/cp/
	* cp-tree.h (COMPLETE_OR_OPEN_TYPE_P): Replace with...
	(DEFINITE_OR_OPEN_TYPE_P): ...this new macro.
	(sizeless_struct_type): New tag_types enum.
	(require_complete_type_sfinae): Add a default false parameter.
	(complete_type_or_else): Likewise.
	(complete_type_or_maybe_complain): Likewise.
	(require_definite_type_sfinae): New function.
	(definite_type_or_maybe_complain): Likewise.
	(definite_type_or_else): Likewise.
	* call.c (reference_binding): Require definite types rather
	than complete types when processing the target type of a
	reference binding.
	(implicit_conversion): Likewise when processing the target
	type of an implicit conversion.
	(convert_arg_to_ellipsis): Likewise when processing a value
	that is being passed through "...".
	(build_x_va_arg): Likewise when processing the second argument
	to va_arg.
	(maybe_warn_class_memaccess): Likewise when processing a
	member access.
	(build_cxx_call): Likewise when processing the function in
	a function call.
	(build_special_member_call): Likewise when looking up a
	special member.
	(complain_about_no_candidates_for_method_call): Likewise
	when reporting that a type has no suitable member functions.
	(add_builtin_candidate, build_op_delete_call)
	(convert_like_real): Add comments.
	* class.c (build_base_path, check_bases): Likewise.
	(check_field_decls, build_base_field): Likewise.
	(add_method): Require definite types rather than complete types
	when adding a new member to a class.
	(type_has_virtual_destructor): Relax the assert so that it
	accepts sizeless definite types as well as complete types.
	(type_build_dtor_call): Handle destructors in sizeless definite
	types in the same way as destructors in complete classes.
	(finish_struct_1): Report a redeclaration error for classes
	that are already definite as well as already complete.
	Record that sizeless types are not literal types.
	(is_really_empty_class): Use the cached result for definite
	classes as well as complete classes.
	* constexpr.c (literal_type_p): Relax the assert so that it
	accepts sizeless definite types as well as complete types.
	(ensure_literal_type_for_constexpr_object): Check for indefinite
	rather than incomplete types when short-circuiting the test
	for literal types.
	(cxx_eval_constant_expression): Add comments.
	(potential_constant_expression_1): Likewise.
	* cp-gimplify.c (cxx_omp_finish_clause): Likewise.
	(cp_fold): Check for definite rather than complete types when
	handling the offsetof-like idiom.
	* cvt.c (cp_convert_to_pointer): Require definite types rather than
	complete types when processing the source of a pointer conversion.
	(convert_to_void): Check for indefinite types rather than incomplete
	types when issuing the warning abut converting to void.
	(build_expr_type_conversion): Add a comment.
	* decl.c (redeclaration_error_message): Check for definite types
	rather than complete types when deciding whether to issue a
	redeclaration error.
	(make_typename_type): Require definite types rather than complete
	types when resolving a typename.
	(cp_finish_decomp): Likewise when processing the source of a
	structured binding.
	(require_complete_types_for_parms): Likewise when processing
	the types of formal parameters.
	(check_function_type): Likewise when processing the return type
	in a function definition.
	(fixup_anonymous_aggr): Reject anonymous sizeless structures
	in sized aggregates.
	(start_decl): Check for definite types rather than complete types
	when processing a decl that belongs to an already-defined class.
	(start_decl_1): Require initialized and aggregate definitions
	to have definite rather than complete type.  Reject sizeless decls
	with static or thread-local storage duration.
	(layout_var_decl): Check for definite types rather than complete types
	when deciding whether to lay out a decl.
	(check_array_initializer, get_tuple_size): Add comments.
	(check_static_variable_definition, grok_op_properties): Likewise.
	(check_initializer): Require the initialized type to have definite
	rather than complete type.
	(cp_finish_decl): Check for indefinite types rather than incomplete
	types when deciding whether to suppress debug information.
	(grokdeclarator): Likewise when processing qualified function names.
	Reject virtual methods inside a sizeless struct.  Accept sizeless
	definite members in sizeless structs, but not in normal sized
	aggregates.
	(tag_name, xref_tag_1): Handle sizeless_struct_type.
	(xref_basetypes): Reject base classes for sizeless structs.
	(finish_enum_value_list): Check for definite types rather than
	complete types when processing qualified enum names.
	(begin_destructor_body): Likewise when deciding whether to build
	a destructor body.
	(maybe_register_incomplete_var): Likewise when deciding whether
	to queue a variable for later processing.
	* decl2.c (check_classfn): Check for definite types rather than
	complete types when deciding how to report a name lookup failure.
	(cp_omp_mappable_type): Add a comment.
	* error.c (class_key_or_enum_as_string): Return "__sizeless_struct"
	for sizeless structs.
	(qualified_name_lookup_error): Check for definite types rather than
	complete types when deciding how to report a name lookup failure.
	* except.c (complete_ptr_ref_or_void_ptr_p): Add comments.
	* expr.c (cplus_expand_constant): Check for definite types rather than
	complete types when deciding whether to punt on PTRMEM_CSTs.
	* friend.c (do_friend): Require definite types rather than complete
	types when processing the class name in a member friend declaration.
	* init.c (build_value_init_noctor): Likewise when processing
	a vector initializer.
	(build_offset_ref): Likewise when processing the class name
	in a member reference.  Reject attempts to create pointers
	to member variables of sizeless structures.
	(emit_mem_initializers): Check for definite types rather than
	complete types when deciding whether to emit code for initializers.
	(build_new): Add a comment.
	(build_vec_delete_1): Reject attempts to delete sizeless objects.
	(build_delete): Likewise.
	* lambda.c (lambda_function): Check for definite types rather than
	complete types when trying to detect debug_tree calls.
	(lambda_expr_this_capture): Likewise when handling "this" in a NSDMI.
	(add_capture): Tighten assert so that it requires the capture
	to be indefinite as well as incomplete.
	* name-lookup.c (search_anon_aggr): Accept definite types as
	well as complete types.
	(get_class_binding_direct, get_class_binding, find_member_slot)
	(add_member_slot): Extend handling of name lookup and member
	registration for complete types to sizeless types.
	(maybe_process_template_type_declaration, do_pushtag): Check for
	indefinite types rather than incomplete types when deciding
	whether to queue a template instantiation.
	* parser.c (cp_keyword_starts_decl_specifier_p): Handle
	RID_SIZELESS_STRUCT.
	(cp_parser_type_specifier): Likewise.
	(cp_parser_token_is_class_key): Likewise.
	(cp_parser_diagnose_invalid_type_name): Check for definite types
	rather than complete types when deciding how to report a name
	lookup failure.
	(cp_parser_nested_name_specifier_opt): Extend shortcut for
	complete types to definite types.
	(cp_parser_postfix_dot_deref_expression): Require definite types
	rather than complete types when processing "." and "->" expressions.
	(cp_parser_perform_range_for_lookup): Likewise when processing
	range-based for loops.
	(cp_parser_class_head): Check whether the existing type is definite
	rather than complete when deciding whether to issue a redefinition
	error.
	(cp_parser_check_class_key): Extend checks for invalid tags to
	include __sizeless_struct.
	* pt.c (maybe_new_partial_specialization): Check for indefinite types
	rather than incomplete types when deciding whether to exit early.
	(maybe_process_partial_specialization): Likewise when deciding
	whether something is an explicit specialization.
	(process_partial_specialization): Tighten assert so that it requires
	the instantiation to be indefinite as well as incomplete.  Check for
	definite types rather than complete types when checking whether
	earlier uses are ambiguated or invalidated by the specialization.
	(lookup_template_class_1): Copy TYPE_SIZELESS_P to the instantiation.
	(tsubst_friend_function): Require definite types rather than complete
	types when processing the class name in a member friend declaration.
	(tsubst): Likewise when processing the class name in a typename.
	(do_type_instantiation): Likewise for the type of a template
	when processing an instantiation of it.
	(can_complete_type_without_circularity): Check for definite types
	rather than complete types when deciding whether to exit early.
	(instantiate_class_template_1): Likewise, and also when deciding
	whether to defer the instantiation till later.  Allow instantations
	of sizeless structure templates to have sizeless members.
	(instantiate_pending_templates): Check for definite types rather than
	complete types when deciding whether to process or defer a queued
	instantiation.
	* rtti.c (get_tinfo_decl_dynamic, typeid_ok_p, get_typeid)
	(build_dynamic_cast_1, tinfo_base_init): Add comments.
	* search.c (lookup_base): Extend base lookup in complete types to
	definite types.
	* semantics.c (finish_underlying_type, calculate_direct_bases)
	(calculate_bases, finish_offsetof, finish_omp_clauses)
	(finish_omp_threadprivate): Add comments.
	(check_trait_type): Require definite types rather than complete
	types when processing a type trait query.
	(finish_trait_expr): Likewise for the second type in __is_base_of.
	(apply_deduced_return_type): Likewise when processing an auto
	return type.
	* tree.c (build_cplus_new): Likewise when processing a constructor
	call.
	(build_cplus_array_type): Add a comment.
	(strip_typedefs): Check for definite types rather than complete
	types when deciding whether to skip the attribute handling.
	(type_has_nontrivial_copy_init): Accept definite types as
	well as complete types.
	(record_has_unique_obj_representations): Handle poly_int offsets.
	* typeck.c (require_complete_type_sfinae): Add a sizeless_p
	parameter.
	(complete_type_or_maybe_complain): Likewise.
	(complete_type_or_else): Likewise.
	(complete_type): Check for definite types rather than complete
	types when deciding whether to bail out early.
	(cxx_sizeof_or_alignof_type, cxx_sizeof_nowarn): Add comments.
	(cp_build_array_ref, pointer_diff): Likewise.
	(build_reinterpret_cast_1, ptr_reasonably_similar): Likewise.
	(decay_conversion): Require definite types rather than complete
	types when processing the source of the conversion.
	(build_class_member_access_expr): Likewise when processing a
	member access.
	(finish_class_member_access_expr): Likewise.
	(convert_arguments): Likewise when processing the types of
	formal and actual parameters in a function call.
	(cp_build_modify_expr): Likewise when processing the lhs
	of an assignment.
	(convert_for_assignment): Likewise when processing the rhs
	of an assignment.
	(get_member_function_from_ptrfunc): Check for definite types
	rather than complete types when optimizing the handling of
	non-virtual methods.
	(build_x_unary_op): Likewise when deciding whether to circumvent
	the use of operator&.
	(cp_apply_type_quals_to_decl): Likewise when deciding whether
	to remove const qualification.
	* typeck2.c (complete_type_check_abstract): Accept definite types as
	well as complete types.
	(abstract_virtuals_error_sfinae): Check for indefinite types
	rather than incomplete types when deciding whether to postpone
	the check for whether a type has abstract virtual functions.
	(digest_init_r): Require definite types rather than complete
	types when processing the type being initialized.
	(build_functional_cast): Likewise when processing a constructor call.
	(build_m_component_ref, add_exception_specifier): Add a comment.
	(require_complete_eh_spec_types): Likewise.

gcc/testsuite/
	* g++.dg/ext/sizeless-1.C: New test.
	* g++.dg/ext/sizeless-2.C: Likewise.
	* g++.dg/ext/sizeless-3.C: Likewise.
	* g++.dg/ext/sizeless-4.C: Likewise.
	* g++.dg/ext/sizeless-5.C: Likewise.
	* g++.dg/ext/sizeless-6.C: Likewise.
	* g++.dg/ext/sizeless-7.C: Likewise.
diff mbox series

Patch

Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	2018-10-15 14:13:32.988230244 +0100
+++ gcc/c-family/c-common.h	2018-10-15 14:13:37.844189990 +0100
@@ -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.  */
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	2018-10-15 14:08:45.570612130 +0100
+++ gcc/cp/cp-tree.h	2018-10-15 14:13:37.848189957 +0100
@@ -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);
Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c	2018-10-15 14:08:45.570612130 +0100
+++ gcc/cp/call.c	2018-10-15 14:13:37.844189990 +0100
@@ -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%>",
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	2018-10-05 13:46:09.839798545 +0100
+++ gcc/cp/class.c	2018-10-15 14:13:37.848189957 +0100
@@ -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;
Index: gcc/cp/constexpr.c
===================================================================
--- gcc/cp/constexpr.c	2018-10-15 14:08:45.562612196 +0100
+++ gcc/cp/constexpr.c	2018-10-15 14:13:37.848189957 +0100
@@ -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))
Index: gcc/cp/cp-gimplify.c
===================================================================
--- gcc/cp/cp-gimplify.c	2018-08-28 11:25:45.742884177 +0100
+++ gcc/cp/cp-gimplify.c	2018-10-15 14:13:37.848189957 +0100
@@ -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);
Index: gcc/cp/cvt.c
===================================================================
--- gcc/cp/cvt.c	2018-08-21 14:47:07.531170069 +0100
+++ gcc/cp/cvt.c	2018-10-15 14:13:37.848189957 +0100
@@ -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))
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	2018-10-15 14:08:45.558612230 +0100
+++ gcc/cp/decl.c	2018-10-15 14:13:37.852189924 +0100
@@ -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)))
Index: gcc/cp/decl2.c
===================================================================
--- gcc/cp/decl2.c	2018-08-21 14:47:07.527170104 +0100
+++ gcc/cp/decl2.c	2018-10-15 14:13:37.852189924 +0100
@@ -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.  */
Index: gcc/cp/error.c
===================================================================
--- gcc/cp/error.c	2018-10-05 13:46:09.839798545 +0100
+++ gcc/cp/error.c	2018-10-15 14:13:37.852189924 +0100
@@ -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)
Index: gcc/cp/except.c
===================================================================
--- gcc/cp/except.c	2018-09-25 08:03:44.163263685 +0100
+++ gcc/cp/except.c	2018-10-15 14:13:37.852189924 +0100
@@ -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;
     }
Index: gcc/cp/expr.c
===================================================================
--- gcc/cp/expr.c	2018-06-27 10:27:09.702651350 +0100
+++ gcc/cp/expr.c	2018-10-15 14:13:37.852189924 +0100
@@ -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)
Index: gcc/cp/friend.c
===================================================================
--- gcc/cp/friend.c	2018-08-21 14:47:07.543169969 +0100
+++ gcc/cp/friend.c	2018-10-15 14:13:37.852189924 +0100
@@ -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
Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c	2018-08-21 14:47:07.515170204 +0100
+++ gcc/cp/init.c	2018-10-15 14:13:37.852189924 +0100
@@ -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)
 		{
Index: gcc/cp/lambda.c
===================================================================
--- gcc/cp/lambda.c	2018-09-10 17:38:19.394814760 +0100
+++ gcc/cp/lambda.c	2018-10-15 14:13:37.852189924 +0100
@@ -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;
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c	2018-10-05 13:46:09.843798513 +0100
+++ gcc/cp/name-lookup.c	2018-10-15 14:13:37.856189890 +0100
@@ -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);
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	2018-10-15 14:08:45.566612164 +0100
+++ gcc/cp/parser.c	2018-10-15 14:13:37.860189857 +0100
@@ -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);
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	2018-10-15 14:08:45.566612164 +0100
+++ gcc/cp/pt.c	2018-10-15 14:13:37.860189857 +0100
@@ -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
 	    {
Index: gcc/cp/rtti.c
===================================================================
--- gcc/cp/rtti.c	2018-10-15 14:08:45.562612196 +0100
+++ gcc/cp/rtti.c	2018-10-15 14:13:37.860189857 +0100
@@ -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
Index: gcc/cp/search.c
===================================================================
--- gcc/cp/search.c	2018-08-21 14:47:07.543169969 +0100
+++ gcc/cp/search.c	2018-10-15 14:13:37.864189824 +0100
@@ -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)))
 	  {
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	2018-10-05 13:46:09.839798545 +0100
+++ gcc/cp/semantics.c	2018-10-15 14:13:37.864189824 +0100
@@ -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.
Index: gcc/cp/tree.c
===================================================================
--- gcc/cp/tree.c	2018-10-05 13:46:09.839798545 +0100
+++ gcc/cp/tree.c	2018-10-15 14:13:37.864189824 +0100
@@ -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;
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	2018-10-15 14:08:45.558612230 +0100
+++ gcc/cp/typeck.c	2018-10-15 14:13:37.864189824 +0100
@@ -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);
Index: gcc/cp/typeck2.c
===================================================================
--- gcc/cp/typeck2.c	2018-09-25 08:03:44.163263685 +0100
+++ gcc/cp/typeck2.c	2018-10-15 14:13:37.864189824 +0100
@@ -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)
Index: gcc/testsuite/g++.dg/ext/sizeless-1.C
===================================================================
--- /dev/null	2018-09-14 11:16:31.122530289 +0100
+++ gcc/testsuite/g++.dg/ext/sizeless-1.C	2018-10-15 14:13:37.864189824 +0100
@@ -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 ());
+}
Index: gcc/testsuite/g++.dg/ext/sizeless-2.C
===================================================================
--- /dev/null	2018-09-14 11:16:31.122530289 +0100
+++ gcc/testsuite/g++.dg/ext/sizeless-2.C	2018-10-15 14:13:37.868189791 +0100
@@ -0,0 +1,2 @@ 
+__sizeless_struct s {};
+const int foo = __is_literal_type (s);
Index: gcc/testsuite/g++.dg/ext/sizeless-3.C
===================================================================
--- /dev/null	2018-09-14 11:16:31.122530289 +0100
+++ gcc/testsuite/g++.dg/ext/sizeless-3.C	2018-10-15 14:13:37.868189791 +0100
@@ -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;
+}
Index: gcc/testsuite/g++.dg/ext/sizeless-4.C
===================================================================
--- /dev/null	2018-09-14 11:16:31.122530289 +0100
+++ gcc/testsuite/g++.dg/ext/sizeless-4.C	2018-10-15 14:13:37.868189791 +0100
@@ -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;
+}
Index: gcc/testsuite/g++.dg/ext/sizeless-5.C
===================================================================
--- /dev/null	2018-09-14 11:16:31.122530289 +0100
+++ gcc/testsuite/g++.dg/ext/sizeless-5.C	2018-10-15 14:13:37.868189791 +0100
@@ -0,0 +1,12 @@ 
+// { dg-do run }
+
+struct t {
+  ~t () { __builtin_exit (0); }
+};
+
+__sizeless_struct s {
+  ~s () {}
+  t t1;
+};
+
+int main () { s (); __builtin_abort (); }
Index: gcc/testsuite/g++.dg/ext/sizeless-6.C
===================================================================
--- /dev/null	2018-09-14 11:16:31.122530289 +0100
+++ gcc/testsuite/g++.dg/ext/sizeless-6.C	2018-10-15 14:13:37.868189791 +0100
@@ -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" } }
Index: gcc/testsuite/g++.dg/ext/sizeless-7.C
===================================================================
--- /dev/null	2018-09-14 11:16:31.122530289 +0100
+++ gcc/testsuite/g++.dg/ext/sizeless-7.C	2018-10-15 14:13:37.868189791 +0100
@@ -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;
+}