From: Patrick Palka Date: Tue, 16 Jun 2020 12:21:33 +0000 (-0400) Subject: c++: Improve access checking inside templates [PR41437] X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=92bed036098928cd4659c8990e14cf7ad040e0c2;p=gcc.git c++: Improve access checking inside templates [PR41437] This patch generalizes our existing functionality for deferring access checking of typedefs when parsing a function or class template to now defer all kinds of access checks until template instantiation time, including member function and member object accesses. Since all access checks eventually go through enforce_access, the main component of this patch is new handling inside enforce_access to defer the current access check if we're inside a template. The bulk of the rest of the patch consists of removing now-unneeded code pertaining to suppressing access checks inside templates or pertaining to typedef-specific access handling. Renamings and other changes with no functional impact have been split off into the followup patch. gcc/cp/ChangeLog: PR c++/41437 PR c++/47346 * call.c (enforce_access): Move to semantics.c. * cp-tree.h (enforce_access): Delete. (get_types_needing_access_check): Delete. (add_typedef_to_current_template_for_access_check): Delete. * decl.c (make_typename_type): Adjust accordingly. Use check_accessibility_of_qualified_id instead of directly using perform_or_defer_access_check. * parser.c (cp_parser_template_declaration_after_parameters): Don't push a dk_no_check access state when parsing a template. * pt.c (get_types_needing_access_check): Delete. (append_type_to_template_for_access_check_1): Delete. (perform_typedefs_access_check): Adjust. If type_decl is a FIELD_DECL, also check its DECL_CONTEXT for dependence. Use tsubst_copy instead of tsubst to substitute into type_decl so that we substitute into the DECL_CONTEXT of a FIELD_DECL. (append_type_to_template_for_access_check): Delete. * search.c (accessible_p): Remove the processing_template_decl early exit. * semantics.c (enforce_access): Moved from call.c. If we're parsing a template and the access check failed, add the check to TI_TYPEDEFS_NEEDING_ACCESS_CHECKING. (perform_or_defer_access_check): Adjust comment. (add_typedef_to_current_template_for_access_check): Delete. (check_accessibility_of_qualified_id): Adjust accordingly. Exit early if the scope is dependent. gcc/testsuite/ChangeLog: PR c++/41437 PR c++/47346 * g++.dg/cpp2a/concepts-using2.C: Adjust. * g++.dg/lto/20081219_1.C: Adjust. * g++.dg/lto/20091002-1_0.C: Adjust. * g++.dg/lto/pr65475c_0.C: Adjust. * g++.dg/opt/dump1.C: Adjust. * g++.dg/other/pr53574.C: Adjust. * g++.dg/template/access30.C: New test. * g++.dg/template/access31.C: New test. * g++.dg/wrappers/wrapper-around-type-pack-expansion.C: Adjust. libstdc++-v3/ChangeLog: PR libstdc++/94003 * testsuite/20_util/is_constructible/94003.cc: New test. --- diff --git a/gcc/cp/call.c b/gcc/cp/call.c index b99959f76f9..b55dc83f0e7 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -7083,42 +7083,6 @@ complain_about_access (tree decl, tree diag_decl, bool issue_error) } } -/* If the current scope isn't allowed to access DECL along - BASETYPE_PATH, give an error. The most derived class in - BASETYPE_PATH is the one used to qualify DECL. DIAG_DECL is - the declaration to use in the error diagnostic. */ - -bool -enforce_access (tree basetype_path, tree decl, tree diag_decl, - tsubst_flags_t complain, access_failure_info *afi) -{ - gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO); - - if (flag_new_inheriting_ctors - && DECL_INHERITED_CTOR (decl)) - { - /* 7.3.3/18: The additional constructors are accessible if they would be - accessible when used to construct an object of the corresponding base - class. */ - decl = strip_inheriting_ctors (decl); - basetype_path = lookup_base (basetype_path, DECL_CONTEXT (decl), - ba_any, NULL, complain); - } - - if (!accessible_p (basetype_path, decl, true)) - { - if (flag_new_inheriting_ctors) - diag_decl = strip_inheriting_ctors (diag_decl); - if (complain & tf_error) - complain_about_access (decl, diag_decl, true); - if (afi) - afi->record_access_failure (basetype_path, decl, diag_decl); - return false; - } - - return true; -} - /* Initialize a temporary of type TYPE with EXPR. The FLAGS are a bitwise or of LOOKUP_* values. If any errors are warnings are generated, set *DIAGNOSTIC_FN to "error" or "warning", diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 44cb10cfee5..771d51cc283 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6339,9 +6339,6 @@ class access_failure_info }; extern void complain_about_access (tree, tree, bool); -extern bool enforce_access (tree, tree, tree, - tsubst_flags_t, - access_failure_info *afi = NULL); extern void push_defarg_context (tree); extern void pop_defarg_context (void); extern tree convert_default_arg (tree, tree, tree, int, @@ -6939,7 +6936,6 @@ extern tree make_pack_expansion (tree, tsubst_flags_t = tf_warni extern bool check_for_bare_parameter_packs (tree, location_t = UNKNOWN_LOCATION); extern tree build_template_info (tree, tree); extern tree get_template_info (const_tree); -extern vec *get_types_needing_access_check (tree); extern int template_class_depth (tree); extern int is_specialization_of (tree, tree); extern bool is_specialization_of_friend (tree, tree); @@ -7257,8 +7253,6 @@ extern void finish_mem_initializers (tree); extern tree check_template_template_default_arg (tree); extern bool expand_or_defer_fn_1 (tree); extern void expand_or_defer_fn (tree); -extern void add_typedef_to_current_template_for_access_check (tree, tree, - location_t); extern bool check_accessibility_of_qualified_id (tree, tree, tree, tsubst_flags_t); extern tree finish_qualified_id_expr (tree, tree, bool, bool, bool, bool, tsubst_flags_t); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b8bd09b37e6..539609e8ada 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4009,14 +4009,10 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, return error_mark_node; } - if (!perform_or_defer_access_check (TYPE_BINFO (context), t, t, complain)) + if (!check_accessibility_of_qualified_id (t, /*object_type=*/NULL_TREE, + context, complain)) return error_mark_node; - /* If we are currently parsing a template and if T is a typedef accessed - through CONTEXT then we need to remember and check access of T at - template instantiation time. */ - add_typedef_to_current_template_for_access_check (t, context, input_location); - if (want_template) return lookup_template_class (t, TREE_OPERAND (fullname, 1), NULL_TREE, context, diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index bc66e6e5c50..799f310bcee 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -29118,16 +29118,12 @@ cp_parser_template_declaration_after_parameters (cp_parser* parser, decl = cp_parser_concept_definition (parser); else { - /* There are no access checks when parsing a template, as we do not - know if a specialization will be a friend. */ - push_deferring_access_checks (dk_no_check); cp_token *token = cp_lexer_peek_token (parser->lexer); decl = cp_parser_single_declaration (parser, checks, member_p, /*explicit_specialization_p=*/false, &friend_p); - pop_deferring_access_checks (); /* If this is a member template declaration, let the front end know. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index cdf6a3eeaf3..bab48c2fdf6 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -216,8 +216,6 @@ static bool dependent_type_p_r (tree); static tree tsubst_copy (tree, tree, tsubst_flags_t, tree); static tree tsubst_decl (tree, tree, tsubst_flags_t); static void perform_typedefs_access_check (tree tmpl, tree targs); -static void append_type_to_template_for_access_check_1 (tree, tree, tree, - location_t); static tree listify (tree); static tree listify_autos (tree, tree); static tree tsubst_template_parm (tree, tree, tsubst_flags_t); @@ -11532,7 +11530,7 @@ perform_typedefs_access_check (tree tmpl, tree targs) return; if (vec *tdefs - = get_types_needing_access_check (tmpl)) + = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (get_template_info (tmpl))) FOR_EACH_VEC_ELT (*tdefs, i, iter) { tree type_decl = iter->typedef_decl; @@ -11541,8 +11539,10 @@ perform_typedefs_access_check (tree tmpl, tree targs) if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope)) continue; - if (uses_template_parms (type_decl)) - type_decl = tsubst (type_decl, targs, tf_error, NULL_TREE); + if (uses_template_parms (type_decl) + || (TREE_CODE (type_decl) == FIELD_DECL + && uses_template_parms (DECL_CONTEXT (type_decl)))) + type_decl = tsubst_copy (type_decl, targs, tf_error, NULL_TREE); if (uses_template_parms (type_scope)) type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE); @@ -29154,116 +29154,6 @@ check_auto_in_tmpl_args (tree tmpl, tree args) return errors; } -/* For a given template T, return the vector of typedefs referenced - in T for which access check is needed at T instantiation time. - T is either a FUNCTION_DECL or a RECORD_TYPE. - Those typedefs were added to T by the function - append_type_to_template_for_access_check. */ - -vec * -get_types_needing_access_check (tree t) -{ - gcc_checking_assert ((CLASS_TYPE_P (t) || TREE_CODE (t) == FUNCTION_DECL)); - - if (tree ti = get_template_info (t)) - if (TI_TEMPLATE (ti)) - return TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti); - - return NULL; -} - -/* Append the typedef TYPE_DECL used in template T to a list of typedefs - tied to T. That list of typedefs will be access checked at - T instantiation time. - T is either a FUNCTION_DECL or a RECORD_TYPE. - TYPE_DECL is a TYPE_DECL node representing a typedef. - SCOPE is the scope through which TYPE_DECL is accessed. - LOCATION is the location of the usage point of TYPE_DECL. - - This function is a subroutine of - append_type_to_template_for_access_check. */ - -static void -append_type_to_template_for_access_check_1 (tree t, - tree type_decl, - tree scope, - location_t location) -{ - qualified_typedef_usage_t typedef_usage; - tree ti; - - if (!t || t == error_mark_node) - return; - - gcc_assert ((TREE_CODE (t) == FUNCTION_DECL - || CLASS_TYPE_P (t)) - && type_decl - && TREE_CODE (type_decl) == TYPE_DECL - && scope); - - if (!(ti = get_template_info (t))) - return; - - gcc_assert (TI_TEMPLATE (ti)); - - typedef_usage.typedef_decl = type_decl; - typedef_usage.context = scope; - typedef_usage.locus = location; - - vec_safe_push (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti), typedef_usage); -} - -/* Append TYPE_DECL to the template TEMPL. - TEMPL is either a class type, a FUNCTION_DECL or a TEMPLATE_DECL. - At TEMPL instanciation time, TYPE_DECL will be checked to see - if it can be accessed through SCOPE. - LOCATION is the location of the usage point of TYPE_DECL. - - e.g. consider the following code snippet: - - class C - { - typedef int myint; - }; - - template struct S - { - C::myint mi; // <-- usage point of the typedef C::myint - }; - - S s; - - At S instantiation time, we need to check the access of C::myint - In other words, we need to check the access of the myint typedef through - the C scope. For that purpose, this function will add the myint typedef - and the scope C through which its being accessed to a list of typedefs - tied to the template S. That list will be walked at template instantiation - time and access check performed on each typedefs it contains. - Note that this particular code snippet should yield an error because - myint is private to C. */ - -void -append_type_to_template_for_access_check (tree templ, - tree type_decl, - tree scope, - location_t location) -{ - qualified_typedef_usage_t *iter; - unsigned i; - - gcc_assert (type_decl && (TREE_CODE (type_decl) == TYPE_DECL)); - - /* Make sure we don't append the type to the template twice. */ - if (vec *tdefs - = get_types_needing_access_check (templ)) - FOR_EACH_VEC_ELT (*tdefs, i, iter) - if (iter->typedef_decl == type_decl && scope == iter->context) - return; - - append_type_to_template_for_access_check_1 (templ, type_decl, - scope, location); -} - /* Recursively walk over && expressions searching for EXPR. Return a reference to that expression. */ diff --git a/gcc/cp/search.c b/gcc/cp/search.c index b9da2fccb7f..a1a45a5ee6b 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -827,21 +827,6 @@ accessible_p (tree type, tree decl, bool consider_local_p) if (current_function_decl && DECL_THUNK_P (current_function_decl)) return 1; - /* In a template declaration, we cannot be sure whether the - particular specialization that is instantiated will be a friend - or not. Therefore, all access checks are deferred until - instantiation. However, PROCESSING_TEMPLATE_DECL is set in the - parameter list for a template (because we may see dependent types - in default arguments for template parameters), and access - checking should be performed in the outermost parameter list. */ - if (processing_template_decl - /* FIXME CWG has been talking about doing access checking in the context - of the constraint-expression, rather than the constrained declaration, - in which case we would want to remove this test. */ - && !processing_constraint_expression_p () - && (!processing_template_parmlist || processing_template_decl > 1)) - return 1; - tree otype = NULL_TREE; if (!TYPE_P (type)) { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 64587c791c6..13b844a49c9 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -256,6 +256,68 @@ pop_to_parent_deferring_access_checks (void) } } +/* If the current scope isn't allowed to access DECL along + BASETYPE_PATH, give an error, or if we're parsing a function or class + template, defer the access check to be performed at instantiation time. + The most derived class in BASETYPE_PATH is the one used to qualify DECL. + DIAG_DECL is the declaration to use in the error diagnostic. */ + +static bool +enforce_access (tree basetype_path, tree decl, tree diag_decl, + tsubst_flags_t complain, access_failure_info *afi = NULL) +{ + gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO); + + if (flag_new_inheriting_ctors + && DECL_INHERITED_CTOR (decl)) + { + /* 7.3.3/18: The additional constructors are accessible if they would be + accessible when used to construct an object of the corresponding base + class. */ + decl = strip_inheriting_ctors (decl); + basetype_path = lookup_base (basetype_path, DECL_CONTEXT (decl), + ba_any, NULL, complain); + } + + tree cs = current_scope (); + if (processing_template_decl + && (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL)) + if (tree template_info = get_template_info (cs)) + { + /* When parsing a function or class template, we in general need to + defer access checks until template instantiation time, since a friend + declaration may grant access only to a particular specialization of + the template. */ + + if (accessible_p (basetype_path, decl, /*consider_local_p=*/true)) + /* But if the member is deemed accessible at parse time, then we can + assume it'll be accessible at instantiation time. */ + return true; + + /* Defer this access check until instantiation time. */ + qualified_typedef_usage_t typedef_usage; + typedef_usage.typedef_decl = decl; + typedef_usage.context = TREE_TYPE (basetype_path); + typedef_usage.locus = input_location; + vec_safe_push (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (template_info), + typedef_usage); + return true; + } + + if (!accessible_p (basetype_path, decl, /*consider_local_p=*/true)) + { + if (flag_new_inheriting_ctors) + diag_decl = strip_inheriting_ctors (diag_decl); + if (complain & tf_error) + complain_about_access (decl, diag_decl, true); + if (afi) + afi->record_access_failure (basetype_path, decl, diag_decl); + return false; + } + + return true; +} + /* Perform the access checks in CHECKS. The TREE_PURPOSE of each node is the BINFO indicating the qualifying scope used to access the DECL node stored in the TREE_VALUE of the node. If CHECKS is empty @@ -320,9 +382,7 @@ perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl, deferred_access *ptr; deferred_access_check *chk; - - /* Exit if we are in a context that no access checking is performed. - */ + /* Exit if we are in a context that no access checking is performed. */ if (deferred_access_no_check) return true; @@ -1992,37 +2052,6 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) return ret; } -/* If we are currently parsing a template and we encountered a typedef - TYPEDEF_DECL that is being accessed though CONTEXT, this function - adds the typedef to a list tied to the current template. - At template instantiation time, that list is walked and access check - performed for each typedef. - LOCATION is the location of the usage point of TYPEDEF_DECL. */ - -void -add_typedef_to_current_template_for_access_check (tree typedef_decl, - tree context, - location_t location) -{ - tree template_info = NULL; - tree cs = current_scope (); - - if (!is_typedef_decl (typedef_decl) - || !context - || !CLASS_TYPE_P (context) - || !cs) - return; - - if (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL) - template_info = get_template_info (cs); - - if (template_info - && TI_TEMPLATE (template_info) - && !currently_open_class (context)) - append_type_to_template_for_access_check (cs, typedef_decl, - context, location); -} - /* DECL was the declaration to which a qualified-id resolved. Issue an error message if it is not accessible. If OBJECT_TYPE is non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the @@ -2036,28 +2065,21 @@ check_accessibility_of_qualified_id (tree decl, tree nested_name_specifier, tsubst_flags_t complain) { - tree scope; - tree qualifying_type = NULL_TREE; - - /* If we are parsing a template declaration and if decl is a typedef, - add it to a list tied to the template. - At template instantiation time, that list will be walked and - access check performed. */ - add_typedef_to_current_template_for_access_check (decl, - nested_name_specifier - ? nested_name_specifier - : DECL_CONTEXT (decl), - input_location); - /* If we're not checking, return immediately. */ if (deferred_access_no_check) return true; /* Determine the SCOPE of DECL. */ - scope = context_for_name_lookup (decl); + tree scope = context_for_name_lookup (decl); /* If the SCOPE is not a type, then DECL is not a member. */ - if (!TYPE_P (scope)) + if (!TYPE_P (scope) + /* If SCOPE is dependent then we can't perform this access check now, + and since we'll perform this access check again after substitution + there's no need to explicitly defer it. */ + || dependent_type_p (scope)) return true; + + tree qualifying_type = NULL_TREE; /* Compute the scope through which DECL is being accessed. */ if (object_type /* OBJECT_TYPE might not be a class type; consider: @@ -2096,8 +2118,7 @@ check_accessibility_of_qualified_id (tree decl, if (qualifying_type /* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM or similar in a default argument value. */ - && CLASS_TYPE_P (qualifying_type) - && !dependent_type_p (qualifying_type)) + && CLASS_TYPE_P (qualifying_type)) return perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl, decl, complain); diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C index 206b54a2883..b9a67f5d8da 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C @@ -10,7 +10,7 @@ template using g = typename f::e; struct b; template struct f { using e = b; }; template struct m { typedef g aj; }; -template class n { typedef typename m::aj e; }; +template struct n { typedef typename m::aj e; }; template using an = typename n::e; template constexpr bool ao = c::d; template constexpr bool i = c<1>::d; @@ -38,7 +38,7 @@ template concept de = dd; struct { template void operator()(da, b); } di; -class p { +struct p { void begin(); }; template using df = p; diff --git a/gcc/testsuite/g++.dg/lto/20081219_1.C b/gcc/testsuite/g++.dg/lto/20081219_1.C index 1bb96ef37de..8d64a0212cb 100644 --- a/gcc/testsuite/g++.dg/lto/20081219_1.C +++ b/gcc/testsuite/g++.dg/lto/20081219_1.C @@ -7,7 +7,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) { using::mbstate_t; typedef int *__c_locale; - class locale + struct locale { class facet; }; diff --git a/gcc/testsuite/g++.dg/lto/20091002-1_0.C b/gcc/testsuite/g++.dg/lto/20091002-1_0.C index 4ddb3854c64..e09ce01cdfc 100644 --- a/gcc/testsuite/g++.dg/lto/20091002-1_0.C +++ b/gcc/testsuite/g++.dg/lto/20091002-1_0.C @@ -14,7 +14,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) typedef basic_ostream ostream; template > class num_get; - class locale { + struct locale { class facet; }; class locale::facet { diff --git a/gcc/testsuite/g++.dg/lto/pr65475c_0.C b/gcc/testsuite/g++.dg/lto/pr65475c_0.C index 73686918c2c..4e3de7d6a34 100644 --- a/gcc/testsuite/g++.dg/lto/pr65475c_0.C +++ b/gcc/testsuite/g++.dg/lto/pr65475c_0.C @@ -24,7 +24,9 @@ namespace std { class locale { +public: class facet; +private: class _Impl; _Impl *_M_impl; }; @@ -70,6 +72,7 @@ class ios_base int _M_word_size; _Words *_M_word; locale _M_ios_locale; +protected: virtual ~ ios_base (); }; template < typename, typename > class istreambuf_iterator diff --git a/gcc/testsuite/g++.dg/opt/dump1.C b/gcc/testsuite/g++.dg/opt/dump1.C index 75d71110022..558bee00762 100644 --- a/gcc/testsuite/g++.dg/opt/dump1.C +++ b/gcc/testsuite/g++.dg/opt/dump1.C @@ -396,7 +396,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) ; template class function; - class _Function_base + struct _Function_base { template class _Base_manager diff --git a/gcc/testsuite/g++.dg/other/pr53574.C b/gcc/testsuite/g++.dg/other/pr53574.C index cc899a552c8..87622d522ee 100644 --- a/gcc/testsuite/g++.dg/other/pr53574.C +++ b/gcc/testsuite/g++.dg/other/pr53574.C @@ -6,7 +6,7 @@ template struct A { typedef int type; }; struct B { typedef __SIZE_TYPE__ H; }; -template class allocator : B {}; +template class allocator : public B {}; template struct C { template static typename T::H foo(T *); diff --git a/gcc/testsuite/g++.dg/template/access30.C b/gcc/testsuite/g++.dg/template/access30.C new file mode 100644 index 00000000000..b03a99af1f0 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/access30.C @@ -0,0 +1,10 @@ +// PR c++/41437 +// { dg-do compile } + +class A { struct B { B(); }; }; +template void f() { A::B b; } // { dg-error "private" } +void g() { f(); } + +class X { template struct A{}; }; + +X::A a; // { dg-error "private" } diff --git a/gcc/testsuite/g++.dg/template/access31.C b/gcc/testsuite/g++.dg/template/access31.C new file mode 100644 index 00000000000..0aa7dbbf8f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/access31.C @@ -0,0 +1,29 @@ +// PR c++/47346 +// { dg-do compile } + +class C +{ + struct Private { }; +}; + +template +struct exploit1 +{ + typedef C::Private type; // { dg-error "private" } +}; +exploit1::type x1; + +template +struct exploit2 : C::Private // { dg-error "private" } +{ +}; +exploit2 x2; + +template +struct exploit3 +{ + template // { dg-error "private" } + struct E {}; +}; + +exploit3::E<> e; diff --git a/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C b/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C index 5072d1ad59d..1f9ad5fdb47 100644 --- a/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C +++ b/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C @@ -35,7 +35,7 @@ struct __alloc_traits : allocator_traits<_Alloc> { template struct rebind { typedef typename _Base_type::template rebind_alloc<_Tp> other; }; }; -template class allocator { +template struct allocator { typedef _Tp value_type; template struct rebind { typedef allocator<_Tp1> other; }; }; diff --git a/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc b/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc new file mode 100644 index 00000000000..80646b37f55 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc @@ -0,0 +1,28 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do compile { target c++11 } } + +#include + +class Class { Class() {} }; + +template static bool foo() { + return std::is_constructible::value; +} + +static_assert(!std::is_constructible::value, "");