From patchwork Fri Dec 4 21:33:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1411277 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gcc.gnu.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=IFB55ego; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CnmCZ23kNz9sWK for ; Sat, 5 Dec 2020 08:33:14 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 982103896014; Fri, 4 Dec 2020 21:33:11 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 982103896014 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1607117591; bh=gyy5VyAvi0ON0CcANaqaObb7DAGWzOvVVxDz+iIUumI=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=IFB55egoZTDOyVR1hlE8sSbqKBtJEb22vCUuBRrMXH79G+Lv0JMZ8EASozTLBCWFp ChiLb8VTpUqK44WXp+A4jJVuN5omvctFhIcNdg07LHGHNOW7hpn+5ERGJZyubN+M5b 0R/7zsseqY9T8WHoRujzlgX0NNFo2UMOxooXRAeM= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id D6EDD3846034 for ; Fri, 4 Dec 2020 21:33:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org D6EDD3846034 Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-365-9qQvf1XvMpiH9iCLGdRuxg-1; Fri, 04 Dec 2020 16:33:07 -0500 X-MC-Unique: 9qQvf1XvMpiH9iCLGdRuxg-1 Received: by mail-qt1-f200.google.com with SMTP id f33so5806760qtb.1 for ; Fri, 04 Dec 2020 13:33:07 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=gyy5VyAvi0ON0CcANaqaObb7DAGWzOvVVxDz+iIUumI=; b=jUQfpExxaSeZY0AHPYgLDsm3i4PgTeZgQ17Ezd9vL6OSt3IjzXbBPf9BAWBHnGa3R6 vvYf91aJZlA1eEnpBM+3hDYMSaSBS4v6vWAu0MQB1pJSq61472w1ElRkKLzy/X/X46RS RJpwjYysQHjR9xGvWiML3zAjII3U8iEV+Sj2DtTB8bKPQQdubOAuR/4fFe66k+V05pWl fWRVqRB+sxcfZAdeKBhp29YeQDXWaH6xqqbX2PXILMGv2rs+M98BOtOM1ZNuD/+JNxCE C9KyncBPOutY46x9gDb68znjScAAkoeul0GtMTkAxfJgYXMOBe+AyBPaYeVWmGiJFVxV I1sg== X-Gm-Message-State: AOAM532yw6rlGOZLcdnW/SUJRvlG/TMYAiy0V88ugfqBpBh8SroWRNBE SViiwdyAQ2SWvBaszEeSeYm5ftOUMJGJbeJ206whg0ARUjQ2QFE9BZmmtMqK7GoHUczejHxD/90 5rM5VLb1aRP8pyKSrYIni4Lbadz3akmvLZWsF64uMklW59UDEhrya6DsZL2fEfLmVZGk= X-Received: by 2002:a37:4f4e:: with SMTP id d75mr11789448qkb.284.1607117585562; Fri, 04 Dec 2020 13:33:05 -0800 (PST) X-Google-Smtp-Source: ABdhPJz6VcamqKPLPixld7nnoMTsX30TUGO0i0AJMAXTHOknZ9Xh6FqwB7G7FDi8LzROZemC4tAWkw== X-Received: by 2002:a37:4f4e:: with SMTP id d75mr11789389qkb.284.1607117584928; Fri, 04 Dec 2020 13:33:04 -0800 (PST) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id b14sm5731731qtx.36.2020.12.04.13.33.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Dec 2020 13:33:04 -0800 (PST) To: gcc-patches@gcc.gnu.org Subject: [PATCH 1/2 v2] c++: Distinguish unsatisfaction vs errors during satisfaction [PR97093] Date: Fri, 4 Dec 2020 16:33:00 -0500 Message-Id: <20201204213301.1836322-1-ppalka@redhat.com> X-Mailer: git-send-email 2.29.2.404.ge67fbf927d MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-16.9 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_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) 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-Patchwork-Original-From: Patrick Palka via Gcc-patches From: Patrick Palka Reply-To: Patrick Palka Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" During satisfaction, the flag info.noisy() controls three things: whether to diagnose ill-formed satisfaction (such as the satisfaction value of an atom being non-bool or non-constant); whether to diagnose unsatisfaction; and whether to bypass the satisfaction cache. The flag turns out to be too coarse however, because in some cases we want to diagnose ill-formed satisfaction (and bypass the satisfaction cache) but not diagnose unsatisfaction, for instance when replaying an erroneous satisfaction result from constraint_satisfaction_value, evaluate_concept_check and tsubst_nested_requirement. And when noisily evaluating a disjunction, we want to first evaluate its branches noisily (bypassing the satisfaction cache) but suppress unsatisfaction diagnostics. We currently work around this by instead first evaluating each branch quietly, but that means the recursive calls to satisfy_atom will use the satisfaction cache. To fix this, this patch adds the info.diagnose_unsatisfaction_p() flag, which refines the info.noisy() flag as part of a new sat_info class that derives from subst_info. During satisfaction, info.noisy() now controls whether to diagnose ill-formed satisfaction, and info.diagnose_unsatisfaction_p() controls whether to additionally diagnose unsatisfaction. This enables us to address the above two issues straightforwardly. Incidentally, the change to satisfy_disjunction suppresses the ICE in the PR97093 testcase because we no longer insert atoms into the satisfaction cache that have been incorrectly re-normalized in diagnose_nested_requirement (after losing the necessary template context). But the underlying re-normalization issue remains, and will be fixed in a subsequent patch. gcc/cp/ChangeLog: PR c++/97093 * constraint.cc (struct sat_info): Define. (tsubst_nested_requirement): Pass a sat_info object to satisfy_constraint. (satisfy_constraint_r): Take a sat_info argument instead of subst_info. (satisfy_conjunction): Likewise. (satisfy_disjunction): Likewise. Instead of first evaluating each branch quietly, evaluate each branch only with unsatisfaction diagnostics disabled. Exit early if evaluation of a branch returns error_mark_node. (satisfy_atom): Take a sat_info argument instead of subst_info. Fix a comment. Check diagnose_unsatisfaction_p() instead of noisy() before replaying a substitution failure. (satisfy_constraint): Take a sat_info argument instead of subst_info. (satisfy_associated_constraints): Likewise. (satisfy_constraint_expression): Likewise. (satisfy_declaration_constraints): Likewise. (constraint_satisfaction_value): Likewise and adjust accordingly. Fix formatting. (constraints_satisfied_p): Pass a sat_info object to constraint_satisfaction_value. (evaluate_concept_check): Pass a sat_info object to satisfy_constraint_expression. (diagnose_nested_requirement): Likewise. (diagnose_constraints): Pass an appropriate sat_info object to constraint_satisfaction_value. gcc/testsuite/ChangeLog: PR c++/97093 * g++.dg/concepts/pr94252.C: Verify we no longer issue a spurious satisfaction failure note when diagnosing ill-formed satisfaction. * g++.dg/cpp2a/concepts-requires18.C: No longer expect a spurious satisfaction failure diagnostic when immediately evaluating the nested-requirement subst of a requires-expression that appears outside of a template. * g++.dg/cpp2a/concepts-requires21.C: Verify we no longer issue a spurious satisfaction failure note when immediately evaluating a nested-requirement of a requires-expression that appears outside of a template. * g++.dg/cpp2a/concepts-nonbool3.C: New test. * g++.dg/cpp2a/concepts-pr97093.C: New test. --- gcc/cp/constraint.cc | 149 +++++++++++------- gcc/testsuite/g++.dg/concepts/pr94252.C | 1 + .../g++.dg/cpp2a/concepts-nonbool3.C | 5 + .../g++.dg/cpp2a/concepts-requires18.C | 2 +- .../g++.dg/cpp2a/concepts-requires21.C | 1 + 5 files changed, 104 insertions(+), 54 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-nonbool3.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 7f02aa0a215..2be1a841535 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -98,7 +98,35 @@ struct subst_info tree in_decl; }; -static tree satisfy_constraint (tree, tree, subst_info); +/* Provides additional context for satisfaction. + + The flag noisy() controls whether to diagnose ill-formed satisfaction, + such as the satisfaction value of an atom being non-bool or non-constant. + + The flag diagnose_unsatisfaction_p(), which implies noisy(), controls + whether to explain why a constraint is not satisfied. */ + +struct sat_info : subst_info +{ + sat_info (tsubst_flags_t cmp, tree in, bool diagnose_unsat = false) + : subst_info (cmp, in), diagnose_unsatisfaction (diagnose_unsat) + { + if (diagnose_unsatisfaction_p ()) + gcc_checking_assert (noisy ()); + } + + /* True if we should diagnose the cause of satisfaction failure. + Implies noisy(). */ + bool + diagnose_unsatisfaction_p () const + { + return diagnose_unsatisfaction; + } + + bool diagnose_unsatisfaction; +}; + +static tree satisfy_constraint (tree, tree, sat_info); /* True if T is known to be some type other than bool. Note that this is false for dependent types and errors. */ @@ -2059,10 +2087,11 @@ tsubst_nested_requirement (tree t, tree args, subst_info info) { /* Ensure that we're in an evaluation context prior to satisfaction. */ tree norm = TREE_TYPE (t); - tree result = satisfy_constraint (norm, args, info); + tree result = satisfy_constraint (norm, args, + sat_info (info.complain, info.in_decl)); if (result == error_mark_node && info.quiet ()) { - subst_info noisy (tf_warning_or_error, info.in_decl); + sat_info noisy (tf_warning_or_error, info.in_decl); satisfy_constraint (norm, args, noisy); } if (result != boolean_true_node) @@ -2508,12 +2537,12 @@ tsubst_constraint (tree t, tree args, tsubst_flags_t complain, tree in_decl) return expr; } -static tree satisfy_constraint_r (tree, tree, subst_info info); +static tree satisfy_constraint_r (tree, tree, sat_info info); /* Compute the satisfaction of a conjunction. */ static tree -satisfy_conjunction (tree t, tree args, subst_info info) +satisfy_conjunction (tree t, tree args, sat_info info) { tree lhs = satisfy_constraint_r (TREE_OPERAND (t, 0), args, info); if (lhs == error_mark_node || lhs == boolean_false_node) @@ -2567,20 +2596,25 @@ collect_operands_of_disjunction (tree t, auto_vec *operands) /* Compute the satisfaction of a disjunction. */ static tree -satisfy_disjunction (tree t, tree args, subst_info info) +satisfy_disjunction (tree t, tree args, sat_info info) { - /* Evaluate the operands quietly. */ - subst_info quiet (tf_none, NULL_TREE); + /* Evaluate each operand with unsatisfaction diagnostics disabled. */ + sat_info sub = info; + sub.diagnose_unsatisfaction = false; - /* Register the constraint for diagnostics, if needed. */ - diagnosing_failed_constraint failure (t, args, info.noisy ()); + tree lhs = satisfy_constraint_r (TREE_OPERAND (t, 0), args, sub); + if (lhs == boolean_true_node || lhs == error_mark_node) + return lhs; - tree lhs = satisfy_constraint_r (TREE_OPERAND (t, 0), args, quiet); - if (lhs == boolean_true_node) - return boolean_true_node; - tree rhs = satisfy_constraint_r (TREE_OPERAND (t, 1), args, quiet); - if (rhs != boolean_true_node && info.noisy ()) + tree rhs = satisfy_constraint_r (TREE_OPERAND (t, 1), args, sub); + if (rhs == boolean_true_node || rhs == error_mark_node) + return rhs; + + /* Both branches evaluated to false. Explain the satisfaction failure in + each branch. */ + if (info.diagnose_unsatisfaction_p ()) { + diagnosing_failed_constraint failure (t, args, info.noisy ()); cp_expr disj_expr = CONSTR_EXPR (t); inform (disj_expr.get_location (), "no operand of the disjunction is satisfied"); @@ -2601,7 +2635,8 @@ satisfy_disjunction (tree t, tree args, subst_info info) } } } - return rhs; + + return boolean_false_node; } /* Ensures that T is a truth value and not (accidentally, as sometimes @@ -2682,7 +2717,7 @@ static void diagnose_atomic_constraint (tree, tree, tree, subst_info); /* Compute the satisfaction of an atomic constraint. */ static tree -satisfy_atom (tree t, tree args, subst_info info) +satisfy_atom (tree t, tree args, sat_info info) { satisfaction_cache cache (t, args, info.complain); if (tree r = cache.get ()) @@ -2700,9 +2735,9 @@ satisfy_atom (tree t, tree args, subst_info info) tree map = tsubst_parameter_mapping (ATOMIC_CONSTR_MAP (t), args, quiet); if (map == error_mark_node) { - /* If instantiation of the parameter mapping fails, the program - is ill-formed. */ - if (info.noisy()) + /* If instantiation of the parameter mapping fails, the constraint is + not satisfied. Replay the substitution. */ + if (info.diagnose_unsatisfaction_p ()) tsubst_parameter_mapping (ATOMIC_CONSTR_MAP (t), args, info); return cache.save (boolean_false_node); } @@ -2729,7 +2764,7 @@ satisfy_atom (tree t, tree args, subst_info info) { /* If substitution results in an invalid type or expression, the constraint is not satisfied. Replay the substitution. */ - if (info.noisy ()) + if (info.diagnose_unsatisfaction_p ()) tsubst_expr (expr, args, info.complain, info.in_decl, false); return cache.save (inst_cache.save (boolean_false_node)); } @@ -2757,7 +2792,7 @@ satisfy_atom (tree t, tree args, subst_info info) result = error_mark_node; } result = satisfaction_value (result); - if (result == boolean_false_node && info.noisy ()) + if (result == boolean_false_node && info.diagnose_unsatisfaction_p ()) diagnose_atomic_constraint (t, map, result, info); return cache.save (inst_cache.save (result)); @@ -2775,7 +2810,7 @@ satisfy_atom (tree t, tree args, subst_info info) constraint only matters for subsumption. */ static tree -satisfy_constraint_r (tree t, tree args, subst_info info) +satisfy_constraint_r (tree t, tree args, sat_info info) { if (t == error_mark_node) return error_mark_node; @@ -2796,7 +2831,7 @@ satisfy_constraint_r (tree t, tree args, subst_info info) /* Check that the normalized constraint T is satisfied for ARGS. */ static tree -satisfy_constraint (tree t, tree args, subst_info info) +satisfy_constraint (tree t, tree args, sat_info info) { auto_timevar time (TV_CONSTRAINT_SAT); @@ -2814,7 +2849,7 @@ satisfy_constraint (tree t, tree args, subst_info info) value (either true, false, or error). */ static tree -satisfy_associated_constraints (tree t, tree args, subst_info info) +satisfy_associated_constraints (tree t, tree args, sat_info info) { /* If there are no constraints then this is trivially satisfied. */ if (!t) @@ -2832,7 +2867,7 @@ satisfy_associated_constraints (tree t, tree args, subst_info info) satisfaction value. */ static tree -satisfy_constraint_expression (tree t, tree args, subst_info info) +satisfy_constraint_expression (tree t, tree args, sat_info info) { if (t == error_mark_node) return error_mark_node; @@ -2861,12 +2896,12 @@ satisfy_constraint_expression (tree t, tree args, subst_info info) tree satisfy_constraint_expression (tree expr) { - subst_info info (tf_none, NULL_TREE); + sat_info info (tf_none, NULL_TREE); return satisfy_constraint_expression (expr, NULL_TREE, info); } static tree -satisfy_declaration_constraints (tree t, subst_info info) +satisfy_declaration_constraints (tree t, sat_info info) { gcc_assert (DECL_P (t)); const tree saved_t = t; @@ -2926,7 +2961,7 @@ satisfy_declaration_constraints (tree t, subst_info info) } static tree -satisfy_declaration_constraints (tree t, tree args, subst_info info) +satisfy_declaration_constraints (tree t, tree args, sat_info info) { /* Update the declaration for diagnostics. */ info.in_decl = t; @@ -2951,9 +2986,8 @@ satisfy_declaration_constraints (tree t, tree args, subst_info info) } static tree -constraint_satisfaction_value (tree t, tsubst_flags_t complain) +constraint_satisfaction_value (tree t, sat_info info) { - subst_info info (complain, NULL_TREE); tree r; if (DECL_P (t)) r = satisfy_declaration_constraints (t, info); @@ -2961,26 +2995,31 @@ constraint_satisfaction_value (tree t, tsubst_flags_t complain) r = satisfy_constraint_expression (t, NULL_TREE, info); if (r == error_mark_node && info.quiet () && !(DECL_P (t) && TREE_NO_WARNING (t))) - { - constraint_satisfaction_value (t, tf_warning_or_error); - if (DECL_P (t)) - /* Avoid giving these errors again. */ - TREE_NO_WARNING (t) = true; - } + { + /* Replay the error with re-normalized requirements. */ + sat_info noisy (tf_warning_or_error, info.in_decl); + constraint_satisfaction_value (t, noisy); + if (DECL_P (t)) + /* Avoid giving these errors again. */ + TREE_NO_WARNING (t) = true; + } return r; } static tree -constraint_satisfaction_value (tree t, tree args, tsubst_flags_t complain) +constraint_satisfaction_value (tree t, tree args, sat_info info) { - subst_info info (complain, NULL_TREE); tree r; if (DECL_P (t)) r = satisfy_declaration_constraints (t, args, info); else r = satisfy_constraint_expression (t, args, info); if (r == error_mark_node && info.quiet ()) - constraint_satisfaction_value (t, args, tf_warning_or_error); + { + /* Replay the error with re-normalized requirements. */ + sat_info noisy (tf_warning_or_error, info.in_decl); + constraint_satisfaction_value (t, args, noisy); + } return r; } @@ -2993,7 +3032,8 @@ constraints_satisfied_p (tree t) if (!flag_concepts) return true; - return constraint_satisfaction_value (t, tf_none) == boolean_true_node; + sat_info quiet (tf_none, NULL_TREE); + return constraint_satisfaction_value (t, quiet) == boolean_true_node; } /* True iff the result of satisfying T with ARGS is BOOLEAN_TRUE_NODE @@ -3005,7 +3045,8 @@ constraints_satisfied_p (tree t, tree args) if (!flag_concepts) return true; - return constraint_satisfaction_value (t, args, tf_none) == boolean_true_node; + sat_info quiet (tf_none, NULL_TREE); + return constraint_satisfaction_value (t, args, quiet) == boolean_true_node; } /* Evaluate a concept check of the form C. This is only used for the @@ -3020,14 +3061,14 @@ evaluate_concept_check (tree check, tsubst_flags_t complain) gcc_assert (concept_check_p (check)); /* Check for satisfaction without diagnostics. */ - subst_info quiet (tf_none, NULL_TREE); + sat_info quiet (tf_none, NULL_TREE); tree result = satisfy_constraint_expression (check, NULL_TREE, quiet); if (result == error_mark_node && (complain & tf_error)) - { - /* Replay the error with re-normalized requirements. */ - subst_info noisy (tf_warning_or_error, NULL_TREE); - satisfy_constraint_expression (check, NULL_TREE, noisy); - } + { + /* Replay the error with re-normalized requirements. */ + sat_info noisy (tf_warning_or_error, NULL_TREE); + satisfy_constraint_expression (check, NULL_TREE, noisy); + } return result; } @@ -3505,7 +3546,7 @@ diagnose_nested_requirement (tree req, tree args) /* Quietly check for satisfaction first. We can elaborate details later if needed. */ tree norm = TREE_TYPE (req); - subst_info info (tf_none, NULL_TREE); + sat_info info (tf_none, NULL_TREE); tree result = satisfy_constraint (norm, args, info); if (result == boolean_true_node) return; @@ -3516,7 +3557,8 @@ diagnose_nested_requirement (tree req, tree args) { /* Replay the substitution error. */ inform (loc, "nested requirement %qE is not satisfied, because", expr); - subst_info noisy (tf_warning_or_error, NULL_TREE); + sat_info noisy (tf_warning_or_error, NULL_TREE); + noisy.diagnose_unsatisfaction = true; satisfy_constraint_expression (expr, args, noisy); } else @@ -3660,11 +3702,12 @@ diagnose_constraints (location_t loc, tree t, tree args) if (concepts_diagnostics_max_depth == 0) return; - /* Replay satisfaction, but diagnose errors. */ + /* Replay satisfaction, but diagnose unsatisfaction. */ + sat_info noisy (tf_warning_or_error, NULL_TREE, /*diagnose_unsat=*/true); if (!args) - constraint_satisfaction_value (t, tf_warning_or_error); + constraint_satisfaction_value (t, noisy); else - constraint_satisfaction_value (t, args, tf_warning_or_error); + constraint_satisfaction_value (t, args, noisy); static bool suggested_p; if (concepts_diagnostics_max_depth_exceeded_p diff --git a/gcc/testsuite/g++.dg/concepts/pr94252.C b/gcc/testsuite/g++.dg/concepts/pr94252.C index 56ce5f88bad..b0457037ede 100644 --- a/gcc/testsuite/g++.dg/concepts/pr94252.C +++ b/gcc/testsuite/g++.dg/concepts/pr94252.C @@ -16,6 +16,7 @@ static_assert(requires(S o, int i) { template concept c = requires (T t) { requires (T)5; }; // { dg-error "has type .int." } +// { dg-bogus "not satisfied" "" { target *-*-* } .-1 } int foo() diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-nonbool3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-nonbool3.C new file mode 100644 index 00000000000..2a2af54847b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-nonbool3.C @@ -0,0 +1,5 @@ +// { dg-do compile { target c++20 } } + +template concept C = false || V || false; // { dg-error "has type 'int'" } +template int f() requires C; +int a = f<0>(); // { dg-error "no match" } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires18.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires18.C index a9b7720cc6c..9e45c586917 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-requires18.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires18.C @@ -4,7 +4,7 @@ template concept integer = __is_same_as(T, int); template -concept subst = requires (T x) { requires true; }; // { dg-error "parameter type .void." } +concept subst = requires (T x) { requires true; }; template concept c1 = requires { requires integer || subst; }; // { dg-message "in requirements" } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires21.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires21.C index bc38b893c68..8aead2fe2c5 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-requires21.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires21.C @@ -5,3 +5,4 @@ template constexpr bool is_same_v = __is_same (T, U); static_assert(is_same_v); +// { dg-bogus "evaluated to 'false" "" { target *-*-* } .-1 } From patchwork Fri Dec 4 21:33:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1411278 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gcc.gnu.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=ue9OHADw; dkim-atps=neutral Received: from sourceware.org (unknown [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CnmCf2NlDz9sWK for ; Sat, 5 Dec 2020 08:33:18 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 354F1389602C; Fri, 4 Dec 2020 21:33:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 354F1389602C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1607117593; bh=F+d6llEbMStL0EIxres7vZL7t/fxydeMCjOIv2LD2LM=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=ue9OHADwY9KH1Lr/lOgu2Lx2JhYnSTsDPENUQWzT2uoG6u1xnHwv46KTOglkgrLbN OEy+8m9kUtfqj7eRl58GASzPjX27SEFgEOAzbxfrmPGpOEvfBQn+4Lk7HvLjRwENdO u3Y768l95YIU3hAHXVA0aLHJEbK3VJxbDF/Yq7OQ= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [63.128.21.124]) by sourceware.org (Postfix) with ESMTP id 73DE1386EC29 for ; Fri, 4 Dec 2020 21:33:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 73DE1386EC29 Received: from mail-qk1-f198.google.com (mail-qk1-f198.google.com [209.85.222.198]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-194-TlkxHdKpOEeY-bjGKjpOaw-1; Fri, 04 Dec 2020 16:33:08 -0500 X-MC-Unique: TlkxHdKpOEeY-bjGKjpOaw-1 Received: by mail-qk1-f198.google.com with SMTP id b11so6470826qkk.10 for ; Fri, 04 Dec 2020 13:33:07 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=F+d6llEbMStL0EIxres7vZL7t/fxydeMCjOIv2LD2LM=; b=fgu25SCyQzueafz8rllaqxCLaebS35OTCnCsABIGT2T4Yzbb3TU8HV1k4zXikK+cNq wGVq2G2BdgawXvnG5/LEMjiRkPdKMOitbOI/kFKudrEILJa7QQd9vWRmfaztR0UvcXuA VrCvl0Pt5PU7aVcVF8EOZTHwtq4QnpY6h6TCr+0Gza2PBds9+nRV5tbwA9VH3vz4XWDe cop9e4+YjB6N8cBqf0zaQ8PvHM/yDzee39UcEG1xjQ1fCIu2zUR1sGcXwr7njUr0eQ5w vxpfMVe/hRdssjcTBPoCYEr1IuzAFVkhpyqoDT/nckehjdtymqOqoZYItz+PwMv2nVyt yK+g== X-Gm-Message-State: AOAM532yeZRZqlFEwK1wBclOEDUkDhdn+DFx0v3cIqaY5EOizQVQpXGl Ax2H4pdfaW7vzMpvjuOgaifPq2i0bK4Bb6bwcUP9Lnd4QphsY0wo6N7598d7vtknCWnaXJvfr4x yfli5yM9pYQNlhq5gZQs5H9p3IdslOMXhhC56ikHq5kHOcDrKGgOV55EURh9lKPFTfgc= X-Received: by 2002:a05:620a:22eb:: with SMTP id p11mr11376269qki.224.1607117587156; Fri, 04 Dec 2020 13:33:07 -0800 (PST) X-Google-Smtp-Source: ABdhPJwXZTKlIYm/3F+DHeT21NViHvetroPQeolnuHcmnrQzvQo7F/2C+RZJ4rQ6Ll5x5EvJ4Lbygg== X-Received: by 2002:a05:620a:22eb:: with SMTP id p11mr11376223qki.224.1607117586783; Fri, 04 Dec 2020 13:33:06 -0800 (PST) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id b14sm5731731qtx.36.2020.12.04.13.33.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Dec 2020 13:33:06 -0800 (PST) To: gcc-patches@gcc.gnu.org Subject: [PATCH 2/2] c++: Normalize nested-requirements twice at parse time [PR97093] Date: Fri, 4 Dec 2020 16:33:01 -0500 Message-Id: <20201204213301.1836322-2-ppalka@redhat.com> X-Mailer: git-send-email 2.29.2.404.ge67fbf927d In-Reply-To: <20201204213301.1836322-1-ppalka@redhat.com> References: <20201204213301.1836322-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-16.9 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_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) 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-Patchwork-Original-From: Patrick Palka via Gcc-patches From: Patrick Palka Reply-To: Patrick Palka Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" The re-normalization performed from diagnose_nested_requirement doesn't always work because we may have already lost the necessary template context that determines the set of in-scope template parameters used by the nested-requirement. This leads to normalization producing atoms that have incomplete/bogus parameter mappings, which breaks satisfaction. To fix this, we could just use the previously normalized form that we computed at parse time, but this normal form lacks the diagnostic information that leads to good error messages. Instead, this patch makes diagnose_nested_requirement normalize twice at parse time -- once without diagnostic information and once with -- so that routines can use the "regular" normal form when performing satisfaction quietly and the "diagnostic" normal form when performing satisfaction noisily. Moreover, this patch makes tsubst_nested_requirement always first perform satisfaction quietly so that the satisfaction cache can get consistently utilized. Finally, this patch also adds more stringent checking to build_parameter_mapping that would have caught the underlying bug sooner (and deterministically). gcc/cp/ChangeLog: PR c++/97093 * constraint.cc (parameter_mapping_equivalent_p): Add more stringent checking. Clarify comment. (tsubst_nested_requirement): Always perform satisfaction quietly first. If that yields an erroneous result, emit a context message and replay satisfaction noisily with the diagnostic normal form. (finish_nested_requirement): Normalize the constraint-expression twice, once with diagnostic information and once without. Store them in a TREE_LIST within the TREE_TYPE. (diagnose_nested_requirement): When replaying satisfaction, use the diagnostic normal form instead of renormalizing on the spot. gcc/testsuite/ChangeLog: PR c++/97093 * g++.dg/cpp2a/concepts-requires22.C: New test. --- gcc/cp/constraint.cc | 41 ++++++++++++------- .../g++.dg/cpp2a/concepts-requires22.C | 18 ++++++++ 2 files changed, 44 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires22.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 2be1a841535..c6d4d8e7e64 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -612,7 +612,8 @@ build_parameter_mapping (tree expr, tree args, tree decl) return map; } -/* True if the parameter mappings of two atomic constraints are equivalent. */ +/* True if the parameter mappings of two atomic constraints formed + from the same expression are equivalent. */ static bool parameter_mapping_equivalent_p (tree t1, tree t2) @@ -621,6 +622,7 @@ parameter_mapping_equivalent_p (tree t1, tree t2) tree map2 = ATOMIC_CONSTR_MAP (t2); while (map1 && map2) { + gcc_checking_assert (TREE_VALUE (map1) == TREE_VALUE (map2)); tree arg1 = TREE_PURPOSE (map1); tree arg2 = TREE_PURPOSE (map2); if (!template_args_equal (arg1, arg2)) @@ -628,6 +630,7 @@ parameter_mapping_equivalent_p (tree t1, tree t2) map1 = TREE_CHAIN (map1); map2 = TREE_CHAIN (map2); } + gcc_checking_assert (!map1 && !map2); return true; } @@ -2085,14 +2088,16 @@ tsubst_compound_requirement (tree t, tree args, subst_info info) static tree tsubst_nested_requirement (tree t, tree args, subst_info info) { - /* Ensure that we're in an evaluation context prior to satisfaction. */ - tree norm = TREE_TYPE (t); - tree result = satisfy_constraint (norm, args, - sat_info (info.complain, info.in_decl)); - if (result == error_mark_node && info.quiet ()) + /* Perform satisfaction quietly with the regular normal form. */ + sat_info quiet (tf_none, info.in_decl); + tree norm = TREE_VALUE (TREE_TYPE (t)); + tree diag_norm = TREE_PURPOSE (TREE_TYPE (t)); + tree result = satisfy_constraint (norm, args, quiet); + if (result == error_mark_node) { + /* Replay the error using the diagnostic normal form. */ sat_info noisy (tf_warning_or_error, info.in_decl); - satisfy_constraint (norm, args, noisy); + satisfy_constraint (diag_norm, args, noisy); } if (result != boolean_true_node) return error_mark_node; @@ -3139,10 +3144,15 @@ finish_compound_requirement (location_t loc, tree expr, tree type, bool noexcept tree finish_nested_requirement (location_t loc, tree expr) { - tree norm = normalize_constraint_expression (expr, false); + /* We need to normalize the constraints now, at parse time, while + we have the necessary template context. We normalize twice, + once without diagnostic information and once with, which we'll + later use during quiet and noisy satisfaction respectively. */ + tree norm = normalize_constraint_expression (expr, /*diag=*/false); + tree diag_norm = normalize_constraint_expression (expr, /*diag=*/true); - /* Build the constraint, saving its normalization as its type. */ - tree r = build1 (NESTED_REQ, norm, expr); + /* Build the constraint, saving its two normalizations as its type. */ + tree r = build1 (NESTED_REQ, build_tree_list (diag_norm, norm), expr); SET_EXPR_LOCATION (r, loc); return r; } @@ -3543,9 +3553,10 @@ diagnose_type_requirement (tree req, tree args, tree in_decl) static void diagnose_nested_requirement (tree req, tree args) { - /* Quietly check for satisfaction first. We can elaborate details - later if needed. */ - tree norm = TREE_TYPE (req); + /* Quietly check for satisfaction first using the regular normal form. + We can elaborate details later if needed. */ + tree norm = TREE_VALUE (TREE_TYPE (req)); + tree diag_norm = TREE_PURPOSE (TREE_TYPE (req)); sat_info info (tf_none, NULL_TREE); tree result = satisfy_constraint (norm, args, info); if (result == boolean_true_node) @@ -3555,11 +3566,11 @@ diagnose_nested_requirement (tree req, tree args) location_t loc = cp_expr_location (expr); if (diagnosing_failed_constraint::replay_errors_p ()) { - /* Replay the substitution error. */ + /* Replay the substitution error using the diagnostic normal form. */ inform (loc, "nested requirement %qE is not satisfied, because", expr); sat_info noisy (tf_warning_or_error, NULL_TREE); noisy.diagnose_unsatisfaction = true; - satisfy_constraint_expression (expr, args, noisy); + satisfy_constraint (diag_norm, args, noisy); } else inform (loc, "nested requirement %qE is not satisfied", expr); diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires22.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires22.C new file mode 100644 index 00000000000..5afcbbecbd5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires22.C @@ -0,0 +1,18 @@ +// PR c++/97093 +// { dg-do compile { target c++20 } } +// { dg-additional-options "-fconcepts-diagnostics-depth=3" } + +template +concept C = requires { + requires (X)x; // { dg-message "false" } + }; + +template +concept D = requires { + requires false || (X)x; // { dg-message "false" } + }; + +int main() { + static_assert(C); // { dg-error "failed" } + static_assert(D); // { dg-error "failed" } +}