From patchwork Wed Mar 29 02:32:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathaniel Shead X-Patchwork-Id: 1762532 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: legolas.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=kAy0inzK; 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 ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PmVx41nSCz1yYk for ; Wed, 29 Mar 2023 13:34:00 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 28298384F027 for ; Wed, 29 Mar 2023 02:33:58 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 28298384F027 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1680057238; bh=kKGxCIdByKmk4KA9+fEWCTPedR1wDfMgQMFJWmYHApw=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=kAy0inzKs9Ql3exoOQSHp004g75i4TTiuQoqO7Luhr0dSfpe05NG16YQKSoQw7vGZ zWuYJ6RrGOz9zpasRB5gXYwSF1KKdT756XAp7eX87AKzvXhmQbZm7AMM1qtSquz+tu Z5w3lGz7c4TLcXsdSU92671MMAJxRoAb+aMH90a0= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pl1-x634.google.com (mail-pl1-x634.google.com [IPv6:2607:f8b0:4864:20::634]) by sourceware.org (Postfix) with ESMTPS id 5969A3858C50 for ; Wed, 29 Mar 2023 02:33:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5969A3858C50 Received: by mail-pl1-x634.google.com with SMTP id k2so13560200pll.8 for ; Tue, 28 Mar 2023 19:33:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680057198; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=kKGxCIdByKmk4KA9+fEWCTPedR1wDfMgQMFJWmYHApw=; b=zDyZxAv8ORxfhWq2ijLI7bdCjw/9rrbJHhxG4cTvWufFf0ZY7+nv7jTRcAC013+BI1 HxG1r4gyDVfXMKr+NiQOSHvoFdQOnqYux8vnmyt3qC0gj+6mM8WROseGi35qwwEZIBng f3HVDP64JdxyN+hSiHlVbxl3SbJQlia1fU4rT2CQGl1kB5m0qD2/aaThQIhnlYmdKqg0 ZbjTMPBmonvH9R05Av7w3KXZdIbGD7uInV+DeK/aaUMy33UW4w3qkYw8gtfKZ5M1Q4Pp UIqV2rDogFgHYZxYgZTqcJWG9DzwR/wbFLtXBgpHqALAQ6sE++jNLzkUNC8BTX5GTSWz cu1Q== X-Gm-Message-State: AO0yUKVwHazuWIsUUERS92RPM793D/VL227rF3f8/qiWCjWNjmIvDn5D b1ItlcXQl0b1AwhWpy4Tdu8cPcmnKGo= X-Google-Smtp-Source: AK7set/sHoa43yjYrmVMfQsiaCz2i5Kl3YM0tl4k6ZN2SbPvIO8KRoanKcBZrPNJfPbzcjpvqFwM7A== X-Received: by 2002:a05:6a20:49a4:b0:da:834d:edd with SMTP id fs36-20020a056a2049a400b000da834d0eddmr16354542pzb.34.1680057197979; Tue, 28 Mar 2023 19:33:17 -0700 (PDT) Received: from Thaum.localdomain (125-209-144-50.tpgi.com.au. [125.209.144.50]) by smtp.gmail.com with ESMTPSA id r1-20020a62e401000000b005a8ba70315bsm21811004pfh.6.2023.03.28.19.33.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Mar 2023 19:33:17 -0700 (PDT) To: gcc-patches@gcc.gnu.org Cc: Nathaniel Shead Subject: [PATCH v2 1/3] c++: Track lifetimes in constant evaluation [PR70331, PR96630, PR98675] Date: Wed, 29 Mar 2023 13:32:56 +1100 Message-Id: <20230329023258.13487-2-nathanieloshead@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230329023258.13487-1-nathanieloshead@gmail.com> References: <20230329023258.13487-1-nathanieloshead@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-12.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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: Nathaniel Shead via Gcc-patches From: Nathaniel Shead Reply-To: Nathaniel Shead Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This adds rudimentary lifetime tracking in C++ constexpr contexts, allowing the compiler to report errors with using values after their backing has gone out of scope. We don't yet handle other ways of ending lifetimes (e.g. explicit destructor calls). PR c++/96630 PR c++/98675 PR c++/70331 gcc/cp/ChangeLog: * constexpr.cc (constexpr_global_ctx::put_value): Mark value as in lifetime. (constexpr_global_ctx::remove_value): Mark value as expired. (cxx_eval_call_expression): Remove comment that is no longer applicable. (non_const_var_error): Add check for expired values. (cxx_eval_constant_expression): Add checks for expired values. Forget local variables at end of bind expressions. Forget temporaries at end of cleanup points. * cp-tree.h (struct lang_decl_base): New flag to track expired values in constant evaluation. (DECL_EXPIRED_P): Access the new flag. (SET_DECL_EXPIRED_P): Modify the new flag. * module.cc (trees_out::lang_decl_bools): Write out the new flag. (trees_in::lang_decl_bools): Read in the new flag. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/constexpr-ice20.C: Update error raised by test. * g++.dg/cpp1y/constexpr-lifetime1.C: New test. * g++.dg/cpp1y/constexpr-lifetime2.C: New test. * g++.dg/cpp1y/constexpr-lifetime3.C: New test. * g++.dg/cpp1y/constexpr-lifetime4.C: New test. * g++.dg/cpp1y/constexpr-lifetime5.C: New test. Signed-off-by: Nathaniel Shead --- gcc/cp/constexpr.cc | 69 +++++++++++++++---- gcc/cp/cp-tree.h | 10 ++- gcc/cp/module.cc | 2 + gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C | 2 +- .../g++.dg/cpp1y/constexpr-lifetime1.C | 13 ++++ .../g++.dg/cpp1y/constexpr-lifetime2.C | 20 ++++++ .../g++.dg/cpp1y/constexpr-lifetime3.C | 13 ++++ .../g++.dg/cpp1y/constexpr-lifetime4.C | 11 +++ .../g++.dg/cpp1y/constexpr-lifetime5.C | 11 +++ 9 files changed, 137 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 3de60cfd0f8..bdbc12144a7 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -1185,10 +1185,22 @@ public: void put_value (tree t, tree v) { bool already_in_map = values.put (t, v); + if (!already_in_map && DECL_P (t)) + { + if (!DECL_LANG_SPECIFIC (t)) + retrofit_lang_decl (t); + if (DECL_LANG_SPECIFIC (t)) + SET_DECL_EXPIRED_P (t, false); + } if (!already_in_map && modifiable) modifiable->add (t); } - void remove_value (tree t) { values.remove (t); } + void remove_value (tree t) + { + if (DECL_P (t) && DECL_LANG_SPECIFIC (t)) + SET_DECL_EXPIRED_P (t, true); + values.remove (t); + } }; /* Helper class for constexpr_global_ctx. In some cases we want to avoid @@ -3157,10 +3169,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, for (tree save_expr : save_exprs) ctx->global->remove_value (save_expr); - /* Remove the parms/result from the values map. Is it worth - bothering to do this when the map itself is only live for - one constexpr evaluation? If so, maybe also clear out - other vars from call, maybe in BIND_EXPR handling? */ + /* Remove the parms/result from the values map. */ ctx->global->remove_value (res); for (tree parm = parms; parm; parm = TREE_CHAIN (parm)) ctx->global->remove_value (parm); @@ -5708,6 +5717,13 @@ non_const_var_error (location_t loc, tree r, bool fundef_p) inform (DECL_SOURCE_LOCATION (r), "allocated here"); return; } + if (DECL_EXPIRED_P (r)) + { + if (constexpr_error (loc, fundef_p, "accessing object outside its " + "lifetime")) + inform (DECL_SOURCE_LOCATION (r), "declared here"); + return; + } if (!constexpr_error (loc, fundef_p, "the value of %qD is not usable in " "a constant expression", r)) return; @@ -7048,6 +7064,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = build_constructor (TREE_TYPE (t), NULL); TREE_CONSTANT (r) = true; } + else if (DECL_EXPIRED_P (t)) + { + if (!ctx->quiet) + non_const_var_error (loc, r, /*fundef_p*/false); + *non_constant_p = true; + break; + } else if (ctx->strict) r = decl_really_constant_value (t, /*unshare_p=*/false); else @@ -7093,7 +7116,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, else { if (!ctx->quiet) - error ("%qE is not a constant expression", t); + { + if (DECL_EXPIRED_P (r)) + { + error_at (loc, "accessing object outside its lifetime"); + inform (DECL_SOURCE_LOCATION (r), "declared here"); + } + else + error_at (loc, "%qE is not a constant expression", t); + } *non_constant_p = true; } break; @@ -7315,17 +7346,28 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, auto_vec cleanups; vec *prev_cleanups = ctx->global->cleanups; ctx->global->cleanups = &cleanups; - r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), + + auto_vec save_exprs; + constexpr_ctx new_ctx = *ctx; + new_ctx.save_exprs = &save_exprs; + + r = cxx_eval_constant_expression (&new_ctx, TREE_OPERAND (t, 0), lval, non_constant_p, overflow_p, jump_target); + ctx->global->cleanups = prev_cleanups; unsigned int i; tree cleanup; /* Evaluate the cleanups. */ FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup) - cxx_eval_constant_expression (ctx, cleanup, vc_discard, + cxx_eval_constant_expression (&new_ctx, cleanup, vc_discard, non_constant_p, overflow_p); + + /* Forget SAVE_EXPRs and TARGET_EXPRs created by this + full-expression. */ + for (tree save_expr : save_exprs) + ctx->global->remove_value (save_expr); } break; @@ -7831,10 +7873,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, non_constant_p, overflow_p, jump_target); case BIND_EXPR: - return cxx_eval_constant_expression (ctx, BIND_EXPR_BODY (t), - lval, - non_constant_p, overflow_p, - jump_target); + r = cxx_eval_constant_expression (ctx, BIND_EXPR_BODY (t), + lval, + non_constant_p, overflow_p, + jump_target); + for (tree decl = BIND_EXPR_VARS (t); decl; decl = DECL_CHAIN (decl)) + ctx->global->remove_value (decl); + return r; case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b74c18b03ad..3cc08da816f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2860,6 +2860,7 @@ struct GTY(()) lang_decl_base { unsigned concept_p : 1; /* applies to vars and functions */ unsigned var_declared_inline_p : 1; /* var */ unsigned dependent_init_p : 1; /* var */ + unsigned expired_p : 1; /* var or parm */ /* The following apply to VAR, FUNCTION, TYPE, CONCEPT, & NAMESPACE decls. */ @@ -2871,7 +2872,7 @@ struct GTY(()) lang_decl_base { /* VAR_DECL or FUNCTION_DECL has keyed decls. */ unsigned module_keyed_decls_p : 1; - /* 12 spare bits. */ + /* 11 spare bits. */ }; /* True for DECL codes which have template info and access. */ @@ -4366,6 +4367,13 @@ get_vec_init_expr (tree t) #define SET_DECL_DEPENDENT_INIT_P(NODE, X) \ (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.dependent_init_p = (X)) +/* Nonzero if NODE is a VAR_DECL, PARM_DECL, or FIELD_DECL that is within + its lifetime for constant evaluation purposes. */ +#define DECL_EXPIRED_P(NODE) \ + (DECL_LANG_SPECIFIC (NODE) && DECL_LANG_SPECIFIC (NODE)->u.base.expired_p) +#define SET_DECL_EXPIRED_P(NODE, X) \ + (DECL_LANG_SPECIFIC (NODE)->u.base.expired_p = (X)) + /* Nonzero if NODE is an artificial VAR_DECL for a C++17 structured binding declaration or one of VAR_DECLs for the user identifiers in it. */ #define DECL_DECOMPOSITION_P(NODE) \ diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index ac2fe66b080..7af43b5736d 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -5654,6 +5654,7 @@ trees_out::lang_decl_bools (tree t) WB (lang->u.base.concept_p); WB (lang->u.base.var_declared_inline_p); WB (lang->u.base.dependent_init_p); + WB (lang->u.base.expired_p); /* When building a header unit, everthing is marked as purview, (so we know which decls to write). But when we import them we do not want to mark them as in module purview. */ @@ -5728,6 +5729,7 @@ trees_in::lang_decl_bools (tree t) RB (lang->u.base.concept_p); RB (lang->u.base.var_declared_inline_p); RB (lang->u.base.dependent_init_p); + RB (lang->u.base.expired_p); RB (lang->u.base.module_purview_p); RB (lang->u.base.module_attach_p); if (VAR_OR_FUNCTION_DECL_P (t)) diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C index e2d4853a284..ebaa95e5324 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C @@ -4,4 +4,4 @@ typedef bool (*Function)(int); constexpr bool check(int x, Function p) { return p(x); } // { dg-message "in .constexpr. expansion of" } -static_assert(check(2, check), ""); // { dg-error "conversion|constant|in .constexpr. expansion of" } +static_assert(check(2, check), ""); // { dg-error "conversion|constant|lifetime|in .constexpr. expansion of" } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C new file mode 100644 index 00000000000..43aa7c974c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C @@ -0,0 +1,13 @@ +// PR c++/96630 +// { dg-do compile { target c++14 } } + +struct S { + int x = 0; + constexpr const int& get() const { return x; } +}; + +constexpr const int& test() { + auto local = S{}; // { dg-message "note: declared here" } + return local.get(); +} +constexpr int x = test(); // { dg-error "accessing object outside its lifetime" } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C new file mode 100644 index 00000000000..22cd919fcda --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C @@ -0,0 +1,20 @@ +// PR c++/98675 +// { dg-do compile { target c++14 } } + +struct S { + int x = 0; + constexpr const int& get() const { return x; } +}; + +constexpr int error() { + const auto& local = S{}.get(); // { dg-message "note: declared here" } + return local; +} +constexpr int x = error(); // { dg-error "accessing object outside its lifetime" } + +constexpr int ok() { + // temporary should only be destroyed after end of full-expression + auto local = S{}.get(); + return local; +} +constexpr int y = ok(); diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C new file mode 100644 index 00000000000..6329f8cf6c6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C @@ -0,0 +1,13 @@ +// PR c++/70331 +// { dg-do compile { target c++14 } } + +constexpr int f(int i) { + int *p = &i; + if (i == 0) { + int j = 123; // { dg-message "note: declared here" } + p = &j; + } + return *p; +} + +constexpr int i = f(0); // { dg-error "accessing object outside its lifetime" } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C new file mode 100644 index 00000000000..181a1201663 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C @@ -0,0 +1,11 @@ +// { dg-do compile { target c++14 } } + +constexpr const double& test() { + const double& local = 3.0; // { dg-message "note: declared here" } + return local; +} + +static_assert(test() == 3.0, ""); // { dg-error "constant|accessing object outside its lifetime" } + +// no deference, shouldn't error +static_assert((test(), true), ""); diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C new file mode 100644 index 00000000000..a4bc71d890a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C @@ -0,0 +1,11 @@ +// { dg-do compile { target c++14 } } +// { dg-options "-Wno-return-local-addr" } + +constexpr const int& id(int x) { return x; } + +constexpr bool test() { + const int& y = id(3); + return y == 3; +} + +constexpr bool x = test(); // { dg-error "" } From patchwork Wed Mar 29 02:32:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathaniel Shead X-Patchwork-Id: 1762530 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: legolas.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=mPX7KO10; 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 ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PmVwn2kNMz1yYk for ; Wed, 29 Mar 2023 13:33:44 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 08FEC38582BD for ; Wed, 29 Mar 2023 02:33:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 08FEC38582BD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1680057222; bh=on6EJVT8JRdKCBbK6+vcjXgEic7lAUzwm3OxazHxFQ4=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=mPX7KO10uAJZZcpfPhiLIoHN1JjhSh+01/PrZeC6lh0szcw+ahc/q3If0zxCSA6Ea WCdyJMmPjCsHDRuh4ugBkWl/EHJ9cloAOITAgrcsQkok9hjsEtqsKo3wu/A8yxQFB4 x+Sa9JW16eZif5qlnSXDh+4tXDK44BgiJsWX3ZF8= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pj1-x1032.google.com (mail-pj1-x1032.google.com [IPv6:2607:f8b0:4864:20::1032]) by sourceware.org (Postfix) with ESMTPS id F28B33858C54 for ; Wed, 29 Mar 2023 02:33:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F28B33858C54 Received: by mail-pj1-x1032.google.com with SMTP id f6-20020a17090ac28600b0023b9bf9eb63so14688284pjt.5 for ; Tue, 28 Mar 2023 19:33:20 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680057200; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=on6EJVT8JRdKCBbK6+vcjXgEic7lAUzwm3OxazHxFQ4=; b=5Y3s7SxnHxig7KkEsjmvJ/cnag+pNqASmUH3EOJvGMWGBwnB6x1618keegNIrXg7vP e1vH3+121UHphuCCYi8mDiF9UzS7rnJAfuxDd6x1kUldTiOeD7ehVWhh7f/DbAlNa5Yt sh7ckB+hNuM6qdwTHptXWLMFGYMO1lcb1wujsGcsTdAfP0QNYERM2CzaStxAlBjN3d0V 3t3lIIMkTGq0MEBB4/+jpgmmhTcnMyPqZj6RegOSlIkwllgL6vvHav4VltDWJ+QptKwS 0W63YSGKm0CGnpX4FbAOb2qvFjS1hGHzclBcrVuSeholTd8k5lhLLezOYBjWyPp84cJ6 ydzg== X-Gm-Message-State: AO0yUKWGU3i/FXVE+cHC0I3q+6iYMYs3o1pZXV4B5ntLCDt34hDLYnYv WB59loPc/NEXIS79o8AWwRwfmd3pqzs= X-Google-Smtp-Source: AK7set/DLkWDzt2azpiKZnEKL+h9l8KzYptVlEvA2S2nAGs+XqgnbejLZCDr9Toqj6BUvmaVdOHRYQ== X-Received: by 2002:a05:6a20:6730:b0:db:df13:4f73 with SMTP id q48-20020a056a20673000b000dbdf134f73mr14656601pzh.26.1680057199737; Tue, 28 Mar 2023 19:33:19 -0700 (PDT) Received: from Thaum.localdomain (125-209-144-50.tpgi.com.au. [125.209.144.50]) by smtp.gmail.com with ESMTPSA id r1-20020a62e401000000b005a8ba70315bsm21811004pfh.6.2023.03.28.19.33.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Mar 2023 19:33:19 -0700 (PDT) To: gcc-patches@gcc.gnu.org Cc: Nathaniel Shead Subject: [PATCH v2 2/3] c++: Improve constexpr error for dangling local variables Date: Wed, 29 Mar 2023 13:32:57 +1100 Message-Id: <20230329023258.13487-3-nathanieloshead@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230329023258.13487-1-nathanieloshead@gmail.com> References: <20230329023258.13487-1-nathanieloshead@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-12.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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: Nathaniel Shead via Gcc-patches From: Nathaniel Shead Reply-To: Nathaniel Shead Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Currently, when typeck discovers that a return statement will refer to a local variable it rewrites to return a null pointer. This causes the error messages for using the return value in a constant expression to be unhelpful, especially for reference return values. This patch removes this "optimisation". Relying on this raises a warning by default and causes UB anyway, so there should be no issue in doing so. We also suppress additional warnings from later passes that detect this as a dangling pointer, since we've already indicated this anyway. gcc/cp/ChangeLog: * semantics.cc (finish_return_stmt): Suppress dangling pointer reporting on return statement if already reported. * typeck.cc (check_return_expr): Don't set return expression to zero for dangling addresses. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/constexpr-lifetime5.C: Test reported message is correct. * g++.dg/warn/Wreturn-local-addr-6.C: Remove check for return value optimisation. Signed-off-by: Nathaniel Shead --- gcc/cp/semantics.cc | 5 ++++- gcc/cp/typeck.cc | 5 +++-- gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C | 4 ++-- gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C | 3 --- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 87c2e8a7111..14b4b7f4ce1 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -1246,7 +1246,10 @@ finish_return_stmt (tree expr) r = build_stmt (input_location, RETURN_EXPR, expr); if (no_warning) - suppress_warning (r, OPT_Wreturn_type); + { + suppress_warning (r, OPT_Wreturn_type); + suppress_warning (r, OPT_Wdangling_pointer_); + } r = maybe_cleanup_point_expr_void (r); r = add_stmt (r); diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index afb956087ce..a7d642e2029 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -11235,8 +11235,9 @@ check_return_expr (tree retval, bool *no_warning) else if (!processing_template_decl && maybe_warn_about_returning_address_of_local (retval, loc) && INDIRECT_TYPE_P (valtype)) - retval = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval, - build_zero_cst (TREE_TYPE (retval))); + /* Suppress the Wdangling-pointer warning in the return statement + that would otherwise occur. */ + *no_warning = true; } if (processing_template_decl) diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C index a4bc71d890a..ad3ef579f63 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C @@ -1,11 +1,11 @@ // { dg-do compile { target c++14 } } // { dg-options "-Wno-return-local-addr" } -constexpr const int& id(int x) { return x; } +constexpr const int& id(int x) { return x; } // { dg-message "note: declared here" } constexpr bool test() { const int& y = id(3); return y == 3; } -constexpr bool x = test(); // { dg-error "" } +constexpr bool x = test(); // { dg-error "accessing object outside its lifetime" } diff --git a/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C index fae8b7e766f..ec8e241d83e 100644 --- a/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C +++ b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C @@ -24,6 +24,3 @@ return_addr_local_as_intref (void) return (const intptr_t&)a; // { dg-warning "\\\[-Wreturn-local-addr]" } */ } - -/* Verify that the return value has been replaced with zero: - { dg-final { scan-tree-dump-times "return 0;" 2 "optimized" } } */ From patchwork Wed Mar 29 02:32:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathaniel Shead X-Patchwork-Id: 1762533 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: legolas.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=sDD3yFO3; 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 ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PmVy80r0Qz1yYk for ; Wed, 29 Mar 2023 13:34:55 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A4588385086A for ; Wed, 29 Mar 2023 02:34:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A4588385086A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1680057293; bh=m4/o4l6k79QXBxQzcFzZUWg8znrDPO7lnaYTCIbpKlM=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=sDD3yFO3bpCJHDZP2qSHfy29qGSe+DHLbaPz0Y7ejB55bR/N5+8xa5vZ+A/DqC/08 UMQ5pLcmdV3/mSm0FQVYFQeKng89dXfW1KnkQw0Z7Lmv0TT+bMmZWDcQLE6yln85vD C/Cg+mfqpC2AX5mb3TsBCh9rC4Mya113bhbk86IE= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pl1-x631.google.com (mail-pl1-x631.google.com [IPv6:2607:f8b0:4864:20::631]) by sourceware.org (Postfix) with ESMTPS id BCB763858417 for ; Wed, 29 Mar 2023 02:33:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BCB763858417 Received: by mail-pl1-x631.google.com with SMTP id iw3so13572539plb.6 for ; Tue, 28 Mar 2023 19:33:24 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680057202; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=m4/o4l6k79QXBxQzcFzZUWg8znrDPO7lnaYTCIbpKlM=; b=1Vi7P+420P5HOW00UixJS0kIx0af0+TwKGkzOgjrTK5yN1PbFXy3lpQtn1B6m3XJLg z6JITmvOdj62/jARp7BRuN7cIc5knDS7wId/Yk6CQMH22Nv3jiMMM+t0SdaLm1JAzFTr 1r8eJ+uaO6vHonpoK3G1bH4T3efcWPlOdImPiJhUJVwae9iRjqHneA0vNMpMbjDBEKJy SAZCpGIpEjyxdmW1hYr+Xwwlfbc6IENbB8z3rUFtfIyFrEZQVMqp70py9L4yOVse+nV+ 2GEluX5EYzLxB0wCVLJJVnXNz+HyimUliPGVoJ5NagZIQkG1PFMg5vrFGGeTo8Awfaru jN6Q== X-Gm-Message-State: AO0yUKUprGmXaiBDB/4IiTwcCD2kuzTos4/SfWFfqRxgkcjKPSqnqtY1 j1yZFxM7ztbyqjLCT75KeoQPBRItxq4= X-Google-Smtp-Source: AK7set8rtYQaYu4DHIh8TI4L4OoCKBM/nd2UK6HINYo9MD/X0qraEQTFiVFUnEFQ85gNg4a6EjizQw== X-Received: by 2002:a05:6a20:c426:b0:d5:e640:15ec with SMTP id en38-20020a056a20c42600b000d5e64015ecmr15500329pzb.29.1680057201664; Tue, 28 Mar 2023 19:33:21 -0700 (PDT) Received: from Thaum.localdomain (125-209-144-50.tpgi.com.au. [125.209.144.50]) by smtp.gmail.com with ESMTPSA id r1-20020a62e401000000b005a8ba70315bsm21811004pfh.6.2023.03.28.19.33.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Mar 2023 19:33:21 -0700 (PDT) To: gcc-patches@gcc.gnu.org Cc: Nathaniel Shead Subject: [PATCH v2 3/3] c++: Improve location information in constexpr evaluation Date: Wed, 29 Mar 2023 13:32:58 +1100 Message-Id: <20230329023258.13487-4-nathanieloshead@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230329023258.13487-1-nathanieloshead@gmail.com> References: <20230329023258.13487-1-nathanieloshead@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-12.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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: Nathaniel Shead via Gcc-patches From: Nathaniel Shead Reply-To: Nathaniel Shead Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch caches the current expression's location information in the constexpr_global_ctx struct, which allows subexpressions that have lost location information to still provide accurate diagnostics. Also rewrites a number of 'error' calls as 'error_at' to provide more specific location information. The primary effect of this change is that many errors within evaluation of a constexpr function will now point at the offending expression (with expansion tracing information) rather than just the outermost call. gcc/cp/ChangeLog: * constexpr.cc (constexpr_global_ctx): New field for cached tree location, defaulting to input_location. (cxx_eval_internal_function): Fall back to ctx->global->loc rather than input_location. (modifying_const_object_error): Likewise. (cxx_eval_dynamic_cast_fn): Likewise. (eval_and_check_array_index): Likewise. (cxx_eval_array_reference): Likewise. (cxx_eval_bit_field_ref): Likewise. (cxx_eval_component_reference): Likewise. (cxx_eval_indirect_ref): Likewise. (cxx_eval_store_expression): Likewise. (cxx_eval_increment_expression): Likewise. (cxx_eval_loop_expr): Likewise. (cxx_eval_binary_expression): Likewise. (cxx_eval_constant_expression): Cache location of trees for use in errors, and prefer it instead of input_location. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/constexpr-48089.C: Updated diagnostic locations. * g++.dg/cpp0x/constexpr-diag3.C: Likewise. * g++.dg/cpp0x/constexpr-ice20.C: Likewise. * g++.dg/cpp1y/constexpr-89481.C: Likewise. * g++.dg/cpp1y/constexpr-lifetime1.C: Likewise. * g++.dg/cpp1y/constexpr-lifetime2.C: Likewise. * g++.dg/cpp1y/constexpr-lifetime3.C: Likewise. * g++.dg/cpp1y/constexpr-lifetime4.C: Likewise. * g++.dg/cpp1y/constexpr-lifetime5.C: Likewise. * g++.dg/cpp1y/constexpr-union5.C: Likewise. * g++.dg/cpp1y/pr68180.C: Likewise. * g++.dg/cpp1z/constexpr-lambda6.C: Likewise. * g++.dg/cpp2a/bit-cast11.C: Likewise. * g++.dg/cpp2a/bit-cast12.C: Likewise. * g++.dg/cpp2a/bit-cast14.C: Likewise. * g++.dg/cpp2a/constexpr-98122.C: Likewise. * g++.dg/cpp2a/constexpr-dynamic17.C: Likewise. * g++.dg/cpp2a/constexpr-init1.C: Likewise. * g++.dg/cpp2a/constexpr-new12.C: Likewise. * g++.dg/cpp2a/constexpr-new3.C: Likewise. * g++.dg/ext/constexpr-vla2.C: Likewise. * g++.dg/ext/constexpr-vla3.C: Likewise. * g++.dg/ubsan/pr63956.C: Likewise. libstdc++/ChangeLog: * testsuite/25_algorithms/equal/constexpr_neg.cc: Updated diagnostics locations. Signed-off-by: Nathaniel Shead --- gcc/cp/constexpr.cc | 83 +++++++++++-------- gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C | 10 +-- gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C | 2 +- gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C | 4 +- gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C | 3 +- .../g++.dg/cpp1y/constexpr-lifetime1.C | 1 + .../g++.dg/cpp1y/constexpr-lifetime2.C | 4 +- .../g++.dg/cpp1y/constexpr-lifetime3.C | 4 +- .../g++.dg/cpp1y/constexpr-lifetime4.C | 2 +- .../g++.dg/cpp1y/constexpr-lifetime5.C | 4 +- gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C | 4 +- gcc/testsuite/g++.dg/cpp1y/pr68180.C | 4 +- .../g++.dg/cpp1z/constexpr-lambda6.C | 4 +- gcc/testsuite/g++.dg/cpp2a/bit-cast11.C | 10 +-- gcc/testsuite/g++.dg/cpp2a/bit-cast12.C | 10 +-- gcc/testsuite/g++.dg/cpp2a/bit-cast14.C | 14 ++-- gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C | 4 +- .../g++.dg/cpp2a/constexpr-dynamic17.C | 5 +- gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C | 5 +- gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C | 6 +- gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C | 10 +-- gcc/testsuite/g++.dg/ext/constexpr-vla2.C | 4 +- gcc/testsuite/g++.dg/ext/constexpr-vla3.C | 4 +- gcc/testsuite/g++.dg/ubsan/pr63956.C | 4 +- .../25_algorithms/equal/constexpr_neg.cc | 7 +- 25 files changed, 111 insertions(+), 101 deletions(-) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index bdbc12144a7..74045477a92 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -1165,10 +1165,12 @@ public: hash_set *modifiable; /* Number of heap VAR_DECL deallocations. */ unsigned heap_dealloc_count; + /* Current location in case subtree has no location information. */ + location_t loc; /* Constructor. */ constexpr_global_ctx () : constexpr_ops_count (0), cleanups (NULL), modifiable (nullptr), - heap_dealloc_count (0) {} + heap_dealloc_count (0), loc (input_location) {} tree get_value (tree t) { @@ -2113,7 +2115,7 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, default: if (!ctx->quiet) - error_at (cp_expr_loc_or_input_loc (t), + error_at (cp_expr_loc_or_loc (t, ctx->global->loc), "call to internal function %qE", t); *non_constant_p = true; return t; @@ -2128,7 +2130,7 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) { - location_t loc = cp_expr_loc_or_input_loc (t); + location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc); tree type = TREE_TYPE (TREE_TYPE (t)); tree result = fold_binary_loc (loc, opcode, type, fold_convert_loc (loc, type, arg0), @@ -2164,9 +2166,9 @@ clear_no_implicit_zero (tree ctor) EXPR is the MODIFY_EXPR expression performing the modification. */ static void -modifying_const_object_error (tree expr, tree obj) +modifying_const_object_error (const constexpr_ctx* ctx, tree expr, tree obj) { - location_t loc = cp_expr_loc_or_input_loc (expr); + location_t loc = cp_expr_loc_or_loc (expr, ctx->global->loc); auto_diagnostic_group d; error_at (loc, "modifying a const object %qE is not allowed in " "a constant expression", TREE_OPERAND (expr, 0)); @@ -2358,7 +2360,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, tree obj = CALL_EXPR_ARG (call, 0); tree type = CALL_EXPR_ARG (call, 2); HOST_WIDE_INT hint = int_cst_value (CALL_EXPR_ARG (call, 3)); - location_t loc = cp_expr_loc_or_input_loc (call); + location_t loc = cp_expr_loc_or_loc (call, ctx->global->loc); /* Get the target type of the dynamic_cast. */ gcc_assert (TREE_CODE (type) == ADDR_EXPR); @@ -3656,7 +3658,7 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, && integer_zerop (lhs) && !integer_zerop (rhs)) { if (!ctx->quiet) - error ("arithmetic involving a null pointer in %qE", lhs); + error_at (loc, "arithmetic involving a null pointer in %qE", lhs); *non_constant_p = true; return t; } @@ -4149,7 +4151,7 @@ eval_and_check_array_index (const constexpr_ctx *ctx, tree t, bool allow_one_past, bool *non_constant_p, bool *overflow_p) { - location_t loc = cp_expr_loc_or_input_loc (t); + location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc); tree ary = TREE_OPERAND (t, 0); t = TREE_OPERAND (t, 1); tree index = cxx_eval_constant_expression (ctx, t, vc_prvalue, @@ -4187,6 +4189,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, value_cat lval, bool *non_constant_p, bool *overflow_p) { + location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc); tree oldary = TREE_OPERAND (t, 0); tree ary = cxx_eval_constant_expression (ctx, oldary, lval, @@ -4274,7 +4277,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, building; if there's no initializer for this element yet, that's an error. */ if (!ctx->quiet) - error ("accessing uninitialized array element"); + error_at (loc, "accessing uninitialized array element"); *non_constant_p = true; return t; } @@ -4323,13 +4326,14 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, tree whole = cxx_eval_constant_expression (ctx, orig_whole, lval, non_constant_p, overflow_p); + location_t loc = cp_expr_loc_or_loc (whole, ctx->global->loc); if (*non_constant_p) return t; if (INDIRECT_REF_P (whole) && integer_zerop (TREE_OPERAND (whole, 0))) { if (!ctx->quiet) - error ("dereferencing a null pointer in %qE", orig_whole); + error_at (loc, "dereferencing a null pointer in %qE", orig_whole); *non_constant_p = true; return t; } @@ -4348,7 +4352,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, if (TREE_CODE (whole) != CONSTRUCTOR) { if (!ctx->quiet) - error ("%qE is not a constant expression", orig_whole); + error_at (loc, "%qE is not a constant expression", orig_whole); *non_constant_p = true; return t; } @@ -4356,7 +4360,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, && DECL_MUTABLE_P (part)) { if (!ctx->quiet) - error ("mutable %qD is not usable in a constant expression", part); + error_at (loc, "mutable %qD is not usable in a constant expression", part); *non_constant_p = true; return t; } @@ -4386,10 +4390,10 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, { constructor_elt *cep = CONSTRUCTOR_ELT (whole, 0); if (cep->value == NULL_TREE) - error ("accessing uninitialized member %qD", part); + error_at (loc, "accessing uninitialized member %qD", part); else - error ("accessing %qD member instead of initialized %qD member in " - "constant expression", part, cep->index); + error_at (loc, "accessing %qD member instead of initialized %qD member " + "in constant expression", part, cep->index); } *non_constant_p = true; return t; @@ -4408,7 +4412,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, building; if there's no initializer for this member yet, that's an error. */ if (!ctx->quiet) - error ("accessing uninitialized member %qD", part); + error_at (loc, "accessing uninitialized member %qD", part); *non_constant_p = true; return t; } @@ -4436,6 +4440,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t, tree whole = cxx_eval_constant_expression (ctx, orig_whole, lval, non_constant_p, overflow_p); + location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc); tree start, field, value; unsigned HOST_WIDE_INT i; @@ -4448,7 +4453,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t, && TREE_CODE (whole) != CONSTRUCTOR) { if (!ctx->quiet) - error ("%qE is not a constant expression", orig_whole); + error_at (loc, "%qE is not a constant expression", orig_whole); *non_constant_p = true; } if (*non_constant_p) @@ -4460,7 +4465,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t, TREE_OPERAND (t, 1), TREE_OPERAND (t, 2))) return r; if (!ctx->quiet) - error ("%qE is not a constant expression", orig_whole); + error_at (loc, "%qE is not a constant expression", orig_whole); *non_constant_p = true; return t; } @@ -5609,6 +5614,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, value_cat lval, bool *non_constant_p, bool *overflow_p) { + location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc); tree orig_op0 = TREE_OPERAND (t, 0); bool empty_base = false; @@ -5639,7 +5645,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, if (!lval && integer_zerop (op0)) { if (!ctx->quiet) - error ("dereferencing a null pointer"); + error_at (loc, "dereferencing a null pointer"); *non_constant_p = true; return t; } @@ -5658,8 +5664,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t))); /* DR 1188 says we don't have to deal with this. */ if (!ctx->quiet) - error_at (cp_expr_loc_or_input_loc (t), - "accessing value of %qE through a %qT glvalue in a " + error_at (loc, "accessing value of %qE through a %qT glvalue in a " "constant expression", build_fold_indirect_ref (sub), TREE_TYPE (t)); *non_constant_p = true; @@ -5906,6 +5911,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, value_cat lval, bool *non_constant_p, bool *overflow_p) { + location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc); constexpr_ctx new_ctx = *ctx; tree init = TREE_OPERAND (t, 1); @@ -6030,7 +6036,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, /* A constant-expression cannot modify objects from outside the constant-expression. */ if (!ctx->quiet) - error ("modification of %qE is not a constant expression", object); + error_at (loc, "modification of %qE is not a constant expression", object); *non_constant_p = true; return t; } @@ -6128,7 +6134,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (cxx_dialect < cxx20) { if (!ctx->quiet) - error_at (cp_expr_loc_or_input_loc (t), + error_at (cp_expr_loc_or_loc (t, ctx->global->loc), "change of the active member of a union " "from %qD to %qD", CONSTRUCTOR_ELT (*valp, 0)->index, @@ -6141,7 +6147,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, /* Diagnose changing the active union member while the union is in the process of being initialized. */ if (!ctx->quiet) - error_at (cp_expr_loc_or_input_loc (t), + error_at (cp_expr_loc_or_loc (t, ctx->global->loc), "change of the active member of a union " "from %qD to %qD during initialization", CONSTRUCTOR_ELT (*valp, 0)->index, @@ -6224,7 +6230,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (fail) { if (!ctx->quiet) - modifying_const_object_error (t, const_object_being_modified); + modifying_const_object_error (ctx, t, const_object_being_modified); *non_constant_p = true; return t; } @@ -6381,6 +6387,8 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, tree offset = TREE_OPERAND (t, 1); gcc_assert (TREE_CONSTANT (offset)); + location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc); + /* OFFSET is constant, but perhaps not constant enough. We need to e.g. bash FLOAT_EXPRs to REAL_CSTs. */ offset = fold_simple (offset); @@ -6428,8 +6436,7 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, VERIFY_CONSTANT (mod); /* Storing the modified value. */ - tree store = build2_loc (cp_expr_loc_or_loc (t, input_location), - MODIFY_EXPR, type, op, mod); + tree store = build2_loc (loc, MODIFY_EXPR, type, op, mod); mod = cxx_eval_constant_expression (ctx, store, lval, non_constant_p, overflow_p); ggc_free (store); @@ -6602,6 +6609,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p, tree *jump_target) { + location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc); constexpr_ctx new_ctx = *ctx; tree local_target; if (!jump_target) @@ -6691,7 +6699,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, if (++count >= constexpr_loop_limit) { if (!ctx->quiet) - error_at (cp_expr_loc_or_input_loc (t), + error_at (loc, "% loop iteration count exceeds limit of %d " "(use %<-fconstexpr-loop-limit=%> to increase the limit)", constexpr_loop_limit); @@ -6950,7 +6958,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, return t; } - location_t loc = cp_expr_loc_or_input_loc (t); + /* Track current location, propagating down from parent calls + in case this expression has no location information. */ + location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc); + ctx->global->loc = loc; STRIP_ANY_LOCATION_WRAPPER (t); @@ -6973,8 +6984,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, && !integer_zerop (t)) { if (!ctx->quiet) - error ("value %qE of type %qT is not a constant expression", - t, TREE_TYPE (t)); + error_at (loc, "value %qE of type %qT is not a constant expression", + t, TREE_TYPE (t)); *non_constant_p = true; } @@ -7222,8 +7233,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (!ctx->quiet) { auto_diagnostic_group d; - error ("temporary of non-literal type %qT in a " - "constant expression", type); + error_at (loc, "temporary of non-literal type %qT in a " + "constant expression", type); explain_non_literal_class (type); } *non_constant_p = true; @@ -8025,8 +8036,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (function_concept_p (tmpl)) { if (!ctx->quiet) - error_at (cp_expr_loc_or_input_loc (t), - "function concept must be called"); + error_at (loc, "function concept must be called"); r = error_mark_node; break; } @@ -8121,6 +8131,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, break; } + /* Reset current location in case it was modified in child calls. */ + ctx->global->loc = loc; + if (r == error_mark_node) *non_constant_p = true; diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C index 4574eb83ff7..11630f26ffe 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C @@ -10,11 +10,11 @@ // R() is well-formed because i is initialized before j. struct s { - constexpr s() : v(v) { } + constexpr s() : v(v) { } // { dg-error "accessing uninitialized member" } int v; }; -constexpr s bang; // { dg-error "|" } +constexpr s bang; // { dg-message "in .constexpr. expansion" } struct R { int i,j; @@ -26,14 +26,14 @@ constexpr R r; // { dg-bogus "" } // Ill-formed (no diagnostic required) struct T { int i; - constexpr int f() { return i; } + constexpr int f() { return i; } // { dg-error "accessing uninitialized member" } constexpr T(): i(0) { } - constexpr T(const T& t) : i(f()) { } // { dg-message "" } + constexpr T(const T& t) : i(f()) { } // { dg-message "in .constexpr. expansion" } }; constexpr T t1; // Ill-formed (diagnostic required) -constexpr T t2(t1); // { dg-message "" } +constexpr T t2(t1); // { dg-message "in .constexpr. expansion" } // Well-formed struct U { diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C index 5eedf42ba36..50c676c56cd 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C @@ -16,7 +16,7 @@ int main() struct complex // { dg-message "no .constexpr. constructor" "" { target { ! implicit_constexpr } } } { complex(double r, double i) : re(r), im(i) { } - constexpr double real() const { return re; } // { dg-error "not a literal type" "" { target c++11_only } } + constexpr double real() const { return re; } // { dg-error "not a literal type|not usable in a constant expression" "" { target { ! implicit_constexpr } } } double imag() const { return im; } private: diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C index ebaa95e5324..e4e3bf865cd 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C @@ -2,6 +2,6 @@ // { dg-do compile { target c++11 } } typedef bool (*Function)(int); -constexpr bool check(int x, Function p) { return p(x); } // { dg-message "in .constexpr. expansion of" } +constexpr bool check(int x, Function p) { return p(x); } // { dg-error "lifetime" } -static_assert(check(2, check), ""); // { dg-error "conversion|constant|lifetime|in .constexpr. expansion of" } +static_assert(check(2, check), ""); // { dg-error "conversion|constant|in .constexpr. expansion of" } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C index 8ac4ef0fd36..6f8f6a8038e 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C @@ -6,7 +6,7 @@ foo () { union U { long long a; int b[2]; } u { 5LL }; u.b[1] = 4; // { dg-error "change of the active member of a union from" "" { target c++17_down } } - return u.b[0]; + return u.b[0]; // { dg-error "accessing uninitialized array element" "" { target c++2a } } } constexpr int @@ -19,6 +19,5 @@ bar () static_assert (foo () == 0, ""); // { dg-error "non-constant condition for static assertion" } // { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 } - // { dg-error "accessing uninitialized array element" "" { target c++2a } .-2 } static_assert (bar () == 4, ""); // { dg-error "non-constant condition for static assertion" "" { target c++17_down } } // { dg-message "in 'constexpr' expansion of" "" { target c++17_down } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C index 43aa7c974c1..f79f1611d5f 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C @@ -11,3 +11,4 @@ constexpr const int& test() { return local.get(); } constexpr int x = test(); // { dg-error "accessing object outside its lifetime" } + diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C index 22cd919fcda..2f5ae8db6d5 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C @@ -8,9 +8,9 @@ struct S { constexpr int error() { const auto& local = S{}.get(); // { dg-message "note: declared here" } - return local; + return local; // { dg-error "accessing object outside its lifetime" } } -constexpr int x = error(); // { dg-error "accessing object outside its lifetime" } +constexpr int x = error(); // { dg-message "in .constexpr. expansion" } constexpr int ok() { // temporary should only be destroyed after end of full-expression diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C index 6329f8cf6c6..53785521d05 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C @@ -7,7 +7,7 @@ constexpr int f(int i) { int j = 123; // { dg-message "note: declared here" } p = &j; } - return *p; + return *p; // { dg-error "accessing object outside its lifetime" } } -constexpr int i = f(0); // { dg-error "accessing object outside its lifetime" } +constexpr int i = f(0); // { dg-message "in .constexpr. expansion" } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C index 181a1201663..4302da1eddc 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C @@ -5,7 +5,7 @@ constexpr const double& test() { return local; } -static_assert(test() == 3.0, ""); // { dg-error "constant|accessing object outside its lifetime" } +static_assert(test() == 3.0, ""); // { dg-error "non-constant condition|accessing object outside its lifetime" } // no deference, shouldn't error static_assert((test(), true), ""); diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C index ad3ef579f63..a12920c8fba 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C @@ -5,7 +5,7 @@ constexpr const int& id(int x) { return x; } // { dg-message "note: declared he constexpr bool test() { const int& y = id(3); - return y == 3; + return y == 3; // { dg-error "accessing object outside its lifetime" } } -constexpr bool x = test(); // { dg-error "accessing object outside its lifetime" } +constexpr bool x = test(); // { dg-message "in .constexpr. expansion" } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C index 55fe9fa2f0b..3d76345d564 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C @@ -8,8 +8,8 @@ union U { }; constexpr int foo(U *up) { - up->a++; + up->a++; // { dg-error "accessing uninitialized member" } return {42}; } -extern constexpr U u = {}; // { dg-error "accessing uninitialized member" } +extern constexpr U u = {}; // { dg-message "in .constexpr. expansion" } diff --git a/gcc/testsuite/g++.dg/cpp1y/pr68180.C b/gcc/testsuite/g++.dg/cpp1y/pr68180.C index 9e6e5e984f9..8de1ef3936b 100644 --- a/gcc/testsuite/g++.dg/cpp1y/pr68180.C +++ b/gcc/testsuite/g++.dg/cpp1y/pr68180.C @@ -6,11 +6,11 @@ typedef float __attribute__( ( vector_size( 16 ) ) ) float32x4_t; constexpr float32x4_t fill(float x) { float32x4_t v{0}; constexpr auto vs = sizeof(v)/sizeof(v[0]); - for (auto i=0U; i(a); + dynamic_cast(a); // { dg-error "accessing uninitialized member" } } -constexpr D d; // { dg-error "accessing uninitialized member" } -// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 } +constexpr D d; // { dg-message "in 'constexpr' expansion of" } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C index e56ecfed48a..b4e39b6f928 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C @@ -52,11 +52,10 @@ constexpr int fn5 () { struct S { int a = 9; int b; } s; - return s.b; + return s.b; // { dg-error "accessing uninitialized member" } } -constexpr int b = fn5 (); // { dg-error "accessing uninitialized member" } -// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 } +constexpr int b = fn5 (); // { dg-message "in .constexpr. expansion of" } constexpr int fn6 () diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C index 5a3d06a5fab..832782e1427 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C @@ -17,11 +17,11 @@ struct B : A { constexpr int foo () { - A *a = new B (); + A *a = new B (); // { dg-message "allocated here" } a->a = 4; delete a; - int r = a->foo (); + int r = a->foo (); // { dg-error "constant expression" } return r; } -constexpr auto a = foo (); // { dg-error "constant expression" } +constexpr auto a = foo (); // { dg-message "in .constexpr. expansion" } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C index 70b841208f8..3ba440fec53 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C @@ -45,11 +45,10 @@ constexpr bool f5 () { int *p = new int; // { dg-message "allocated here" } - return *p == 1; + return *p == 1; // { dg-error "the content of uninitialized storage is not usable in a constant expression" } } -constexpr auto v5 = f5 (); // { dg-error "the content of uninitialized storage is not usable in a constant expression" } - // { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 } +constexpr auto v5 = f5 (); // { dg-message "in 'constexpr' expansion of" } constexpr bool f6 () @@ -57,11 +56,10 @@ f6 () int *p = new int (2); // { dg-message "allocated here" } int *q = p; delete p; - return *q == 2; + return *q == 2; // { dg-error "use of allocated storage after deallocation in a constant expression" } } -constexpr auto v6 = f6 (); // { dg-error "use of allocated storage after deallocation in a constant expression" } - // { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 } +constexpr auto v6 = f6 (); // { dg-message "in 'constexpr' expansion of" } constexpr int * f7 () diff --git a/gcc/testsuite/g++.dg/ext/constexpr-vla2.C b/gcc/testsuite/g++.dg/ext/constexpr-vla2.C index d4ea7c58c0d..e09a27af3de 100644 --- a/gcc/testsuite/g++.dg/ext/constexpr-vla2.C +++ b/gcc/testsuite/g++.dg/ext/constexpr-vla2.C @@ -4,7 +4,7 @@ constexpr int fn_bad (int n) { - __extension__ int a [n] = { 0 }; + __extension__ int a [n] = { 0 }; // { dg-error "array subscript" } int z = a [0] + (n ? fn_bad (n - 1) : 0); // { dg-message "in .constexpr. expansion of " } return z; } @@ -18,4 +18,4 @@ fn_ok (int n) } constexpr int i1 = fn_ok (3); -constexpr int i2 = fn_bad (3); // { dg-error "array subscript|in .constexpr. expansion of " } +constexpr int i2 = fn_bad (3); // { dg-message "in .constexpr. expansion of " } diff --git a/gcc/testsuite/g++.dg/ext/constexpr-vla3.C b/gcc/testsuite/g++.dg/ext/constexpr-vla3.C index 538b576a825..6f9daa1897f 100644 --- a/gcc/testsuite/g++.dg/ext/constexpr-vla3.C +++ b/gcc/testsuite/g++.dg/ext/constexpr-vla3.C @@ -4,11 +4,11 @@ constexpr int foo (int n) { - __extension__ int a[n] = { 1, 2, 3, 4, 5, 6 }; + __extension__ int a[n] = { 1, 2, 3, 4, 5, 6 }; // { dg-error "array subscript" } int z = 0; for (int i = 0; i <= n; ++i) z += a[i]; return z; } -constexpr int n = foo (3); // { dg-error "array subscript|in .constexpr. expansion of " } +constexpr int n = foo (3); // { dg-message "in .constexpr. expansion of " } diff --git a/gcc/testsuite/g++.dg/ubsan/pr63956.C b/gcc/testsuite/g++.dg/ubsan/pr63956.C index 3a1596e6e2e..0771732ef00 100644 --- a/gcc/testsuite/g++.dg/ubsan/pr63956.C +++ b/gcc/testsuite/g++.dg/ubsan/pr63956.C @@ -100,13 +100,13 @@ constexpr int fn7 (const int *a, int b) { if (b != 3) - return fn6 (*a, b); + return fn6 (*a, b); // { dg-error "null pointer" } return 7; } constexpr int n1 = 7; constexpr int n2 = fn7 (&n1, 5); -constexpr int n3 = fn7 ((const int *) 0, 8); // { dg-error "null pointer|in .constexpr. expansion of " } +constexpr int n3 = fn7 ((const int *) 0, 8); // { dg-message "in .constexpr. expansion of " } constexpr int fn8 (int i) diff --git a/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc b/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc index 34ca5c4805c..fd89ac0e166 100644 --- a/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc +++ b/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc @@ -32,7 +32,7 @@ test01() return outa; } -static_assert(test01()); // { dg-error "outside the bounds" } +static_assert(test01()); // { dg-error "non-constant condition" } constexpr bool test02() @@ -44,7 +44,8 @@ test02() return outa; } -static_assert(test02()); // { dg-error "outside the bounds" } +static_assert(test02()); // { dg-error "non-constant condition" } -// { dg-prune-output "non-constant condition" } +// Errors occuring within internals: +// { dg-error "outside the bounds of array" "" { target *-*-* } 0 } // { dg-prune-output "in 'constexpr'" }