From patchwork Sat Jul 22 15:13:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathaniel Shead X-Patchwork-Id: 124330 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:9010:0:b0:3e4:2afc:c1 with SMTP id l16csp854497vqg; Sat, 22 Jul 2023 08:14:49 -0700 (PDT) X-Google-Smtp-Source: APBJJlFJi9KnGfJvYUh7t86H3m5gonXNN8qzNJhQsh/b5PiXSqPmSaODer6dgRplU/19+TSqs9vN X-Received: by 2002:a17:906:cc4f:b0:99b:65fa:e30f with SMTP id mm15-20020a170906cc4f00b0099b65fae30fmr5073480ejb.1.1690038888934; Sat, 22 Jul 2023 08:14:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690038888; cv=none; d=google.com; s=arc-20160816; b=O4KLiHc/hx4ItUzdDh4TGSU+DWAJewIxV4FCkiY4WFn8AnSoRUpRskZv89NyD5oWbz 4Znjag5yfRDMLjvP0erazstnpTi9ldQtF+gUrT2FJ3Atv5K1wCVvqfkB9kC8lUvnd5H/ vaXMlO4vsUr1XQfKsgVScYjlQ5nnxTnAUZazjadGZcDziAswNIpRt+4j+hkgCJl2R9+u pW3PpH3vAJb+oKbAaguqrT+QvSLPn+f6cQ2cDg5GbdJ3kmchj2CwthNccLlnM4ZsF/VA R5CP4WZZKJ33goFaAFReDwnrozSFB3ApTOQO+vx3dki7en4OL5R+VJyiyuQr9p+xn/br WF4A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:date:dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=YweFIGlxRQJ17MgCw2rkxWe5+2H0AhrMcmcb81aanEo=; fh=O6SbEp1Lmu8iWDJwmE5AT4hXTvupzW71de0eJ/uUO/o=; b=m5zpHx2FmOh1k0xeaUj+vUyBuCwjj0H/LIHUelQfA5xVSheqsR18jJSleay0pv29Dg PCaqbw9+Xzxt6tJJBK5MpMxH0Fc3DCFqb8VYvGKr1Ja4Rn5oegtAIUn/psWjE5KDR9j4 TJ6PuYO3JPq3TPdST0ZzmmqWr56cGjJ8nGq2BDBXg8Xxhuf79q6cCqDvGzDs9UUn1pKC J6GXNguPoksBpyatjTWWwZjiXcK9qDiiPh3vCq997VqRkpi/X0g4jPMl1TRQF1Cnq72T BmKZ9amJuhtoxiYrto1aeT0Ws2/FwnVeMydzGpqSvMVaJ2A2JaYPP9gdPjEUlGcqauRH Pn5g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=vwvWr7Z6; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id gx6-20020a170906f1c600b0098f564f636esi3518020ejb.132.2023.07.22.08.14.48 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 22 Jul 2023 08:14:48 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=vwvWr7Z6; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 860A53853568 for ; Sat, 22 Jul 2023 15:14:47 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 860A53853568 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1690038887; bh=YweFIGlxRQJ17MgCw2rkxWe5+2H0AhrMcmcb81aanEo=; h=Date:To:Cc:Subject:References:In-Reply-To:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=vwvWr7Z6cLKWv4/F2HxizCMW6Zi93y7tw9zbIxNI9NrSu+ZhuRXPc1aOR4IYTdjNS 9X2e0rY+6j6KzU8J/LUy6zP+xH09HVpuM6xeX3op844qBj/WUcG9tlru9p9qvkJNbZ NKrSmpSCMX3ZqIh4GAQVoBL4Jp5gupf3A01OW8HA= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x429.google.com (mail-pf1-x429.google.com [IPv6:2607:f8b0:4864:20::429]) by sourceware.org (Postfix) with ESMTPS id 78AD8385E00F for ; Sat, 22 Jul 2023 15:13:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 78AD8385E00F Received: by mail-pf1-x429.google.com with SMTP id d2e1a72fcca58-666eb03457cso1697923b3a.1 for ; Sat, 22 Jul 2023 08:13:50 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1690038829; x=1690643629; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=YweFIGlxRQJ17MgCw2rkxWe5+2H0AhrMcmcb81aanEo=; b=dueh6+xOCfzgTpbHBUeKeAT/570g4Q7OK3OXtopo0tX9l0CK8cQmpMLSnCH1VMmF1x XMIPWEDKkgKFviaJ+46tTieZ+7wJm/lvG5i/i5mRGRKQCkHt3iWZk//KsB6uUQBGRXM7 FAcFW6TLvI964bEs8Vs3vjEPrtRo/zHtz0cgvbk03yXPai81iKcDbhed+YaoiY+k1eue oXvoZF6oCWoylwZkndz+1y5xfCRqaKdxPVZjD+lsWDXOXhRozw55gzb82yufFZ2VClFp omSIQc8483uaiZX/jh0rlwF2KCjiH5WKXCvte4ZMbNmTLJdlKUbxY6Ij4T8dZHsCg66b SbBg== X-Gm-Message-State: ABy/qLaQtkSUfD9j7zE4UcEm5xmPp25ZZLPQcIp0s2267isk5MSk8CMl DMDnCirObwB4Ikeds2wyeItdOKvtY54= X-Received: by 2002:a05:6a00:b51:b0:65e:ec60:b019 with SMTP id p17-20020a056a000b5100b0065eec60b019mr2393342pfo.25.1690038828156; Sat, 22 Jul 2023 08:13:48 -0700 (PDT) Received: from Thaum.localdomain (59-102-120-25.tpgi.com.au. [59.102.120.25]) by smtp.gmail.com with ESMTPSA id j21-20020aa78dd5000000b00671eb039b23sm4794544pfr.58.2023.07.22.08.13.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 22 Jul 2023 08:13:47 -0700 (PDT) Date: Sun, 23 Jul 2023 01:13:43 +1000 To: gcc-patches@gcc.gnu.org Cc: Jason Merrill , Patrick Palka Subject: [PATCH v5 1/3] c++: Improve location information in constant evaluation Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Spam-Status: No, score=-11.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, T_SCC_BODY_TEXT_LINE, URI_HEX 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+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1772134217788769106 X-GMAIL-MSGID: 1772134217788769106 This patch updates 'input_location' during constant evaluation to ensure that errors in subexpressions that lack location information still provide accurate diagnostics. By itself this change causes some small regressions in diagnostic quality for circumstances where errors used 'input_location' but the location of the parent subexpression doesn't make sense, so this patch also includes a small diagnostic improvement to fix the most egregious case. gcc/cp/ChangeLog: * constexpr.cc (modifying_const_object_error): Find the source location of the const object's declaration. (cxx_eval_constant_expression): Update input_location to the location of the currently evaluated expression, if possible. libstdc++-v3/ChangeLog: * testsuite/25_algorithms/equal/constexpr_neg.cc: Update diagnostic locations. * testsuite/26_numerics/gcd/105844.cc: Likewise. * testsuite/26_numerics/lcm/105844.cc: Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/constexpr-48089.C: Update diagnostic locations. * g++.dg/cpp0x/constexpr-70323.C: Likewise. * g++.dg/cpp0x/constexpr-70323a.C: Likewise. * g++.dg/cpp0x/constexpr-delete2.C: Likewise. * g++.dg/cpp0x/constexpr-diag3.C: Likewise. * g++.dg/cpp0x/constexpr-ice20.C: Likewise. * g++.dg/cpp0x/constexpr-recursion.C: Likewise. * g++.dg/cpp0x/overflow1.C: Likewise. * g++.dg/cpp1y/constexpr-89285.C: Likewise. * g++.dg/cpp1y/constexpr-89481.C: Likewise. * g++.dg/cpp1y/constexpr-tracking-const14.C: Likewise. * g++.dg/cpp1y/constexpr-tracking-const16.C: Likewise. * g++.dg/cpp1y/constexpr-tracking-const18.C: Likewise. * g++.dg/cpp1y/constexpr-tracking-const19.C: Likewise. * g++.dg/cpp1y/constexpr-tracking-const21.C: Likewise. * g++.dg/cpp1y/constexpr-tracking-const22.C: Likewise. * g++.dg/cpp1y/constexpr-tracking-const3.C: Likewise. * g++.dg/cpp1y/constexpr-tracking-const4.C: Likewise. * g++.dg/cpp1y/constexpr-tracking-const7.C: Likewise. * g++.dg/cpp1y/constexpr-union5.C: Likewise. * g++.dg/cpp1y/pr68180.C: Likewise. * g++.dg/cpp1z/constexpr-lambda6.C: Likewise. * g++.dg/cpp1z/constexpr-lambda8.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/cpp2a/constinit10.C: Likewise. * g++.dg/cpp2a/is-corresponding-member4.C: Likewise. * g++.dg/ext/constexpr-vla2.C: Likewise. * g++.dg/ext/constexpr-vla3.C: Likewise. * g++.dg/ubsan/pr63956.C: Likewise. Signed-off-by: Nathaniel Shead --- gcc/cp/constexpr.cc | 31 ++++++++++++++++++- gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C | 10 +++--- gcc/testsuite/g++.dg/cpp0x/constexpr-70323.C | 8 ++--- gcc/testsuite/g++.dg/cpp0x/constexpr-70323a.C | 8 ++--- .../g++.dg/cpp0x/constexpr-delete2.C | 5 +-- gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C | 2 +- gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C | 1 + .../g++.dg/cpp0x/constexpr-recursion.C | 6 ++-- gcc/testsuite/g++.dg/cpp0x/overflow1.C | 2 +- gcc/testsuite/g++.dg/cpp1y/constexpr-89285.C | 5 +-- gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C | 3 +- .../g++.dg/cpp1y/constexpr-tracking-const14.C | 3 +- .../g++.dg/cpp1y/constexpr-tracking-const16.C | 3 +- .../g++.dg/cpp1y/constexpr-tracking-const18.C | 4 +-- .../g++.dg/cpp1y/constexpr-tracking-const19.C | 4 +-- .../g++.dg/cpp1y/constexpr-tracking-const21.C | 4 +-- .../g++.dg/cpp1y/constexpr-tracking-const22.C | 4 +-- .../g++.dg/cpp1y/constexpr-tracking-const3.C | 3 +- .../g++.dg/cpp1y/constexpr-tracking-const4.C | 3 +- .../g++.dg/cpp1y/constexpr-tracking-const7.C | 3 +- gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C | 4 +-- gcc/testsuite/g++.dg/cpp1y/pr68180.C | 4 +-- .../g++.dg/cpp1z/constexpr-lambda6.C | 4 +-- .../g++.dg/cpp1z/constexpr-lambda8.C | 5 ++- 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/cpp2a/constinit10.C | 5 ++- .../g++.dg/cpp2a/is-corresponding-member4.C | 4 +-- 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 | 23 +++++++------- .../25_algorithms/equal/constexpr_neg.cc | 7 +++-- .../testsuite/26_numerics/gcd/105844.cc | 10 +++--- .../testsuite/26_numerics/lcm/105844.cc | 14 +++++---- 40 files changed, 147 insertions(+), 117 deletions(-) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 6e8f1c2b61e..2bf2458c3cd 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -2160,7 +2160,33 @@ modifying_const_object_error (tree expr, tree obj) auto_diagnostic_group d; error_at (loc, "modifying a const object %qE is not allowed in " "a constant expression", TREE_OPERAND (expr, 0)); - inform (location_of (obj), "originally declared % here"); + + /* Find the underlying object that was declared as const. */ + location_t decl_loc = UNKNOWN_LOCATION; + for (tree probe = obj; decl_loc == UNKNOWN_LOCATION; ) + switch (TREE_CODE (probe)) + { + case BIT_FIELD_REF: + case COMPONENT_REF: + { + tree elt = TREE_OPERAND (probe, 1); + if (CP_TYPE_CONST_P (TREE_TYPE (elt))) + decl_loc = DECL_SOURCE_LOCATION (elt); + probe = TREE_OPERAND (probe, 0); + } + break; + + case ARRAY_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + probe = TREE_OPERAND (probe, 0); + break; + + default: + decl_loc = location_of (probe); + break; + } + inform (decl_loc, "originally declared % here"); } /* Return true if FNDECL is a replaceable global allocation function that @@ -6950,7 +6976,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, return t; } + /* Change the input location to the currently processed expression for + better error messages when a subexpression has no location. */ location_t loc = cp_expr_loc_or_input_loc (t); + iloc_sentinel sentinel (loc); STRIP_ANY_LOCATION_WRAPPER (t); 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-70323.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-70323.C index 272a225d967..bfb185f2fb5 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-70323.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-70323.C @@ -1,10 +1,10 @@ // PR c++/70323 // { dg-do compile { target c++11 } } -constexpr int overflow_if_0 (int i) { return __INT_MAX__ + !i; } -constexpr int overflow_if_1 (int i) { return __INT_MAX__ + i; } +constexpr int overflow_if_0 (int i) { return __INT_MAX__ + !i; } // { dg-error "overflow in constant expression" } +constexpr int overflow_if_1 (int i) { return __INT_MAX__ + i; } // { dg-error "overflow in constant expression" } -constexpr bool i0_0 = overflow_if_0 (0); // { dg-error "overflow in constant expression|in .constexpr. expansion of " } +constexpr bool i0_0 = overflow_if_0 (0); // { dg-message "in .constexpr. expansion of " } constexpr bool i0_1 = overflow_if_0 (1); constexpr bool i1_0 = overflow_if_1 (0); -constexpr bool i1_1 = overflow_if_1 (1); // { dg-error "overflow in constant expression|in .constexpr. expansion of " } +constexpr bool i1_1 = overflow_if_1 (1); // { dg-message "in .constexpr. expansion of " } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-70323a.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-70323a.C index 1990ab6be2d..b5ed581e1c8 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-70323a.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-70323a.C @@ -2,10 +2,10 @@ // { dg-do compile { target c++11 } } // { dg-options "-Wall" } -constexpr int overflow_if_0 (int i) { return __INT_MAX__ + !i; } -constexpr int overflow_if_1 (int i) { return __INT_MAX__ + i; } +constexpr int overflow_if_0 (int i) { return __INT_MAX__ + !i; } // { dg-error "overflow in constant expression" } +constexpr int overflow_if_1 (int i) { return __INT_MAX__ + i; } // { dg-error "overflow in constant expression" } -constexpr bool i0_0 = overflow_if_0 (0); // { dg-error "overflow in constant expression|in .constexpr. expansion of" } +constexpr bool i0_0 = overflow_if_0 (0); // { dg-message "in .constexpr. expansion of" } constexpr bool i0_1 = overflow_if_0 (1); constexpr bool i1_0 = overflow_if_1 (0); -constexpr bool i1_1 = overflow_if_1 (1); // { dg-error "overflow in constant expression|in .constexpr. expansion of" } +constexpr bool i1_1 = overflow_if_1 (1); // { dg-message "in .constexpr. expansion of" } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-delete2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-delete2.C index 999f9b7851e..f2b6df2509c 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-delete2.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-delete2.C @@ -6,8 +6,9 @@ constexpr int f(int i) { return i; } constexpr int g(A* ap) { return f((delete[] ap, 42)); // { dg-message "" "" { target c++17_down } } + // { dg-error "" "" { target c++2a } .-1 } } A a; -constexpr int i = g(&a); // { dg-error "" } - // { dg-message "in 'constexpr' expansion of" "" { target c++2a } .-1 } +constexpr int i = g(&a); // { dg-error "" "" { target c++17_down } } + // { dg-message "in 'constexpr' expansion of" "" { target c++2a } .-1 } 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 e2d4853a284..43fa9a03c14 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C @@ -3,5 +3,6 @@ typedef bool (*Function)(int); constexpr bool check(int x, Function p) { return p(x); } // { dg-message "in .constexpr. expansion of" } +// { dg-error "not a constant expression" "" { target *-*-* } .-1 } static_assert(check(2, check), ""); // { dg-error "conversion|constant|in .constexpr. expansion of" } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-recursion.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-recursion.C index 8c4201e1ec2..b00f8794d4c 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-recursion.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-recursion.C @@ -1,6 +1,6 @@ // Test that we catch excessive recursion. // { dg-do compile { target c++11 } } // { dg-options "-fconstexpr-depth=5" } -// { dg-prune-output "in constexpr expansion" } -constexpr int f (int i) { return f (i-1); } // { dg-message "in .constexpr. expansion of " } -constexpr int i = f(42); // { dg-error ".constexpr. evaluation depth|in .constexpr. expansion of " } +// { dg-prune-output "in .constexpr. expansion" } +constexpr int f (int i) { return f (i-1); } // { dg-error ".constexpr. evaluation depth" } +constexpr int i = f(42); diff --git a/gcc/testsuite/g++.dg/cpp0x/overflow1.C b/gcc/testsuite/g++.dg/cpp0x/overflow1.C index b8591b4af41..e295355c88f 100644 --- a/gcc/testsuite/g++.dg/cpp0x/overflow1.C +++ b/gcc/testsuite/g++.dg/cpp0x/overflow1.C @@ -4,7 +4,7 @@ template struct Fib { static const long long value // { dg-error "overflow" } - = Fib::value + Fib::value; + = Fib::value + Fib::value; // { dg-error "overflow" } }; template <> diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-89285.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-89285.C index fe0b8570ca2..efbf9bd15dd 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-89285.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-89285.C @@ -13,8 +13,9 @@ struct B { *c = reinterpret_cast(this) - reinterpret_cast(c); // { dg-error "reinterpret_cast" "" { target c++20_down } } } }; -struct C : A { +struct C : A { // { dg-error "" "" { target c++14_down } } B bar {this}; }; -constexpr C foo {}; // { dg-message "" } +// error path changes in C++17 due to `C` becoming an aggregate +constexpr C foo {}; // { dg-error "" "" { target c++17 } } 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-tracking-const14.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const14.C index 45c4fcf50be..0c77dd4934d 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const14.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const14.C @@ -14,7 +14,7 @@ struct C { struct A { int r; - const C c; + const C c; // { dg-message "originally declared" } constexpr A() : r(11) { r = 14; const_cast(c).n = 42; } // { dg-error "modifying a const object" } }; @@ -34,5 +34,4 @@ struct B { }; constexpr B b(false); // { dg-message "in .constexpr. expansion of" } -// { dg-message "originally declared" "" { target *-*-* } .-1 } static_assert(b.e.d.a.c.n == 2, ""); // { dg-error "non-constant condition" } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const16.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const16.C index 5a5b92bc8cc..b5ccf3a4ea5 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const16.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const16.C @@ -7,7 +7,7 @@ constexpr int& impl(const int (&array)[10], int index) { struct A { constexpr int& operator[](int i) { return impl(elems, i); } - const int elems[10]; + const int elems[10]; // { dg-message "originally declared" } }; constexpr bool @@ -19,4 +19,3 @@ f() } constexpr bool b = f(); // { dg-message "in .constexpr. expansion of " } -// { dg-message "originally declared" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const18.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const18.C index 11a680468c2..278628c121b 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const18.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const18.C @@ -13,11 +13,11 @@ struct array template struct S { using U = array; - const U m; + const U m; // { dg-message "originally declared" } constexpr S(int) : m{} { const_cast(const_cast(m)[0]) = 42; // { dg-error "modifying a const object" } } }; -constexpr S p = { 10 }; // { dg-message "originally declared" } +constexpr S p = { 10 }; diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const19.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const19.C index c31222ffcdd..2d18c94537b 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const19.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const19.C @@ -7,7 +7,7 @@ template struct array { constexpr const E &operator[](size_t n) const noexcept { return elems[n]; } - const E elems[N]; + const E elems[N]; // { dg-message "originally declared" } }; template @@ -20,4 +20,4 @@ struct S { } }; -constexpr S p = { 10 }; // { dg-message "originally declared" } +constexpr S p = { 10 }; diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const21.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const21.C index 0b16193398e..d3bbcb116a6 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const21.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const21.C @@ -18,11 +18,11 @@ struct array2 { template struct S { using U = array2; - const U m; + const U m; // { dg-message "originally declared" } constexpr S(int) : m{} { const_cast(m.a[0]) = 42; // { dg-error "modifying a const object" } } }; -constexpr S p = { 10 }; // { dg-message "originally declared" } +constexpr S p = { 10 }; diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const22.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const22.C index 216cf1607a4..27522f86dbd 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const22.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const22.C @@ -7,11 +7,11 @@ struct X { template struct S { - const X x; + const X x; // { dg-message "originally declared" } constexpr S(int) : x{} { const_cast(x).i = 19; // { dg-error "modifying a const object" } } }; -constexpr S p = { 10 }; // { dg-message "originally declared" } +constexpr S p = { 10 }; diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const3.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const3.C index 6853775c1e2..fc88dd05eef 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const3.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const3.C @@ -7,7 +7,7 @@ struct A { }; struct B { - const A a; + const A a; // { dg-message "originally declared" } constexpr B(bool b) { if (b) const_cast(a).n = 3; // { dg-error "modifying a const object" } @@ -18,5 +18,4 @@ constexpr B b(false); static_assert(b.a.n == 2, ""); constexpr B b2(true); // { dg-message "in .constexpr. expansion of " } -// { dg-message "originally declared" "" { target *-*-* } .-1 } static_assert((b2.a.n, 1), ""); diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const4.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const4.C index 8263a7cc505..27fede152c7 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const4.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const4.C @@ -2,7 +2,7 @@ // { dg-do compile { target c++14 } } struct A { - const int n; + const int n; // { dg-message "originally declared" } constexpr A() : n(1) { } }; struct B { @@ -13,5 +13,4 @@ struct B { } }; constexpr B b; // { dg-message "in .constexpr. expansion of " } -// { dg-message "originally declared" "" { target *-*-* } .-1 } static_assert((b.a.n, 1), ""); diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const7.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const7.C index 922e8ff126f..bea14b05602 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const7.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const7.C @@ -3,7 +3,7 @@ struct D { int n; }; -struct C { const D d; }; +struct C { const D d; }; // { dg-message "originally declared" } struct A { C c; @@ -19,5 +19,4 @@ struct B { }; constexpr B b{}; // { dg-message "in .constexpr. expansion of " } -// { dg-message "originally declared" "" { target *-*-* } .-1 } static_assert((b.a.c.d.n, 1), ""); 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/cpp2a/constinit10.C b/gcc/testsuite/g++.dg/cpp2a/constinit10.C index b678788541e..d2c49c41f91 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constinit10.C +++ b/gcc/testsuite/g++.dg/cpp2a/constinit10.C @@ -11,15 +11,14 @@ struct S1 struct alignas(64) S2 { constexpr S2 () - : m_tabS1() + : m_tabS1() // { dg-error "used before its definition" } {} S1 m_tabS1[7]; }; constinit S2 objX; // { dg-error ".constinit. variable .objX. does not have a constant initializer" } -// { dg-error "used before its definition" "" { target *-*-* } .-1 } -// // { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-2 } +// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 } constexpr S1::S1 () : m_i(14) diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member4.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member4.C index 6b74090306b..241e9976e8c 100644 --- a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member4.C +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member4.C @@ -14,8 +14,8 @@ is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept struct A { int a; }; struct B; constexpr int B::*n = nullptr; -constexpr auto a = std::is_corresponding_member (&A::a, n); // { dg-error "invalid use of incomplete type 'struct B'" } -constexpr auto b = std::is_corresponding_member (n, &A::a); // { dg-error "invalid use of incomplete type 'struct B'" } +constexpr auto a = std::is_corresponding_member (&A::a, n); // { dg-message "in .constexpr. expansion of" } +constexpr auto b = std::is_corresponding_member (n, &A::a); // { dg-message "in .constexpr. expansion of" } void foo (int B::*m) 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..6fd0b4f893e 100644 --- a/gcc/testsuite/g++.dg/ubsan/pr63956.C +++ b/gcc/testsuite/g++.dg/ubsan/pr63956.C @@ -56,12 +56,13 @@ fn3 (int a, int b) { if (b != 2) a = a / b; // { dg-error "..7 / 0.. is not a constant expression" } + // { dg-error "overflow in constant expression" "" { target *-*-* } .-1 } return a; } constexpr int k1 = fn3 (8, 4); constexpr int k2 = fn3 (7, 0); // { dg-message "in .constexpr. expansion" } -constexpr int k3 = fn3 (INT_MIN, -1); // { dg-error "overflow in constant expression|in .constexpr. expansion of " } +constexpr int k3 = fn3 (INT_MIN, -1); // { dg-message "in .constexpr. expansion of " } SA (k1 == 2); @@ -100,13 +101,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) @@ -122,15 +123,15 @@ constexpr int fn9 (int a, int b) { if (b != 0) - return a + b; + return a + b; // { dg-error "overflow in constant expression" } return a; } constexpr int p1 = fn9 (42, 7); -constexpr int p2 = fn9 (__INT_MAX__, 1); // { dg-error "overflow in constant expression|in .constexpr. expansion of " } +constexpr int p2 = fn9 (__INT_MAX__, 1); // { dg-message "in .constexpr. expansion of " } constexpr int p3 = fn9 (__INT_MAX__, -1); constexpr int p4 = fn9 (INT_MIN, 1); -constexpr int p5 = fn9 (INT_MIN, -1); // { dg-error "overflow in constant expression|in .constexpr. expansion of " } +constexpr int p5 = fn9 (INT_MIN, -1); // { dg-message "in .constexpr. expansion of " } SA (p1 == 49); SA (p3 == __INT_MAX__ - 1); @@ -140,13 +141,13 @@ constexpr int fn10 (int a, int b) { if (b != 0) - return a * b; + return a * b; // { dg-error "overflow in constant expression" } return a; } constexpr int q1 = fn10 (10, 10); -constexpr int q2 = fn10 (__INT_MAX__, 2); // { dg-error "overflow in constant expression|in .constexpr. expansion of " } -constexpr int q3 = fn10 (INT_MIN, 2); // { dg-error "overflow in constant expression|in .constexpr. expansion of " } +constexpr int q2 = fn10 (__INT_MAX__, 2); // { dg-message "in .constexpr. expansion of " } +constexpr int q3 = fn10 (INT_MIN, 2); // { dg-message "in .constexpr. expansion of " } constexpr int q4 = fn10 (-1, -1); SA (q1 == 100); @@ -155,14 +156,14 @@ SA (q4 == 1); constexpr int fn11 (double d) { - int i = d; + int i = d; // { dg-error "overflow in constant expression" } if (i != 0) return i; return i * 2; } constexpr int r1 = fn11 (3.4); -constexpr int r2 = fn11 (__builtin_inf ()); // { dg-error "overflow in constant expression|in .constexpr. expansion of " } +constexpr int r2 = fn11 (__builtin_inf ()); // { dg-message "in .constexpr. expansion of " } constexpr int fn12 (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'" } diff --git a/libstdc++-v3/testsuite/26_numerics/gcd/105844.cc b/libstdc++-v3/testsuite/26_numerics/gcd/105844.cc index 5b6fea7b560..bc9b29bc39d 100644 --- a/libstdc++-v3/testsuite/26_numerics/gcd/105844.cc +++ b/libstdc++-v3/testsuite/26_numerics/gcd/105844.cc @@ -13,9 +13,11 @@ static_assert( std::gcd(LLONG_MIN, 2ull) == 2 ); static_assert( std::gcd(2ull, LLONG_MIN) == 2 ); // But |INT_MIN| cannot be represented in common_type i.e. int. -constexpr int a = std::gcd(INT_MIN, 1); // { dg-error "overflow" } -constexpr int b = std::gcd(1, INT_MIN); // { dg-error "overflow" } +constexpr int a = std::gcd(INT_MIN, 1); // { dg-error "in .constexpr." } +constexpr int b = std::gcd(1, INT_MIN); // { dg-error "in .constexpr." } // And |LLONG_MIN| cannot be represented in long. -constexpr long long c = std::gcd(LLONG_MIN, 1); // { dg-error "overflow" } -constexpr long long d = std::gcd(1, LLONG_MIN); // { dg-error "overflow" } +constexpr long long c = std::gcd(LLONG_MIN, 1); // { dg-error "in .constexpr." } +constexpr long long d = std::gcd(1, LLONG_MIN); // { dg-error "in .constexpr." } + +// { dg-error "overflow" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/26_numerics/lcm/105844.cc b/libstdc++-v3/testsuite/26_numerics/lcm/105844.cc index d0e032e03e0..d853974f77e 100644 --- a/libstdc++-v3/testsuite/26_numerics/lcm/105844.cc +++ b/libstdc++-v3/testsuite/26_numerics/lcm/105844.cc @@ -9,14 +9,16 @@ static_assert( std::lcm(INT_MIN, 1u) == INT_MAX+1u ); static_assert( std::lcm(1u, INT_MIN) == INT_MAX+1u ); // But |INT_MIN| cannot be represented in common_type i.e. int. -constexpr int a = std::lcm(INT_MIN, 1); // { dg-error "overflow" } -constexpr int b = std::lcm(1, INT_MIN); // { dg-error "overflow" } +constexpr int a = std::lcm(INT_MIN, 1); // { dg-error "in .constexpr." } +constexpr int b = std::lcm(1, INT_MIN); // { dg-error "in .constexpr." } // And the LCM of 50000 and 49999 cannot be represented in int. -constexpr int c = std::lcm(50000, 49999); // { dg-error "overflow" } -constexpr int d = std::lcm(49999, 50000); // { dg-error "overflow" } +constexpr int c = std::lcm(50000, 49999); // { dg-error "in .constexpr." } +constexpr int d = std::lcm(49999, 50000); // { dg-error "in .constexpr." } // Similarly for unsigned, but the diagnostic is a failed assertion instead. -constexpr int e = std::lcm(500000u, 499999); // { dg-error "in 'constexpr'" } -constexpr int f = std::lcm(499999u, 500000); // { dg-error "in 'constexpr'" } +constexpr int e = std::lcm(500000u, 499999); // { dg-error "in .constexpr." } +constexpr int f = std::lcm(499999u, 500000); // { dg-error "in .constexpr." } + +// { dg-error "overflow" "" { target *-*-* } 0 } // { dg-error "unreachable" "" { target *-*-* } 0 } From patchwork Sat Jul 22 15:14:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathaniel Shead X-Patchwork-Id: 124331 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:9010:0:b0:3e4:2afc:c1 with SMTP id l16csp854949vqg; Sat, 22 Jul 2023 08:15:42 -0700 (PDT) X-Google-Smtp-Source: APBJJlF47fvVRu1j9IMrIl3SlyTSdulUK5AAJV57bT3k4wTvM7kZy8rHQX8h5H2QN4cE9hYHB49V X-Received: by 2002:a17:906:dc:b0:994:673:8af6 with SMTP id 28-20020a17090600dc00b0099406738af6mr5156497eji.29.1690038942358; Sat, 22 Jul 2023 08:15:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690038942; cv=none; d=google.com; s=arc-20160816; b=MMceM6ZP0Ddov3vMyQndsIvVCcTQurcIZgKFMci6lr/CxCADYbd95i1oNh014wrz0X eKtl6Ln/U0zj5H1eUDZcSoFt2W+suzGIhjTbhl+qLUZ7jZaVSo3XkEaPnjTQEXcji5vX 1HMgGj2OK62ftdogcfzG875KGmRSmZJF+MHcvM0m6DzqNuXSpwv4z90+IEwDyZ+nAWQN VOJhJjebTRZ+lYsgpW55VkcF6aE0mwvwi0YxTAOSVSidXxTnHjTYVxNTRXEchrqTfqA3 yOGqblkITXbc9YnV/uu+SGcHiZ2HOHwKRnRLSBudcdMJ61wD8RZt0oypsTUjJEq9ZNOD IhiQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:date:dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=0SHn2b9pRriPU9Bii008XExZ9j17JjQ6ysszwEiUgCE=; fh=O6SbEp1Lmu8iWDJwmE5AT4hXTvupzW71de0eJ/uUO/o=; b=IdFec+C7o2iKos1kvXj3lyqLB0tBUMg4B74uudZPqxZodLKMpvJEjHM+BZ619EV6A8 U3Rya1WsCVuGSfBgCAqwgxkI7/5dGUCI46ugHE4rDABjycDqOFUBURy0nEmubX+3swUS Fe1SLdmg+4vt6JRAPFO3LahfbGwYPCCIZdIsh9ZoXZkzKTiJYWhXZh/1ZZOqwhc+uC5f fLtNYckGnG29Tpj3LzFCUN17d8YRjfhP/vnQkMiUoI0rLOhtyru4Hahg8nkZVuSinisc r9ql8xbyCKXsqi+sBVudT/oMd+BQWWtiGb79pJek9QoMTodI0BU5YYNVhZ5whid0oi2p HpEA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=y2EvSBeW; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id t2-20020a170906a10200b00991f1e4b041si3729307ejy.737.2023.07.22.08.15.42 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 22 Jul 2023 08:15:42 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=y2EvSBeW; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 64A12386D61B for ; Sat, 22 Jul 2023 15:15:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 64A12386D61B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1690038927; bh=0SHn2b9pRriPU9Bii008XExZ9j17JjQ6ysszwEiUgCE=; h=Date:To:Cc:Subject:References:In-Reply-To:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=y2EvSBeW/SSu9HSNYUjoavkNKLbI3hC0okXRly87TQNtEGV0iWTFJOpLJGL5P7Rxb mwKxL34FRBKt+keqMru18bOhgiEwSd195Sxt/X+SHivNnAV02VEKYkvGMODt/npfph F6xe4fSEvmN9fiJn4+WU/XQ0hAbwj+K09djQ964c= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x42a.google.com (mail-pf1-x42a.google.com [IPv6:2607:f8b0:4864:20::42a]) by sourceware.org (Postfix) with ESMTPS id ADA8D385382B for ; Sat, 22 Jul 2023 15:14:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org ADA8D385382B Received: by mail-pf1-x42a.google.com with SMTP id d2e1a72fcca58-668711086f4so1912017b3a.1 for ; Sat, 22 Jul 2023 08:14:42 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1690038881; x=1690643681; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=0SHn2b9pRriPU9Bii008XExZ9j17JjQ6ysszwEiUgCE=; b=KsiB0tbHwO3XpJzuzwqs3E2VTK88tdt3Mcul7IkP2sObkWQixsOE1cxM4466B1GSTF /IgpIGqf0M7Z8cTwnzLIPxPEjVf6olEmtmins39ZVE1aWySsCimHMdhlKDZ9HXw5Q3Jt znaSh+g3rhE8erwuyklMdVS1Hnbji5hhmej2/IZdrPBw6dbAxTc3lafuxEH9a4ieHRA9 d554Sy5UcywhY35sZSseTwG5Q6ucoP/XqsWk4eW0K/iN7rOw/VxM9YhQ7jLSgweYkWv1 smhrihMXbsvMFq4fKOuQa6eFeXAZX3QrWvm6dN9PPtFpECu2a3zdG9eUFoRevDRgeKPF wa6g== X-Gm-Message-State: ABy/qLa8O5gYjjYrAjGuctUqskJn/sEi8d0KZSWusUvuJprNYMn5TeQo NfbUnls69zL0L/akjawKYIQYmGVmguE= X-Received: by 2002:a05:6a20:918e:b0:134:70b7:238a with SMTP id v14-20020a056a20918e00b0013470b7238amr6737452pzd.12.1690038881378; Sat, 22 Jul 2023 08:14:41 -0700 (PDT) Received: from Thaum.localdomain (59-102-120-25.tpgi.com.au. [59.102.120.25]) by smtp.gmail.com with ESMTPSA id v11-20020a62a50b000000b00682a16f0b00sm4690909pfm.210.2023.07.22.08.14.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 22 Jul 2023 08:14:41 -0700 (PDT) Date: Sun, 23 Jul 2023 01:14:37 +1000 To: gcc-patches@gcc.gnu.org Cc: Jason Merrill , Patrick Palka Subject: [PATCH v5 2/3] c++: Prevent dangling pointers from becoming nullptr in constexpr [PR110619] Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Spam-Status: No, score=-11.4 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, T_SCC_BODY_TEXT_LINE 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+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1772134273866471293 X-GMAIL-MSGID: 1772134273866471293 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, and is also a visible change to otherwise valid code (as in the linked PR). The transformation is nonetheless important, however, both as a safety guard against attackers being able to gain a handle to other data on the stack, and to prevent duplicate warnings from later null-dereference warning passes. As such, this patch just delays the transformation until cp_genericize, after constexpr function definitions have been generated. PR c++/110619 gcc/cp/ChangeLog: * cp-gimplify.cc (cp_genericize_r): Transform RETURN_EXPRs to not return dangling pointers. * cp-tree.h (RETURN_EXPR_LOCAL_ADDR_P): New flag. (check_return_expr): Add a new parameter. * semantics.cc (finish_return_stmt): Set flag on RETURN_EXPR when referring to dangling pointer. * typeck.cc (check_return_expr): Disable transformation of dangling pointers, instead pass this information to caller. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/constexpr-110619.C: New test. Signed-off-by: Nathaniel Shead --- gcc/cp/cp-gimplify.cc | 23 ++++++++++++++++--- gcc/cp/cp-tree.h | 8 ++++++- gcc/cp/semantics.cc | 4 +++- gcc/cp/typeck.cc | 9 ++++---- gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C | 10 ++++++++ 5 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index f5734197774..0a5d6300aca 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -1336,9 +1336,26 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) break; case RETURN_EXPR: - if (TREE_OPERAND (stmt, 0) && is_invisiref_parm (TREE_OPERAND (stmt, 0))) - /* Don't dereference an invisiref RESULT_DECL inside a RETURN_EXPR. */ - *walk_subtrees = 0; + if (TREE_OPERAND (stmt, 0)) + { + if (is_invisiref_parm (TREE_OPERAND (stmt, 0))) + /* Don't dereference an invisiref RESULT_DECL inside a RETURN_EXPR. */ + *walk_subtrees = 0; + if (RETURN_EXPR_LOCAL_ADDR_P (stmt)) + { + /* Don't return the address of a local variable. */ + tree *p = &TREE_OPERAND (stmt, 0); + while (TREE_CODE (*p) == COMPOUND_EXPR) + p = &TREE_OPERAND (*p, 0); + if (TREE_CODE (*p) == INIT_EXPR) + { + tree op = TREE_OPERAND (*p, 1); + tree new_op = build2 (COMPOUND_EXPR, TREE_TYPE (op), op, + build_zero_cst (TREE_TYPE (op))); + TREE_OPERAND (*p, 1) = new_op; + } + } + } break; case OMP_CLAUSE: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3de0e154c12..e0c181d9aef 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -447,6 +447,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; INIT_EXPR_NRV_P (in INIT_EXPR) ATOMIC_CONSTR_MAP_INSTANTIATED_P (in ATOMIC_CONSTR) contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT) + RETURN_EXPR_LOCAL_ADDR_P (in RETURN_EXPR) 1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -4071,6 +4072,11 @@ struct GTY(()) lang_decl { (LANG_DECL_FN_CHECK (FUNCTION_DECL_CHECK (NODE)) \ ->u.saved_auto_return_type) +/* In a RETURN_EXPR, whether the expression refers to the address + of a local variable. */ +#define RETURN_EXPR_LOCAL_ADDR_P(NODE) \ + TREE_LANG_FLAG_0 (RETURN_EXPR_CHECK (NODE)) + /* True if NODE is an implicit INDIRECT_REF from convert_from_reference. */ #define REFERENCE_REF_P(NODE) \ (INDIRECT_REF_P (NODE) \ @@ -8139,7 +8145,7 @@ extern tree composite_pointer_type (const op_location_t &, tsubst_flags_t); extern tree merge_types (tree, tree); extern tree strip_array_domain (tree); -extern tree check_return_expr (tree, bool *); +extern tree check_return_expr (tree, bool *, bool *); extern tree spaceship_type (tree, tsubst_flags_t = tf_warning_or_error); extern tree genericize_spaceship (location_t, tree, tree, tree); extern tree cp_build_binary_op (const op_location_t &, diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 8fb47fd179e..720521b7f1a 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -1240,8 +1240,9 @@ finish_return_stmt (tree expr) { tree r; bool no_warning; + bool dangling; - expr = check_return_expr (expr, &no_warning); + expr = check_return_expr (expr, &no_warning, &dangling); if (error_operand_p (expr) || (flag_openmp && !check_omp_return ())) @@ -1259,6 +1260,7 @@ finish_return_stmt (tree expr) } r = build_stmt (input_location, RETURN_EXPR, expr); + RETURN_EXPR_LOCAL_ADDR_P (r) = dangling; if (no_warning) suppress_warning (r, OPT_Wreturn_type); r = maybe_cleanup_point_expr_void (r); diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 859b133a18d..d5c0c85ed51 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -10920,10 +10920,11 @@ maybe_warn_pessimizing_move (tree expr, tree type, bool return_p) change RETVAL into the function return type, and to assign it to the DECL_RESULT for the function. Set *NO_WARNING to true if code reaches end of non-void function warning shouldn't be issued - on this RETURN_EXPR. */ + on this RETURN_EXPR. Set *DANGLING to true if code returns the + address of a local variable. */ tree -check_return_expr (tree retval, bool *no_warning) +check_return_expr (tree retval, bool *no_warning, bool *dangling) { tree result; /* The type actually returned by the function. */ @@ -10935,6 +10936,7 @@ check_return_expr (tree retval, bool *no_warning) location_t loc = cp_expr_loc_or_input_loc (retval); *no_warning = false; + *dangling = false; /* A `volatile' function is one that isn't supposed to return, ever. (This is a G++ extension, used to get better code for functions @@ -11273,8 +11275,7 @@ 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))); + *dangling = true; } /* A naive attempt to reduce the number of -Wdangling-reference false diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C new file mode 100644 index 00000000000..cca13302238 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C @@ -0,0 +1,10 @@ +// { dg-do compile { target c++14 } } +// { dg-options "-Wno-return-local-addr" } +// PR c++/110619 + +constexpr auto f() { + int i = 0; + return &i; +}; + +static_assert( f() != nullptr ); From patchwork Sat Jul 22 15:15:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathaniel Shead X-Patchwork-Id: 124332 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:9010:0:b0:3e4:2afc:c1 with SMTP id l16csp855404vqg; Sat, 22 Jul 2023 08:16:34 -0700 (PDT) X-Google-Smtp-Source: APBJJlEC9LlwxIIoo1ejNJH/na6PAokk2uYt5/+1HH0lGmZ3MpTNXibgd2GJRD4jVaiv+ucRdYzU X-Received: by 2002:a05:6402:1514:b0:521:7ab6:b954 with SMTP id f20-20020a056402151400b005217ab6b954mr4194862edw.1.1690038994181; Sat, 22 Jul 2023 08:16:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690038994; cv=none; d=google.com; s=arc-20160816; b=AS3BK31e8EsykQPzqMA71z5kcRCeLTOGlBKS+NDeDC0JHspOlaYEyw3TefLazEp3Ke cJRTPn4J03gS7i1v2Z/Hm4eCerVtdXjR+c19J5CRlMh8OdY5qCkkyOkMf7XvpWrfDime FV7rzrvpqqLbFr2vziTuK277E127s7WdJ0v7Odmxdv4zEBDjkxyq/gUpqzB9hXJrB4Zx WPWsrOtVWUQjNMprg5iWt9FF+/6aYvMLA+eLBuhPuBJOEI+7rwWRasGD6Z9kwdc9a6Ko uzARS1pSMEnOzDKqY3kg227j+8yjA4tbdBPbKAe+UXWP+c2AI4QPFwMNcieWg8eE2kn5 WZyQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:date:dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=+zqwGxVA0YdNSWIbjWuJuayJCOJ4qyyeFgdf6JrmVG0=; fh=O6SbEp1Lmu8iWDJwmE5AT4hXTvupzW71de0eJ/uUO/o=; b=bFLIXQOmaU2At2TuBKftfsObPaoIr9Mbh8j46fQMKQzIKVOXSsuwqR5SKuKUdIKLkz NcY0A1F8mbwxTEFtxbXUcn3BWB7YgXTC16WhEO8swcK2UBmgh7ZVxLz8B89nQaMvbuXN Bxpw7c1vq/5vTYyTsKBmBc4FzQJ7SNzaw+xUbNy8Y1PG9HRoEY5Qb6W/Nw2zYXk6GImH TmKElEhnmaEozF8mLcqDJCcAAPhncPNIKFgqnrHrInKw2xIOvwmhlwUftO/EbGwucYHC lzNctqPi0fDKo6ZITLT/VopsinuQPwIzeb8Bw4trOqyZ+0DZS8rWx7+sUSX7t0ldkWXm ZYiA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=GhCttEzW; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id f17-20020a50ee91000000b0051e0d7a3fc9si4118015edr.37.2023.07.22.08.16.33 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 22 Jul 2023 08:16:34 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=GhCttEzW; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 996AC3850438 for ; Sat, 22 Jul 2023 15:16:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 996AC3850438 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1690038972; bh=+zqwGxVA0YdNSWIbjWuJuayJCOJ4qyyeFgdf6JrmVG0=; h=Date:To:Cc:Subject:References:In-Reply-To:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=GhCttEzWy3AfWTuNpbjXLmZcncJuvG9Z4b/7kZqRCzIN3VL0037E+h2Qsg+roNBUJ /SbYvKb4tn4iNfolgBp2V/XsbSsy6uHp19SqdafzXWzXzL4IghJlttjbZkM9Jq6Jgt +MHIqu3OMVIksNX9IFde32bJd6pERwi6+qa/cMxQ= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pl1-x630.google.com (mail-pl1-x630.google.com [IPv6:2607:f8b0:4864:20::630]) by sourceware.org (Postfix) with ESMTPS id 8821C386C5B8 for ; Sat, 22 Jul 2023 15:15:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8821C386C5B8 Received: by mail-pl1-x630.google.com with SMTP id d9443c01a7336-1b8ad907ba4so15738955ad.0 for ; Sat, 22 Jul 2023 08:15:20 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1690038919; x=1690643719; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=+zqwGxVA0YdNSWIbjWuJuayJCOJ4qyyeFgdf6JrmVG0=; b=XEXQD0AJhLu8fIHzkkB0cSsjdCRfWumw6aSQyzM2gCzH81NC/U6ZanlIgNTiMAncso gO1PoMArqAYERDTlKU+FG/kke1VI9kF+iDSXyUQL43JXDxNGFMfqw+M+W8jXEVKYHwS5 tXzyhRznWqJNLI48pzUOJMMozKWCE1noRGJuy8xyo3k6Lepsa47nRmslvNXn5dkqjCth 1xmovoz7E/QfkxUXdB+Tqhp1/g7sAjuJWqiuhjqnjyBdHCA0CZIM2XcdTp1O4ZrLIVdH xtK9YWw86DATjDGHJTz93GUlSSvCtVSs8OYaDIFaQneh53fblqnBdZ11ivRUlLEBetFn 0uOg== X-Gm-Message-State: ABy/qLZL5D1dLq08Gady7cFK/ybn8jX7gRMFGTmZakC61efBDIQStw2e mbLlqDnF0nRnuhOIEiIoD7nr8Vn63w0= X-Received: by 2002:a17:90b:33ca:b0:262:d6e9:208b with SMTP id lk10-20020a17090b33ca00b00262d6e9208bmr2989740pjb.4.1690038919041; Sat, 22 Jul 2023 08:15:19 -0700 (PDT) Received: from Thaum.localdomain (59-102-120-25.tpgi.com.au. [59.102.120.25]) by smtp.gmail.com with ESMTPSA id rm10-20020a17090b3eca00b00262e604724dsm5686373pjb.50.2023.07.22.08.15.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 22 Jul 2023 08:15:18 -0700 (PDT) Date: Sun, 23 Jul 2023 01:15:14 +1000 To: gcc-patches@gcc.gnu.org Cc: Jason Merrill , Patrick Palka Subject: [PATCH v5 3/3] c++: Track lifetimes in constant evaluation [PR70331,PR96630,PR98675] Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Spam-Status: No, score=-11.5 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, T_SCC_BODY_TEXT_LINE 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+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1772134328151848852 X-GMAIL-MSGID: 1772134328151848852 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 accessing values outside their lifetime (e.g. following explicit destructor calls). PR c++/96630 PR c++/98675 PR c++/70331 gcc/cp/ChangeLog: * constexpr.cc (constexpr_global_ctx::is_outside_lifetime): New function. (constexpr_global_ctx::get_value): Don't return expired values. (constexpr_global_ctx::get_value_ptr): Likewise. (constexpr_global_ctx::remove_value): Mark value outside lifetime. (outside_lifetime_error): New function. (cxx_eval_call_expression): No longer track save_exprs. (cxx_eval_loop_expr): Likewise. (cxx_eval_constant_expression): Add checks for outside lifetime values. Remove local variables at end of bind exprs, and temporaries after cleanup points. gcc/testsuite/ChangeLog: * 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. * g++.dg/cpp1y/constexpr-lifetime6.C: New test. Signed-off-by: Nathaniel Shead --- gcc/cp/constexpr.cc | 128 ++++++++++++------ .../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 ++ .../g++.dg/cpp1y/constexpr-lifetime6.C | 15 ++ 7 files changed, 169 insertions(+), 42 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 create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime6.C diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 2bf2458c3cd..0ab77dcaf62 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -1148,7 +1148,8 @@ enum constexpr_switch_state { class constexpr_global_ctx { /* Values for any temporaries or local variables within the - constant-expression. */ + constant-expression. Objects outside their lifetime have + value 'void_node'. */ hash_map values; public: /* Number of cxx_eval_constant_expression calls (except skipped ones, @@ -1170,17 +1171,28 @@ public: : constexpr_ops_count (0), cleanups (NULL), modifiable (nullptr), heap_dealloc_count (0) {} + bool is_outside_lifetime (tree t) + { + if (tree *p = values.get (t)) + if (*p == void_node) + return true; + return false; + } tree get_value (tree t) { if (tree *p = values.get (t)) - return *p; + if (*p != void_node) + return *p; return NULL_TREE; } tree *get_value_ptr (tree t) { if (modifiable && !modifiable->contains (t)) return nullptr; - return values.get (t); + if (tree *p = values.get (t)) + if (*p != void_node) + return p; + return nullptr; } void put_value (tree t, tree v) { @@ -1188,7 +1200,13 @@ public: 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)) + values.put (t, void_node); + else + values.remove (t); + } }; /* Helper class for constexpr_global_ctx. In some cases we want to avoid @@ -3111,12 +3129,9 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, gcc_assert (!DECL_BY_REFERENCE (res)); ctx->global->put_value (res, NULL_TREE); - /* Track the callee's evaluated SAVE_EXPRs and TARGET_EXPRs so that - we can forget their values after the call. */ - constexpr_ctx ctx_with_save_exprs = *ctx; - auto_vec save_exprs; - ctx_with_save_exprs.save_exprs = &save_exprs; - ctx_with_save_exprs.call = &new_call; + /* Remember the current call we're evaluating. */ + constexpr_ctx call_ctx = *ctx; + call_ctx.call = &new_call; unsigned save_heap_alloc_count = ctx->global->heap_vars.length (); unsigned save_heap_dealloc_count = ctx->global->heap_dealloc_count; @@ -3127,7 +3142,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, non_constant_p, overflow_p); tree jump_target = NULL_TREE; - cxx_eval_constant_expression (&ctx_with_save_exprs, body, + cxx_eval_constant_expression (&call_ctx, body, vc_discard, non_constant_p, overflow_p, &jump_target); @@ -3183,15 +3198,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, cxx_set_object_constness (ctx, new_obj, /*readonly_p=*/true, non_constant_p, overflow_p); - /* Forget the saved values of the callee's SAVE_EXPRs and - TARGET_EXPRs. */ - 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); @@ -5723,6 +5730,25 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, return r; } +/* Complain about R, a DECL that is accessed outside its lifetime. */ + +static void +outside_lifetime_error (location_t loc, tree r) +{ + if (DECL_NAME (r) == heap_deleted_identifier) + { + /* Provide a more accurate message for deleted variables. */ + error_at (loc, "use of allocated storage after deallocation " + "in a constant expression"); + inform (DECL_SOURCE_LOCATION (r), "allocated here"); + } + else + { + error_at (loc, "accessing object outside its lifetime"); + inform (DECL_SOURCE_LOCATION (r), "declared here"); + } +} + /* Complain about R, a VAR_DECL, not being usable in a constant expression. FUNDEF_P is true if we're checking a constexpr function body. Shared between potential_constant_expression and @@ -6628,7 +6654,6 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p, tree *jump_target) { - constexpr_ctx new_ctx = *ctx; tree local_target; if (!jump_target) { @@ -6666,14 +6691,12 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, default: gcc_unreachable (); } - auto_vec save_exprs; - new_ctx.save_exprs = &save_exprs; do { if (count != -1) { if (body) - cxx_eval_constant_expression (&new_ctx, body, vc_discard, + cxx_eval_constant_expression (ctx, body, vc_discard, non_constant_p, overflow_p, jump_target); if (breaks (jump_target)) @@ -6686,7 +6709,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, *jump_target = NULL_TREE; if (expr) - cxx_eval_constant_expression (&new_ctx, expr, vc_prvalue, + cxx_eval_constant_expression (ctx, expr, vc_prvalue, non_constant_p, overflow_p, jump_target); } @@ -6694,7 +6717,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, if (cond) { tree res - = cxx_eval_constant_expression (&new_ctx, cond, vc_prvalue, + = cxx_eval_constant_expression (ctx, cond, vc_prvalue, non_constant_p, overflow_p, jump_target); if (res) @@ -6709,11 +6732,6 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, gcc_assert (*jump_target); } - /* Forget saved values of SAVE_EXPRs and TARGET_EXPRs. */ - for (tree save_expr : save_exprs) - ctx->global->remove_value (save_expr); - save_exprs.truncate (0); - if (++count >= constexpr_loop_limit) { if (!ctx->quiet) @@ -6731,10 +6749,6 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, && (!switches (jump_target) || count == 0) && !*non_constant_p); - /* Forget saved values of SAVE_EXPRs and TARGET_EXPRs. */ - for (tree save_expr : save_exprs) - ctx->global->remove_value (save_expr); - return NULL_TREE; } @@ -7079,11 +7093,20 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, else if (t == ctx->object) return ctx->ctor; if (VAR_P (t)) - if (tree v = ctx->global->get_value (t)) + { + if (tree v = ctx->global->get_value (t)) { r = v; break; } + if (ctx->global->is_outside_lifetime (t)) + { + if (!ctx->quiet) + outside_lifetime_error (loc, t); + *non_constant_p = true; + break; + } + } if (ctx->manifestly_const_eval == mce_true) maybe_warn_about_constant_value (loc, t); if (COMPLETE_TYPE_P (TREE_TYPE (t)) @@ -7128,6 +7151,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = v; else if (lval) /* Defer in case this is only used for its type. */; + else if (ctx->global->is_outside_lifetime (t)) + { + if (!ctx->quiet) + outside_lifetime_error (loc, t); + *non_constant_p = true; + break; + } else if (COMPLETE_TYPE_P (TREE_TYPE (t)) && is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/false)) { @@ -7367,17 +7397,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; @@ -7893,10 +7934,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/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..2f5ae8db6d5 --- /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; // { 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 + 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..53785521d05 --- /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; // { 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 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..e7e01fe99a7 --- /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; // { dg-error "outside its lifetime" } +} + +constexpr bool x = test(); // { dg-message "in .constexpr. expansion" } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime6.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime6.C new file mode 100644 index 00000000000..45c11e8384e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime6.C @@ -0,0 +1,15 @@ +// { dg-do compile { target c++14 } } +// { dg-options "-Wno-return-local-addr" } + +struct Empty {}; + +constexpr const Empty& empty() { + return Empty{}; // { dg-message "note: declared here" } +} + +constexpr const Empty& empty_parm(Empty e) { // { dg-message "note: declared here" } + return e; +} + +constexpr Empty a = empty(); // { dg-error "outside its lifetime" } +constexpr Empty b = empty_parm({}); // { dg-error "outside its lifetime" }