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 [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 57A163854838 for ; Sun, 28 Feb 2021 17:59:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 57A163854838 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-3-q5gyCNkhMGafEzPJzvVzQQ-1; Sun, 28 Feb 2021 12:59:43 -0500 X-MC-Unique: q5gyCNkhMGafEzPJzvVzQQ-1 Received: by mail-qk1-f198.google.com with SMTP id m16so12111762qkh.20 for ; Sun, 28 Feb 2021 09:59:43 -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=2Oai+BqUfbprmfRmqWDdH4KWOPzZ3lu1WaYA3xNxSUQ=; b=g7GzGE2tusY/dWlI30K6pkGT7b6yXG04dsmYmPBRLEYzd6uS3ls4f9BRLqaR8h2xyL /Eq+nlDV/AgkT+gmjv/bKEHXV2cgxaGR+DL18QhxNa2N/dAy7ayPqGz7+mLAZamjuNwB ljl1Z6EmEV0zO6waMGm68RSWhLXxyaDrIK++2xSXfHshkpWikV6auPIv7uJaB68+cIGg R1cuJ4nX5cvXU7+bzB+zQ/GI4k8ieTlvoOZC8gvV1chaAOq3XhgNOdgXJgtIRBlLpLuo NJQ4ue9zI07SLpUVMZ+Iy+qr4d4bQILLbTOp3TuIuj8X0nh41wFSIN5ePA9XTWiM5MRp 4Wpg== X-Gm-Message-State: AOAM531bT+oom9pcLsACZFI2NJUzRQUUKOvICm7eCV6moAkhrXHJPHhS hCMKb4jjr6sx1taW63ZwTb82zWLRlgS0M/fZXeamm5SPuE+o6CoCbcVE9J9PVVc9k1OAQslzkV8 ii41SbHMawqVK4ANvmG1ept6vkgNgb8jyS7PRwLPl/PRadgaasK5wrCYMduiK5TGWsjQ= X-Received: by 2002:a37:9e50:: with SMTP id h77mr9719404qke.138.1614535181813; Sun, 28 Feb 2021 09:59:41 -0800 (PST) X-Google-Smtp-Source: ABdhPJzeKP7lTC1GpoCwL0fXYmPzqT+avywwLxrSjDdJtEarC1/SLXKAeDHE6baPsresy13n5gAIhQ== X-Received: by 2002:a37:9e50:: with SMTP id h77mr9719358qke.138.1614535180939; Sun, 28 Feb 2021 09:59:40 -0800 (PST) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id 15sm9564054qty.65.2021.02.28.09.59.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 28 Feb 2021 09:59:40 -0800 (PST) From: Patrick Palka To: gcc-patches@gcc.gnu.org Subject: [PATCH 6/6] c++: Consolidate REQUIRES_EXPR evaluation/diagnostic routines Date: Sun, 28 Feb 2021 12:59:38 -0500 Message-Id: <20210228175938.1286271-1-ppalka@redhat.com> X-Mailer: git-send-email 2.31.0.rc0 In-Reply-To: <20210208190352.1475602-1-ppalka@redhat.com> References: <20210208190352.1475602-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII" X-Spam-Status: No, score=-15.1 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, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, URIBL_SBL, URIBL_SBL_A 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-List-Received-Date: Sun, 28 Feb 2021 17:59:48 -0000 This folds the diagnose_requires_expr routines into the corresponding tsubst_requires_expr ones. This is achieved by making the latter routines take a sat_info instead of a subst_info, and assigning the appropriate meanings to the flags sat_info::noisy and sat_info::diagnose_unsatisfaction_p during tsubst_requires_expr: info.noisy() controls whether to diagnose invalid types and expressions inside the requires-expression, and info.diagnose_unsatisfaction_p() controls whether to diagnose why the requires-expression evaluates to false. gcc/cp/ChangeLog: * constraint.cc (struct sat_info): Document the different meanings of noisy() and diagnose_unsatisfaction_p() during satisfaction and requires-expression evaluation. (tsubst_valid_expression_requirement): Take a sat_info instead of a subst_info. Perform the substitution quietly first. Fold in error-replaying code from diagnose_valid_expression. (tsubst_simple_requirement): Take a sat_info instead of a subst_info. (tsubst_type_requirement_1): New. Fold in error-replaying code from diagnose_valid_type. (tsubst_type_requirement): Use the above. Take a sat_info instead of a subst_info. (tsubst_compound_requirement): Likewise. Fold in error-replaying code from diagnose_compound_requirement. (tsubst_nested_requirement): Take a sat_info instead of a subst_info. Fold in error-replaying code from diagnose_nested_requirement. (tsubst_requirement): Take a sat_info instead of a subst_info. (tsubst_requires_expr): Split into two versions, one that takes a sat_info argument and another that takes a complain and in_decl argument. Remove outdated documentation. Document the effects of the sat_info argument. (diagnose_trait_expr): Make static. Take a template argument vector instead of a parameter mapping. (diagnose_valid_expression): Remove. (diagnose_valid_type): Remove. (diagnose_simple_requirement): Remove. (diagnose_compound_requirement): Remove. (diagnose_type_requirement): Remove. (diagnose_nested_requirement): Remove. (diagnose_requirement): Remove. (diagnose_requires_expr): Remove. (diagnose_atomic_constraint): Take a sat_info instead of a subst_info. Adjust call to diagnose_trait_expr. Call tsubst_requires_expr instead of diagnose_requires_expr. (diagnose_constraints): Call tsubst_requires_expr instead of diagnose_requires_expr. gcc/testsuite/ChangeLog: * g++.dg/concepts/diagnostic1.C: Adjust expected diagnostics now that we diagnose only the first failed requirement of a requires-expression. --- gcc/cp/constraint.cc | 416 +++++++++----------- gcc/testsuite/g++.dg/concepts/diagnostic1.C | 2 +- 2 files changed, 179 insertions(+), 239 deletions(-) diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index cf319b34da0..31f32c25dfe 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -100,17 +100,30 @@ struct 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() controls whether to explain why - a constraint is not satisfied. - - The entrypoints to satisfaction for which we set noisy+unsat are - diagnose_constraints and diagnose_nested_requirement. The entrypoint for - which we set noisy-unsat is the replay inside constraint_satisfaction_value. - From constraints_satisfied_p, we enter satisfaction quietly (both flags - cleared). */ + During 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() controls whether to explain why + a constraint is not satisfied. + - We enter satisfaction with noisy+unsat from diagnose_constraints. + - We enter satisfaction with noisy-unsat from the replay inside + constraint_satisfaction_value. + - We enter satisfaction quietly (both flags cleared) from + constraints_satisfied_p. + + During evaluation of a requires-expression: + - The flag noisy() controls whether to diagnose ill-formed types and + expressions inside its requirements. + - The flag diagnose_unsatisfaction_p() controls whether to explain why + the requires-expression evaluates to false. + - We enter tsubst_requires_expr with noisy+unsat from diagnose_constraints + and from diagnose_atomic_constraint. + - We enter tsubst_requires_expr with noisy-unsat from + cp_parser_requires_expression when processing a requires-expression that + appears outside a template. + - We enter tsubst_requires_expr quietly (both flags cleared) when + substituting through a requires-expression as part of template + instantiation. */ struct sat_info : subst_info { @@ -1926,22 +1939,44 @@ hash_placeholder_constraint (tree c) return val; } -/* Substitute through the simple requirement. */ +/* Substitute through the expression of a simple requirement or + compound requirement. */ static tree -tsubst_valid_expression_requirement (tree t, tree args, subst_info info) +tsubst_valid_expression_requirement (tree t, tree args, sat_info info) { - tree r = tsubst_expr (t, args, info.complain, info.in_decl, false); - if (convert_to_void (r, ICV_STATEMENT, info.complain) == error_mark_node) - return error_mark_node; - return r; + tree r = tsubst_expr (t, args, tf_none, info.in_decl, false); + if (convert_to_void (r, ICV_STATEMENT, tf_none) != error_mark_node) + return r; + + if (info.diagnose_unsatisfaction_p ()) + { + location_t loc = cp_expr_loc_or_input_loc (t); + if (diagnosing_failed_constraint::replay_errors_p ()) + { + inform (loc, "the required expression %qE is invalid, because", t); + if (r == error_mark_node) + tsubst_expr (t, args, info.complain, info.in_decl, false); + else + convert_to_void (r, ICV_STATEMENT, info.complain); + } + else + inform (loc, "the required expression %qE is invalid", t); + } + else if (info.noisy ()) + { + r = tsubst_expr (t, args, info.complain, info.in_decl, false); + convert_to_void (r, ICV_STATEMENT, info.complain); + } + + return error_mark_node; } /* Substitute through the simple requirement. */ static tree -tsubst_simple_requirement (tree t, tree args, subst_info info) +tsubst_simple_requirement (tree t, tree args, sat_info info) { tree t0 = TREE_OPERAND (t, 0); tree expr = tsubst_valid_expression_requirement (t0, args, info); @@ -1950,13 +1985,41 @@ tsubst_simple_requirement (tree t, tree args, subst_info info) return boolean_true_node; } +/* Subroutine of tsubst_type_requirement that performs the actual substitution + and diagnosing. Also used by tsubst_compound_requirement. */ + +static tree +tsubst_type_requirement_1 (tree t, tree args, sat_info info, location_t loc) +{ + tree r = tsubst (t, args, tf_none, info.in_decl); + if (r != error_mark_node) + return r; + + if (info.diagnose_unsatisfaction_p ()) + { + if (diagnosing_failed_constraint::replay_errors_p ()) + { + /* Replay the substitution error. */ + inform (loc, "the required type %qT is invalid, because", t); + tsubst (t, args, info.complain, info.in_decl); + } + else + inform (loc, "the required type %qT is invalid", t); + } + else if (info.noisy ()) + tsubst (t, args, info.complain, info.in_decl); + + return error_mark_node; +} + + /* Substitute through the type requirement. */ static tree -tsubst_type_requirement (tree t, tree args, subst_info info) +tsubst_type_requirement (tree t, tree args, sat_info info) { tree t0 = TREE_OPERAND (t, 0); - tree type = tsubst (t0, args, info.complain, info.in_decl); + tree type = tsubst_type_requirement_1 (t0, args, info, EXPR_LOCATION (t)); if (type == error_mark_node) return error_mark_node; return boolean_true_node; @@ -2013,7 +2076,7 @@ expression_convertible_p (tree expr, tree type, subst_info info) /* Substitute through the compound requirement. */ static tree -tsubst_compound_requirement (tree t, tree args, subst_info info) +tsubst_compound_requirement (tree t, tree args, sat_info info) { tree t0 = TREE_OPERAND (t, 0); tree t1 = TREE_OPERAND (t, 1); @@ -2021,13 +2084,20 @@ tsubst_compound_requirement (tree t, tree args, subst_info info) if (expr == error_mark_node) return error_mark_node; + location_t loc = cp_expr_loc_or_input_loc (expr); + /* Check the noexcept condition. */ bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t); if (noexcept_p && !expr_noexcept_p (expr, tf_none)) - return error_mark_node; + { + if (info.diagnose_unsatisfaction_p ()) + inform (loc, "%qE is not %", expr); + else + return error_mark_node; + } /* Substitute through the type expression, if any. */ - tree type = tsubst (t1, args, info.complain, info.in_decl); + tree type = tsubst_type_requirement_1 (t1, args, info, EXPR_LOCATION (t)); if (type == error_mark_node) return error_mark_node; @@ -2039,29 +2109,76 @@ tsubst_compound_requirement (tree t, tree args, subst_info info) if (tree placeholder = type_uses_auto (type)) { if (!type_deducible_p (expr, type, placeholder, args, quiet)) - return error_mark_node; + { + if (info.diagnose_unsatisfaction_p ()) + { + if (diagnosing_failed_constraint::replay_errors_p ()) + { + inform (loc, + "%qE does not satisfy return-type-requirement, " + "because", t0); + /* Further explain the reason for the error. */ + type_deducible_p (expr, type, placeholder, args, info); + } + else + inform (loc, + "%qE does not satisfy return-type-requirement", t0); + } + return error_mark_node; + } } else if (!expression_convertible_p (expr, type, quiet)) - return error_mark_node; + { + if (info.diagnose_unsatisfaction_p ()) + { + if (diagnosing_failed_constraint::replay_errors_p ()) + { + inform (loc, "cannot convert %qE to %qT because", t0, type); + /* Further explain the reason for the error. */ + expression_convertible_p (expr, type, info); + } + else + inform (loc, "cannot convert %qE to %qT", t0, type); + } + return error_mark_node; + } } return boolean_true_node; } +/* Substitute through the nested requirement. */ + static tree -tsubst_nested_requirement (tree t, tree args, subst_info info) +tsubst_nested_requirement (tree t, tree args, sat_info info) { sat_info quiet (tf_none, info.in_decl); tree result = constraint_satisfaction_value (t, args, quiet); - if (result != boolean_true_node) - return error_mark_node; - return boolean_true_node; + if (result == boolean_true_node) + return boolean_true_node; + + if (result == boolean_false_node + && info.diagnose_unsatisfaction_p ()) + { + tree expr = TREE_OPERAND (t, 0); + location_t loc = cp_expr_location (t); + if (diagnosing_failed_constraint::replay_errors_p ()) + { + /* Replay the substitution error. */ + inform (loc, "nested requirement %qE is not satisfied, because", expr); + constraint_satisfaction_value (t, args, info); + } + else + inform (loc, "nested requirement %qE is not satisfied", expr); + } + + return error_mark_node; } /* Substitute ARGS into the requirement T. */ static tree -tsubst_requirement (tree t, tree args, subst_info info) +tsubst_requirement (tree t, tree args, sat_info info) { iloc_sentinel loc_s (cp_expr_location (t)); switch (TREE_CODE (t)) @@ -2151,30 +2268,22 @@ tsubst_constraint_variables (tree t, tree args, subst_info info) in its requirements ... In such cases, the expression evaluates to false; it does not cause the program to be ill-formed. - However, there are cases where substitution must produce a - new requires-expression, that is not a template constraint. - For example: + When substituting through a REQUIRES_EXPR as part of template + instantiation, we call this routine with info.quiet() true. - template - class X { - template - static constexpr bool var = requires (U u) { T::fn(u); }; - }; + When evaluating a REQUIRES_EXPR that appears outside a template in + cp_parser_requires_expression, we call this routine with + info.noisy() true. - In the instantiation of X (assuming Y defines fn), then the - instantiated requires-expression would include Y::fn(u). If any - substitution in the requires-expression fails, we can immediately - fold the expression to false, as would be the case e.g., when - instantiation X. */ + Finally, when diagnosing unsatisfaction from diagnose_atomic_constraint + and when diagnosing a false REQUIRES_EXPR via diagnose_constraints, + we call this routine with info.diagnose_unsatisfaction_p() true. */ -tree -tsubst_requires_expr (tree t, tree args, - tsubst_flags_t complain, tree in_decl) +static tree +tsubst_requires_expr (tree t, tree args, sat_info info) { local_specialization_stack stack (lss_copy); - subst_info info (complain, in_decl); - /* A requires-expression is an unevaluated context. */ cp_unevaluated u; @@ -2186,7 +2295,7 @@ tsubst_requires_expr (tree t, tree args, checked out of order, so instead just remember the template arguments and wait until we can substitute them all at once. */ t = copy_node (t); - REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, complain); + REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain); return t; } @@ -2207,6 +2316,16 @@ tsubst_requires_expr (tree t, tree args, return boolean_true_node; } +/* Public wrapper for the above. */ + +tree +tsubst_requires_expr (tree t, tree args, + tsubst_flags_t complain, tree in_decl) +{ + sat_info info (complain, in_decl); + return tsubst_requires_expr (t, args, info); +} + /* Substitute ARGS into the constraint information CI, producing a new constraint record. */ @@ -2790,7 +2909,7 @@ get_mapped_args (tree map) return args; } -static void diagnose_atomic_constraint (tree, tree, tree, subst_info); +static void diagnose_atomic_constraint (tree, tree, tree, sat_info); /* Compute the satisfaction of an atomic constraint. */ @@ -3440,11 +3559,10 @@ get_constraint_error_location (tree t) /* Emit a diagnostic for a failed trait. */ -void -diagnose_trait_expr (tree expr, tree map) +static void +diagnose_trait_expr (tree expr, tree args) { location_t loc = cp_expr_location (expr); - tree args = get_mapped_args (map); /* Build a "fake" version of the instantiated trait, so we can get the instantiated types from result. */ @@ -3524,192 +3642,11 @@ diagnose_trait_expr (tree expr, tree map) } } -static tree -diagnose_valid_expression (tree expr, tree args, tree in_decl) -{ - tree result = tsubst_expr (expr, args, tf_none, in_decl, false); - if (result != error_mark_node - && convert_to_void (result, ICV_STATEMENT, tf_none) != error_mark_node) - return result; - - location_t loc = cp_expr_loc_or_input_loc (expr); - if (diagnosing_failed_constraint::replay_errors_p ()) - { - /* Replay the substitution error. */ - inform (loc, "the required expression %qE is invalid, because", expr); - if (result == error_mark_node) - tsubst_expr (expr, args, tf_error, in_decl, false); - else - convert_to_void (result, ICV_STATEMENT, tf_error); - } - else - inform (loc, "the required expression %qE is invalid", expr); - - return error_mark_node; -} - -static tree -diagnose_valid_type (tree type, tree args, tree in_decl) -{ - tree result = tsubst (type, args, tf_none, in_decl); - if (result != error_mark_node) - return result; - - location_t loc = cp_expr_loc_or_input_loc (type); - if (diagnosing_failed_constraint::replay_errors_p ()) - { - /* Replay the substitution error. */ - inform (loc, "the required type %qT is invalid, because", type); - tsubst (type, args, tf_error, in_decl); - } - else - inform (loc, "the required type %qT is invalid", type); - - return error_mark_node; -} - -static void -diagnose_simple_requirement (tree req, tree args, tree in_decl) -{ - diagnose_valid_expression (TREE_OPERAND (req, 0), args, in_decl); -} - -static void -diagnose_compound_requirement (tree req, tree args, tree in_decl) -{ - tree expr = TREE_OPERAND (req, 0); - expr = diagnose_valid_expression (expr, args, in_decl); - if (expr == error_mark_node) - return; - - location_t loc = cp_expr_loc_or_input_loc (expr); - - /* Check the noexcept condition. */ - if (COMPOUND_REQ_NOEXCEPT_P (req) && !expr_noexcept_p (expr, tf_none)) - inform (loc, "%qE is not %", expr); - - tree type = TREE_OPERAND (req, 1); - type = diagnose_valid_type (type, args, in_decl); - if (type == error_mark_node) - return; - - if (type) - { - subst_info quiet (tf_none, in_decl); - subst_info noisy (tf_error, in_decl); - - /* Check the expression against the result type. */ - if (tree placeholder = type_uses_auto (type)) - { - if (!type_deducible_p (expr, type, placeholder, args, quiet)) - { - tree orig_expr = TREE_OPERAND (req, 0); - if (diagnosing_failed_constraint::replay_errors_p ()) - { - inform (loc, - "%qE does not satisfy return-type-requirement, " - "because", orig_expr); - /* Further explain the reason for the error. */ - type_deducible_p (expr, type, placeholder, args, noisy); - } - else - inform (loc, "%qE does not satisfy return-type-requirement", - orig_expr); - } - } - else if (!expression_convertible_p (expr, type, quiet)) - { - tree orig_expr = TREE_OPERAND (req, 0); - if (diagnosing_failed_constraint::replay_errors_p ()) - { - inform (loc, "cannot convert %qE to %qT because", orig_expr, type); - /* Further explain the reason for the error. */ - expression_convertible_p (expr, type, noisy); - } - else - inform (loc, "cannot convert %qE to %qT", orig_expr, type); - } - } -} - -static void -diagnose_type_requirement (tree req, tree args, tree in_decl) -{ - tree type = TREE_OPERAND (req, 0); - diagnose_valid_type (type, args, in_decl); -} - -static void -diagnose_nested_requirement (tree req, tree args) -{ - /* Quietly check for satisfaction first. */ - sat_info quiet (tf_none, NULL_TREE); - tree result = satisfy_nondeclaration_constraints (req, args, quiet); - if (result == boolean_true_node) - return; - - tree expr = TREE_OPERAND (req, 0); - location_t loc = cp_expr_location (expr); - if (diagnosing_failed_constraint::replay_errors_p ()) - { - /* Replay the substitution error with re-normalized requirements. */ - inform (loc, "nested requirement %qE is not satisfied, because", expr); - - sat_info noisy (tf_warning_or_error, NULL_TREE, /*diag_unsat=*/true); - satisfy_nondeclaration_constraints (req, args, noisy); - } - else - inform (loc, "nested requirement %qE is not satisfied", expr); - -} - -static void -diagnose_requirement (tree req, tree args, tree in_decl) -{ - iloc_sentinel loc_s (cp_expr_location (req)); - switch (TREE_CODE (req)) - { - case SIMPLE_REQ: - return diagnose_simple_requirement (req, args, in_decl); - case COMPOUND_REQ: - return diagnose_compound_requirement (req, args, in_decl); - case TYPE_REQ: - return diagnose_type_requirement (req, args, in_decl); - case NESTED_REQ: - return diagnose_nested_requirement (req, args); - default: - gcc_unreachable (); - } -} - -static void -diagnose_requires_expr (tree expr, tree map, tree in_decl) -{ - local_specialization_stack stack (lss_copy); - tree parms = TREE_OPERAND (expr, 0); - tree body = TREE_OPERAND (expr, 1); - tree args = get_mapped_args (map); - - cp_unevaluated u; - subst_info info (tf_warning_or_error, NULL_TREE); - tree vars = tsubst_constraint_variables (parms, args, info); - if (vars == error_mark_node) - return; - - tree p = body; - while (p) - { - tree req = TREE_VALUE (p); - diagnose_requirement (req, args, in_decl); - p = TREE_CHAIN (p); - } -} - /* Diagnose a substitution failure in the atomic constraint T when applied with the instantiated parameter mapping MAP. */ static void -diagnose_atomic_constraint (tree t, tree map, tree result, subst_info info) +diagnose_atomic_constraint (tree t, tree map, 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. */ @@ -3730,13 +3667,16 @@ diagnose_atomic_constraint (tree t, tree map, tree result, subst_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: - diagnose_trait_expr (expr, map); + diagnose_trait_expr (expr, args); break; case REQUIRES_EXPR: - diagnose_requires_expr (expr, map, info.in_decl); + gcc_checking_assert (info.diagnose_unsatisfaction_p ()); + info.in_decl = NULL_TREE; + tsubst_requires_expr (expr, args, info); break; default: if (!same_type_p (TREE_TYPE (result), boolean_type_node)) @@ -3807,7 +3747,7 @@ diagnose_constraints (location_t loc, tree t, tree args) { gcc_assert (!args); ++current_constraint_diagnosis_depth; - diagnose_requires_expr (t, /*map=*/NULL_TREE, /*in_decl=*/NULL_TREE); + tsubst_requires_expr (t, /*args=*/NULL_TREE, noisy); --current_constraint_diagnosis_depth; } else diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic1.C b/gcc/testsuite/g++.dg/concepts/diagnostic1.C index 29c78c4c730..23bd592411e 100644 --- a/gcc/testsuite/g++.dg/concepts/diagnostic1.C +++ b/gcc/testsuite/g++.dg/concepts/diagnostic1.C @@ -8,7 +8,7 @@ concept bool SameAs = __is_same_as(T, U); template concept bool R1 = requires (T& t) { // { dg-message "in requirements" } { t.begin() } -> T; // { dg-error "no match" } - { t.end() } -> SameAs; // { dg-message "does not satisfy" } + { t.end() } -> SameAs; }; template -- 2.31.0.rc0