Index: testsuite/g++.dg/ext/unary_trait_incomplete.C =================================================================== --- testsuite/g++.dg/ext/unary_trait_incomplete.C (revision 180007) +++ testsuite/g++.dg/ext/unary_trait_incomplete.C (working copy) @@ -1,76 +1,76 @@ // PR c++/39475 -struct I; +struct I; // { dg-error "forward declaration" } struct C { }; bool nas1 = __has_nothrow_assign(I); // { dg-error "incomplete type" } bool nas2 = __has_nothrow_assign(C[]); -bool nas3 = __has_nothrow_assign(I[]); // { dg-error "incomplete type" } +bool nas3 = __has_nothrow_assign(I[]); // { dg-error "unspecified bounds" } bool nas4 = __has_nothrow_assign(void); bool nas5 = __has_nothrow_assign(const void); bool tas1 = __has_trivial_assign(I); // { dg-error "incomplete type" } bool tas2 = __has_trivial_assign(C[]); -bool tas3 = __has_trivial_assign(I[]); // { dg-error "incomplete type" } +bool tas3 = __has_trivial_assign(I[]); // { dg-error "unspecified bounds" } bool tas4 = __has_trivial_assign(void); bool tas5 = __has_trivial_assign(const void); bool nco1 = __has_nothrow_constructor(I); // { dg-error "incomplete type" } bool nco2 = __has_nothrow_constructor(C[]); -bool nco3 = __has_nothrow_constructor(I[]); // { dg-error "incomplete type" } +bool nco3 = __has_nothrow_constructor(I[]); // { dg-error "unspecified bounds" } bool nco4 = __has_nothrow_constructor(void); bool nco5 = __has_nothrow_constructor(const void); bool tco1 = __has_trivial_constructor(I); // { dg-error "incomplete type" } bool tco2 = __has_trivial_constructor(C[]); -bool tco3 = __has_trivial_constructor(I[]); // { dg-error "incomplete type" } +bool tco3 = __has_trivial_constructor(I[]); // { dg-error "unspecified bounds" } bool tco4 = __has_trivial_constructor(void); bool tco5 = __has_trivial_constructor(const void); bool ncp1 = __has_nothrow_copy(I); // { dg-error "incomplete type" } bool ncp2 = __has_nothrow_copy(C[]); -bool ncp3 = __has_nothrow_copy(I[]); // { dg-error "incomplete type" } +bool ncp3 = __has_nothrow_copy(I[]); // { dg-error "unspecified bounds" } bool ncp4 = __has_nothrow_copy(void); bool ncp5 = __has_nothrow_copy(const void); bool tcp1 = __has_trivial_copy(I); // { dg-error "incomplete type" } bool tcp2 = __has_trivial_copy(C[]); -bool tcp3 = __has_trivial_copy(I[]); // { dg-error "incomplete type" } +bool tcp3 = __has_trivial_copy(I[]); // { dg-error "unspecified bounds" } bool tcp4 = __has_trivial_copy(void); bool tcp5 = __has_trivial_copy(const void); bool vde1 = __has_virtual_destructor(I); // { dg-error "incomplete type" } bool vde2 = __has_virtual_destructor(C[]); -bool vde3 = __has_virtual_destructor(I[]); // { dg-error "incomplete type" } +bool vde3 = __has_virtual_destructor(I[]); // { dg-error "unspecified bounds" } bool vde4 = __has_virtual_destructor(void); bool vde5 = __has_virtual_destructor(const void); bool tde1 = __has_trivial_destructor(I); // { dg-error "incomplete type" } bool tde2 = __has_trivial_destructor(C[]); -bool tde3 = __has_trivial_destructor(I[]); // { dg-error "incomplete type" } +bool tde3 = __has_trivial_destructor(I[]); // { dg-error "unspecified bounds" } bool tde4 = __has_trivial_destructor(void); bool tde5 = __has_trivial_destructor(const void); bool abs1 = __is_abstract(I); // { dg-error "incomplete type" } bool abs2 = __is_abstract(C[]); -bool abs3 = __is_abstract(I[]); // { dg-error "incomplete type" } +bool abs3 = __is_abstract(I[]); // { dg-error "unspecified bounds" } bool abs4 = __is_abstract(void); bool abs5 = __is_abstract(const void); bool pod1 = __is_pod(I); // { dg-error "incomplete type" } bool pod2 = __is_pod(C[]); -bool pod3 = __is_pod(I[]); // { dg-error "incomplete type" } +bool pod3 = __is_pod(I[]); // { dg-error "unspecified bounds" } bool pod4 = __is_pod(void); bool pod5 = __is_pod(const void); bool emp1 = __is_empty(I); // { dg-error "incomplete type" } bool emp2 = __is_empty(C[]); -bool emp3 = __is_empty(I[]); // { dg-error "incomplete type" } +bool emp3 = __is_empty(I[]); // { dg-error "unspecified bounds" } bool emp4 = __is_empty(void); bool emp5 = __is_empty(const void); bool pol1 = __is_polymorphic(I); // { dg-error "incomplete type" } bool pol2 = __is_polymorphic(C[]); -bool pol3 = __is_polymorphic(I[]); // { dg-error "incomplete type" } +bool pol3 = __is_polymorphic(I[]); // { dg-error "unspecified bounds" } bool pol4 = __is_polymorphic(void); bool pol5 = __is_polymorphic(const void); Index: testsuite/g++.dg/ext/is_base_of_diagnostic.C =================================================================== --- testsuite/g++.dg/ext/is_base_of_diagnostic.C (revision 180007) +++ testsuite/g++.dg/ext/is_base_of_diagnostic.C (working copy) @@ -1,7 +1,7 @@ class A { }; -class B; +class B; // { dg-error "forward declaration" } union C { }; Index: testsuite/g++.dg/ext/is_base_of_incomplete.C =================================================================== --- testsuite/g++.dg/ext/is_base_of_incomplete.C (revision 0) +++ testsuite/g++.dg/ext/is_base_of_incomplete.C (revision 0) @@ -0,0 +1,7 @@ +template +struct non_instantiable +{ + typedef typename T::THIS_TYPE_CANNOT_BE_INSTANTIATED type; +}; + +int check[__is_base_of(non_instantiable, void) ? -1 : 1]; Index: cp/semantics.c =================================================================== --- cp/semantics.c (revision 180007) +++ cp/semantics.c (working copy) @@ -5210,23 +5210,20 @@ trait_expr_value (cp_trait_kind kind, tree type1, } } -/* Returns true if TYPE is a complete type, an array of unknown bound, - or (possibly cv-qualified) void, returns false otherwise. */ +/* If TYPE is an array of unknown bound, or (possibly cv-qualified) + void, or a complete type, returns it, otherwise NULL_TREE. */ -static bool +static tree check_trait_type (tree type) { - if (COMPLETE_TYPE_P (type)) - return true; - if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type) && COMPLETE_TYPE_P (TREE_TYPE (type))) - return true; + return type; if (VOID_TYPE_P (type)) - return true; + return type; - return false; + return complete_type_or_else (type, NULL_TREE); } /* Process a trait expression. */ @@ -5276,10 +5273,6 @@ finish_trait_expr (cp_trait_kind kind, tree type1, return trait_expr; } - complete_type (type1); - if (type2) - complete_type (type2); - switch (kind) { case CPTK_HAS_NOTHROW_ASSIGN: @@ -5298,20 +5291,15 @@ finish_trait_expr (cp_trait_kind kind, tree type1, case CPTK_IS_STD_LAYOUT: case CPTK_IS_TRIVIAL: if (!check_trait_type (type1)) - { - error ("incomplete type %qT not allowed", type1); - return error_mark_node; - } + return error_mark_node; break; 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_P (type2)) - { - error ("incomplete type %qT not allowed", type2); - return error_mark_node; - } + && !complete_type_or_else (type2, NULL_TREE)) + /* We already issued an error. */ + return error_mark_node; break; case CPTK_IS_CLASS: