From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 57442385840E for ; Wed, 16 Feb 2022 19:56:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 57442385840E Received: from mail-qv1-f71.google.com (mail-qv1-f71.google.com [209.85.219.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-625-RPEqX8aOMXSpGEfcJduHFA-1; Wed, 16 Feb 2022 14:56:09 -0500 X-MC-Unique: RPEqX8aOMXSpGEfcJduHFA-1 Received: by mail-qv1-f71.google.com with SMTP id l3-20020a0ce503000000b0042c0129c766so2833622qvm.20 for ; Wed, 16 Feb 2022 11:56:09 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:date:to:cc:subject:in-reply-to:message-id :references:mime-version; bh=RvRQOWDlohwjfYaBWKGA2WtevDMOy4tnLk2rPG2ivL0=; b=UC7SRm6VntlnnHDk0DexSYfVCVwQWByQejj9eC0g7sZwn1kIOC74gAB17+CH7R6JHO PwM6LbWihLsW8+z7cTqyqBbswnbPlDi/98D5m8RjCRAX56w4qBOEKiY5rsvA5xy08923 VZgLTfQCLFr830OFFftoSvnFszd18RbaoPxfBZ0vhO8yesddUxT3Gjgu2F0hKWKNQra7 pac0wOQbWaLrQLa8g6AtN4zEwYd32dYsvRdFCFMh9OgWI0B7Hv+8ZfzaYHuhNLEjWvzm ck57xyD+NI/xcBtUwAMDg9r9rdI1DKxaiUucyD4RmddJXFqYejMp06iztt3c7cuDOkkt ybcQ== X-Gm-Message-State: AOAM5311YdasLBlaGhQEzh7JC8D678ihc3rVm87nYZf7zZlHUUiZdTZH WwALobRAhkOqDb/znViy1Dqwamcv7p21NFB1zg+E2Ol7NR+kyGmyPQG58faQmzV++JKdY8LJIxu GciOLWVFzkcwQ27+2Aw== X-Received: by 2002:ac8:7d54:0:b0:2d7:1ca6:db33 with SMTP id h20-20020ac87d54000000b002d71ca6db33mr3206842qtb.459.1645041368117; Wed, 16 Feb 2022 11:56:08 -0800 (PST) X-Google-Smtp-Source: ABdhPJwFRMCW1ViTYomjGVBL2QBKy4MGniZ217a6S36dntyFgjMLgdwgtZei07zZpPT4SkVJzm+eRg== X-Received: by 2002:ac8:7d54:0:b0:2d7:1ca6:db33 with SMTP id h20-20020ac87d54000000b002d71ca6db33mr3206829qtb.459.1645041367801; Wed, 16 Feb 2022 11:56:07 -0800 (PST) Received: from [192.168.1.130] (ool-18e40894.dyn.optonline.net. [24.228.8.148]) by smtp.gmail.com with ESMTPSA id e17sm22009107qte.94.2022.02.16.11.56.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 11:56:07 -0800 (PST) From: Patrick Palka X-Google-Original-From: Patrick Palka Date: Wed, 16 Feb 2022 14:56:06 -0500 (EST) To: Jason Merrill cc: Patrick Palka , gcc-patches@gcc.gnu.org Subject: Re: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] In-Reply-To: <4c1b4638-0ad6-f229-4d9b-ac2fb362d058@redhat.com> Message-ID: <508cd6cd-3d60-a846-411e-20599702c9d8@idea> References: <20220214163250.3454164-1-ppalka@redhat.com> <4c1b4638-0ad6-f229-4d9b-ac2fb362d058@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=US-ASCII X-Spam-Status: No, score=-14.6 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 16 Feb 2022 19:56:18 -0000 On Tue, 15 Feb 2022, Jason Merrill wrote: > On 2/14/22 11:32, Patrick Palka wrote: > > Here the template context for the atomic constraint has two levels of > > template arguments, but since it depends only on the innermost argument > > T we use a single-level argument vector during substitution into the > > constraint (built by get_mapped_args). We eventually pass this vector > > to do_auto_deduction as part of checking the return-type-requirement > > inside the atom, but do_auto_deduction expects outer_targs to be a full > > set of arguments for sake of satisfaction. > > Could we note the current number of levels in the map and use that in > get_mapped_args instead of the highest level parameter we happened to use? Ah yeah, that seems to work nicely. IIUC it should suffice to remember whether the atomic constraint expression came from a concept definition. If it did, then the depth of the argument vector returned by get_mapped_args must be one, otherwise (as in the testcase) it must be the same as the template depth of the constrained entity, which is the depth of ARGS. How does the following look? Bootstrapped and regtested on x86_64-pc-linux-gnu and also on cmcstl2 and range-v3. -- >8 -- Subject: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] Here the template context for the atomic constraint has two levels of template parameters, but since it depends only on the innermost parameter T we use a single-level argument vector (built by get_mapped_args) during substitution into the atom. We eventually pass this vector to do_auto_deduction as part of checking the return-type-requirement within the atom, but do_auto_deduction expects outer_targs to be a full set of arguments for sake of satisfaction. This patch fixes this by making get_mapped_args always return an argument vector whose depth corresponds to the template depth of the context in which the atomic constraint expression was written, instead of the highest parameter level that the expression happens to use. PR c++/104527 gcc/cp/ChangeLog: * constraint.cc (normalize_atom): Set ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P appropriately. (get_mapped_args): Make static, adjust parameters. Always return a vector whose depth corresponds to the template depth of the context of the atomic constraint expression. Micro-optimize by passing false as exact to safe_grow_cleared and by collapsing a multi-level depth-one argument vector. (satisfy_atom): Adjust call to get_mapped_args and diagnose_atomic_constraint. (diagnose_atomic_constraint): Replace map parameter with an args parameter. * cp-tree.h (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P): Define. (get_mapped_args): Remove declaration. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-return-req4.C: New test. --- gcc/cp/constraint.cc | 64 +++++++++++-------- gcc/cp/cp-tree.h | 7 +- .../g++.dg/cpp2a/concepts-return-req4.C | 24 +++++++ 3 files changed, 69 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 12db7e5cf14..306e28955c6 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -764,6 +764,8 @@ normalize_atom (tree t, tree args, norm_info info) tree ci = build_tree_list (t, info.context); tree atom = build1 (ATOMIC_CONSTR, ci, map); + if (info.in_decl && concept_definition_p (info.in_decl)) + ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true; if (!info.generate_diagnostics ()) { /* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal @@ -2826,33 +2828,37 @@ satisfaction_value (tree t) return boolean_true_node; } -/* Build a new template argument list with template arguments corresponding - to the parameters used in an atomic constraint. */ +/* Build a new template argument vector according to the parameter + mapping of the atomic constraint T, using arguments from ARGS. */ -tree -get_mapped_args (tree map) +static tree +get_mapped_args (tree t, tree args) { + tree map = ATOMIC_CONSTR_MAP (t); + /* No map, no arguments. */ if (!map) return NULL_TREE; - /* Find the mapped parameter with the highest level. */ - int count = 0; - for (tree p = map; p; p = TREE_CHAIN (p)) - { - int level; - int index; - template_parm_level_and_index (TREE_VALUE (p), &level, &index); - if (level > count) - count = level; - } + /* Determine the depth of the resulting argument vector. */ + int depth; + if (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (t)) + /* The expression of this atomic constraint comes from a concept definition, + whose template depth is always one, so the resulting argument vector + will also have depth one. */ + depth = 1; + else + /* Otherwise, the expression of this atomic constraint was written in + the context of the constrained entity, whose template depth is that + of ARGS. */ + depth = TMPL_ARGS_DEPTH (args); /* Place each argument at its corresponding position in the argument list. Note that the list will be sparse (not all arguments supplied), but instantiation is guaranteed to only use the parameters in the mapping, so null arguments would never be used. */ - auto_vec< vec > lists (count); - lists.quick_grow_cleared (count); + auto_vec< vec > lists (depth); + lists.quick_grow_cleared (depth); for (tree p = map; p; p = TREE_CHAIN (p)) { int level; @@ -2862,12 +2868,12 @@ get_mapped_args (tree map) /* Insert the argument into its corresponding position. */ vec &list = lists[level - 1]; if (index >= (int)list.length ()) - list.safe_grow_cleared (index + 1, true); + list.safe_grow_cleared (index + 1, /*exact=*/false); list[index] = TREE_PURPOSE (p); } /* Build the new argument list. */ - tree args = make_tree_vec (lists.length ()); + args = make_tree_vec (lists.length ()); for (unsigned i = 0; i != lists.length (); ++i) { vec &list = lists[i]; @@ -2879,6 +2885,16 @@ get_mapped_args (tree map) } SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, 0); + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args) + && TMPL_ARGS_DEPTH (args) == 1) + { + /* Micro-optimization: represent a depth-one argument vector + using a single level. */ + tree level = TMPL_ARGS_LEVEL (args, 1); + ggc_free (args); + args = level; + } + return args; } @@ -2933,7 +2949,7 @@ satisfy_atom (tree t, tree args, sat_info info) } /* Rebuild the argument vector from the parameter mapping. */ - args = get_mapped_args (map); + args = get_mapped_args (t, args); /* Apply the parameter mapping (i.e., just substitute). */ tree expr = ATOMIC_CONSTR_EXPR (t); @@ -2955,7 +2971,7 @@ satisfy_atom (tree t, tree args, sat_info info) if (!same_type_p (TREE_TYPE (result), boolean_type_node)) { if (info.noisy ()) - diagnose_atomic_constraint (t, map, result, info); + diagnose_atomic_constraint (t, args, result, info); return cache.save (inst_cache.save (error_mark_node)); } @@ -2974,7 +2990,7 @@ satisfy_atom (tree t, tree args, sat_info info) } result = satisfaction_value (result); if (result == boolean_false_node && info.diagnose_unsatisfaction_p ()) - diagnose_atomic_constraint (t, map, result, info); + diagnose_atomic_constraint (t, args, result, info); return cache.save (inst_cache.save (result)); } @@ -3642,11 +3658,10 @@ diagnose_trait_expr (tree expr, tree args) } } -/* Diagnose a substitution failure in the atomic constraint T when applied - with the instantiated parameter mapping MAP. */ +/* Diagnose a substitution failure in the atomic constraint T using ARGS. */ static void -diagnose_atomic_constraint (tree t, tree map, tree result, sat_info info) +diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info) { /* If the constraint is already ill-formed, we've previously diagnosed the reason. We should still say why the constraints aren't satisfied. */ @@ -3667,7 +3682,6 @@ diagnose_atomic_constraint (tree t, tree map, tree result, sat_info info) /* Generate better diagnostics for certain kinds of expressions. */ tree expr = ATOMIC_CONSTR_EXPR (t); STRIP_ANY_LOCATION_WRAPPER (expr); - tree args = get_mapped_args (map); switch (TREE_CODE (expr)) { case TRAIT_EXPR: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f253b32c3f2..dc2429a8406 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -466,6 +466,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; IMPLICIT_CONV_EXPR_NONTYPE_ARG (in IMPLICIT_CONV_EXPR) BASELINK_FUNCTIONS_MAYBE_INCOMPLETE_P (in BASELINK) BIND_EXPR_VEC_DTOR (in BIND_EXPR) + ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR) 2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE) ICS_THIS_FLAG (in _CONV) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) @@ -1679,6 +1680,11 @@ check_constraint_info (tree t) #define ATOMIC_CONSTR_MAP_INSTANTIATED_P(NODE) \ TREE_LANG_FLAG_0 (ATOMIC_CONSTR_CHECK (NODE)) +/* Whether the expression for this atomic constraint belongs to a + concept definition. */ +#define ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P(NODE) \ + TREE_LANG_FLAG_1 (ATOMIC_CONSTR_CHECK (NODE)) + /* The expression of an atomic constraint. */ #define ATOMIC_CONSTR_EXPR(NODE) \ CONSTR_EXPR (ATOMIC_CONSTR_CHECK (NODE)) @@ -8306,7 +8312,6 @@ extern tree evaluate_requires_expr (tree); extern tree tsubst_constraint (tree, tree, tsubst_flags_t, tree); extern tree tsubst_constraint_info (tree, tree, tsubst_flags_t, tree); extern tree tsubst_parameter_mapping (tree, tree, tsubst_flags_t, tree); -extern tree get_mapped_args (tree); struct processing_constraint_expression_sentinel { diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C new file mode 100644 index 00000000000..471946bc8eb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C @@ -0,0 +1,24 @@ +// PR c++/104527 +// { dg-do compile { target c++20 } } + +template +concept is_same = __is_same(T, U); + +template +struct A { + template + requires requires { { 0 } -> is_same; } + struct B {}; + + template + requires requires { { 1 } -> is_same; } + static void f(); +}; + +A::B<> a1; +A::B<> a2; // { dg-error "constraint" } + +int main() { + A::f(); + A::f(); // { dg-error "no match" } +} -- 2.35.1.129.gb80121027d