From patchwork Sat Nov 16 22:23:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 1196222 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-513807-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="x5HzjWSb"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="CLt4Ymly"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47FqWQ02m3z9sNH for ; Sun, 17 Nov 2019 09:23:59 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type :content-transfer-encoding; q=dns; s=default; b=suJ7FUVBbHWdbM47 b8eIO2vSIF7O47EqZKViFXqwPh26HsAmRtCP7N83deK7pINUHI1O1GyzhVIc6lOM Xd7OhaantjmkKzdnRqMLyUccbP9HHZuXgmrKRxmUvAOoPhIn5q6IpaOPyAOd4INT bFdCEWO2Hgpyt7Di8YLeK7Akgxs= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type :content-transfer-encoding; s=default; bh=RyEGOCxGcr+6ZHADrT+FKX pFHp0=; b=x5HzjWSb6xSIWU3ol7D1mLR+p6i46s0tmsiEli6V4z/Q0zrPofVbRD P3vM8oL4zkZnZSKo9YpbE6Nok7yNAJFiiVG9TJcdeIvOhRt1fTJA5XvngvV7V0vG Lh93BaQ/Bk48EbOj3YJiX0ep9YdK10TQIXL22t8nzhrWxmszDTQbM= Received: (qmail 14011 invoked by alias); 16 Nov 2019 22:23:50 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 13996 invoked by uid 89); 16 Nov 2019 22:23:49 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-22.6 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_PASS autolearn=ham version=3.3.1 spammy=gdwarf2, gdwarf-2, island X-HELO: us-smtp-delivery-1.mimecast.com Received: from us-smtp-1.mimecast.com (HELO us-smtp-delivery-1.mimecast.com) (207.211.31.81) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 16 Nov 2019 22:23:44 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573943023; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=4ric1/x4QAVOPv0dkaQLS+2OT1DFnCbg9QplpOFH04Y=; b=CLt4YmlyhPPaoidqE3ZUqN/DcLfYiWt0OPDsajvwaOcVbi9x//7AnGfNi+bTfUPk8mqPtH NUKrUXrnRa+7bRoJLBS9wWsf2LczCn6zznlWO6VMBf0duLCqbAReWfTV5ey5Gh9u0nIDC7 FYnpBCJe0m8meKxmhEDZ5h+SfkG76EY= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-193-SmgAO393M2Wkk7IPcj4g2w-1; Sat, 16 Nov 2019 17:23:40 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id BF6F0107ACC5 for ; Sat, 16 Nov 2019 22:23:39 +0000 (UTC) Received: from redhat.com (ovpn-120-196.rdu2.redhat.com [10.10.120.196]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E46B36293B; Sat, 16 Nov 2019 22:23:38 +0000 (UTC) Date: Sat, 16 Nov 2019 17:23:37 -0500 From: Marek Polacek To: GCC Patches , Jason Merrill , Jakub Jelinek Subject: [C++ PATCH] c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. Message-ID: <20191116222337.GJ3791@redhat.com> MIME-Version: 1.0 User-Agent: Mutt/1.12.1 (2019-06-15) X-Mimecast-Spam-Score: 0 Content-Disposition: inline [ Working virtually on Baker Island. ] This patch implements C++20 P1331, allowing trivial default initialization in constexpr contexts. I used Jakub's patch from the PR which allowed uninitialized variables in constexpr contexts. But the hard part was handling CONSTRUCTOR_NO_CLEARING which is always cleared in cxx_eval_call_expression. We need to set it in the case a constexpr constructor doesn't initialize all the members, so that we can give proper diagnostic instead of value-initializing. A lot of my attempts flopped but then I came up with this approach, which handles various cases as tested in constexpr-init8.C, where S is initialized by a non-default constexpr constructor, and constexpr-init9.C, using delegating constructors. And the best part is that I didn't need any new cx_check_missing_mem_inits calls! Just save the information whether a constructor is missing an init into constexpr_fundef_table and retrieve it when needed. constexpr-init10.C demonstrates that we can now elide a constructor call, this is caused by the walk_field_subobs hunk. I hope that's OK. (No attempts to fix DR 2256 were made.) Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-11-16 Marek Polacek Jakub Jelinek PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. * c-cppbuiltin.c (c_cpp_builtins): Adjust the value of __cpp_constexpr. * class.c (trivial_default_constructor_is_constexpr): Return true in C++20. * constexpr.c (constexpr_fundef): Add a bool member. (retrieve_constexpr_fundef): Initialize it. (cx_check_missing_mem_inits): New pointer-to-bool parameter, with a default value NULL. Allow missing field initializers in C++20. (register_constexpr_fundef): Adjust a call to cx_check_missing_mem_inits. Set missing_init. (cxx_eval_call_expression): Set CONSTRUCTOR_NO_CLEARING on a constexpr constructor that doesn't initialize all the members. * decl.c (check_for_uninitialized_const_var): Permit trivial default initialization in constexpr. * method.c (walk_field_subobs): Still consider a constructor that doesn't initialize all the members constexpr. * g++.dg/cpp0x/constexpr-array6.C: Adjust dg-error. * g++.dg/cpp0x/constexpr-ctor.C: Likewise. * g++.dg/cpp0x/constexpr-diag3.C: Likewise. * g++.dg/cpp0x/constexpr-diag4.C: Likewise. * g++.dg/cpp0x/constexpr-ex3.C: Likewise. * g++.dg/cpp0x/constexpr-template2.C: Likewise. * g++.dg/cpp0x/constexpr-union2.C: Likewise. * g++.dg/cpp0x/lambda/lambda-mangle.C: Rip out a piece of code ... * g++.dg/cpp0x/lambda/lambda-mangle6.C: ... and put it here. * g++.dg/cpp0x/pr79118.C: Adjust dg-error. * g++.dg/cpp1y/constexpr-83921-3.C: Likewise. * g++.dg/cpp1y/constexpr-neg1.C: Likewise. * g++.dg/cpp1z/constexpr-lambda12.C: Likewise. * g++.dg/cpp1z/feat-cxx1z.C: Use -std=c++17. * g++.dg/cpp2a/constexpr-init1.C: New test. * g++.dg/cpp2a/constexpr-init2.C: New test. * g++.dg/cpp2a/constexpr-init3.C: New test. * g++.dg/cpp2a/constexpr-init4.C: New test. * g++.dg/cpp2a/constexpr-init5.C: New test. * g++.dg/cpp2a/constexpr-init6.C: New test. * g++.dg/cpp2a/constexpr-init7.C: New test. * g++.dg/cpp2a/constexpr-init8.C: New test. * g++.dg/cpp2a/constexpr-init9.C: New test. * g++.dg/cpp2a/constexpr-init10.C: New test. * g++.dg/cpp2a/constexpr-try5.C: Adjust dg-error. * g++.dg/cpp2a/feat-cxx2a.C: Test __cpp_constexpr. * g++.dg/cpp2a/lambda-mangle.C: New test. * g++.dg/debug/dwarf2/pr44641.C: Skip for c++2a. * g++.dg/ext/stmtexpr21.C: Adjust dg-error. diff --git gcc/c-family/c-cppbuiltin.c gcc/c-family/c-cppbuiltin.c index 76d1e4a380e..9766d7f96c4 100644 --- gcc/c-family/c-cppbuiltin.c +++ gcc/c-family/c-cppbuiltin.c @@ -972,7 +972,8 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_fold_expressions=201603L"); cpp_define (pfile, "__cpp_nontype_template_args=201411L"); cpp_define (pfile, "__cpp_range_based_for=201603L"); - cpp_define (pfile, "__cpp_constexpr=201603L"); + if (cxx_dialect <= cxx17) + cpp_define (pfile, "__cpp_constexpr=201603L"); cpp_define (pfile, "__cpp_if_constexpr=201606L"); cpp_define (pfile, "__cpp_capture_star_this=201603L"); cpp_define (pfile, "__cpp_inline_variables=201606L"); @@ -991,6 +992,7 @@ c_cpp_builtins (cpp_reader *pfile) { /* Set feature test macros for C++2a. */ cpp_define (pfile, "__cpp_conditional_explicit=201806L"); + cpp_define (pfile, "__cpp_constexpr=201907L"); cpp_define (pfile, "__cpp_constinit=201907L"); cpp_define (pfile, "__cpp_nontype_template_parameter_class=201806L"); cpp_define (pfile, "__cpp_impl_destroying_delete=201806L"); diff --git gcc/cp/class.c gcc/cp/class.c index ef1d5136963..1fd5a7864e5 100644 --- gcc/cp/class.c +++ gcc/cp/class.c @@ -5234,8 +5234,14 @@ trivial_default_constructor_is_constexpr (tree t) /* A defaulted trivial default constructor is constexpr if there is nothing to initialize. */ gcc_assert (!TYPE_HAS_COMPLEX_DFLT (t)); - /* A class with a vptr doesn't have a trivial default ctor. */ - return is_really_empty_class (t, /*ignore_vptr*/true); + /* A class with a vptr doesn't have a trivial default ctor. + In C++20, a class can have transient uninitialized members, e.g.: + + struct S { int i; constexpr S() = default; }; + + should work. */ + return (cxx_dialect >= cxx2a + || is_really_empty_class (t, /*ignore_vptr*/true)); } /* Returns true iff class T has a constexpr default constructor. */ diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c index 8c79b0484fc..2161aa62d44 100644 --- gcc/cp/constexpr.c +++ gcc/cp/constexpr.c @@ -142,6 +142,7 @@ struct GTY((for_user)) constexpr_fundef { tree body; tree parms; tree result; + bool missing_init; }; struct constexpr_fundef_hasher : ggc_ptr_hash @@ -182,7 +183,7 @@ retrieve_constexpr_fundef (tree fun) if (constexpr_fundef_table == NULL) return NULL; - constexpr_fundef fundef = { fun, NULL, NULL, NULL }; + constexpr_fundef fundef = { fun, NULL, NULL, NULL, false }; return constexpr_fundef_table->find (&fundef); } @@ -762,10 +763,13 @@ massage_constexpr_body (tree fun, tree body) } /* CTYPE is a type constructed from BODY. Return true if some - bases/fields are uninitialized, and complain if COMPLAIN. */ + bases/fields are uninitialized, and complain if COMPLAIN. + In C++20, we allow missing field initializers. In such a case + record that in MISSING_INIT, if non-null. */ static bool -cx_check_missing_mem_inits (tree ctype, tree body, bool complain) +cx_check_missing_mem_inits (tree ctype, tree body, bool complain, + bool *missing_init = NULL) { unsigned nelts = 0; @@ -779,7 +783,9 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain) if (TREE_CODE (ctype) == UNION_TYPE) { - if (nelts == 0 && next_initializable_field (field)) + if (cxx_dialect < cxx2a + && nelts == 0 + && next_initializable_field (field)) { if (complain) error ("% constructor for union %qT must " @@ -815,13 +821,19 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain) continue; if (ANON_AGGR_TYPE_P (TREE_TYPE (field))) { - /* Recurse to check the anonummous aggregate member. */ + /* Recurse to check the anonymous aggregate member. */ bad |= cx_check_missing_mem_inits - (TREE_TYPE (field), NULL_TREE, complain); + (TREE_TYPE (field), NULL_TREE, complain, missing_init); if (bad && !complain) return true; continue; } + if (cxx_dialect >= cxx2a) + { + if (missing_init) + *missing_init = true; + continue; + } ftype = strip_array_types (TREE_TYPE (field)); if (type_has_constexpr_default_constructor (ftype)) { @@ -847,7 +859,8 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain) { /* Check the anonymous aggregate initializer is valid. */ bad |= cx_check_missing_mem_inits - (TREE_TYPE (index), CONSTRUCTOR_ELT (body, i)->value, complain); + (TREE_TYPE (index), CONSTRUCTOR_ELT (body, i)->value, complain, + missing_init); if (bad && !complain) return true; } @@ -888,9 +901,11 @@ register_constexpr_fundef (tree fun, tree body) return NULL; } + bool missing_init = false; if (DECL_CONSTRUCTOR_P (fun) && cx_check_missing_mem_inits (DECL_CONTEXT (fun), - massaged, !DECL_GENERATED_P (fun))) + massaged, !DECL_GENERATED_P (fun), + &missing_init)) return NULL; /* Create the constexpr function table if necessary. */ @@ -908,6 +923,7 @@ register_constexpr_fundef (tree fun, tree body) DECL_CONTEXT (DECL_RESULT (fun)) = fun; } entry.body = copy_fn (fun, entry.parms, entry.result); + entry.missing_init = missing_init; current_function_decl = saved_fn; slot = constexpr_fundef_table->find_slot (&entry, INSERT); if (clear_ctx) @@ -2149,9 +2165,24 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, entry->result = result; } - /* The result of a constexpr function must be completely initialized. */ + /* The result of a constexpr function must be completely initialized. + Except in C++20 where a constexpr constructor doesn't necessarily + have to initialize all the fields, so we set CONSTRUCTOR_NO_CLEARING + in order to detect reading an unitialized object in constexpr instead + of value-initializing it. */ if (TREE_CODE (result) == CONSTRUCTOR) - clear_no_implicit_zero (result); + { + /* But do clear the flag in nested constructors. */ + clear_no_implicit_zero (result); + if (cxx_dialect >= cxx2a + && DECL_CONSTRUCTOR_P (fun) + && DECL_DECLARED_CONSTEXPR_P (fun)) + { + constexpr_fundef *f = retrieve_constexpr_fundef (fun); + if (f && f->missing_init) + CONSTRUCTOR_NO_CLEARING (result) = true; + } + } pop_cx_call_context (); return result; diff --git gcc/cp/decl.c gcc/cp/decl.c index 86e38f4af69..ab6da6080a5 100644 --- gcc/cp/decl.c +++ gcc/cp/decl.c @@ -5835,8 +5835,12 @@ check_for_uninitialized_const_var (tree decl, bool constexpr_context_p, 7.1.6 */ if (VAR_P (decl) && !TYPE_REF_P (type) - && (constexpr_context_p - || CP_TYPE_CONST_P (type) || var_in_constexpr_fn (decl)) + && (CP_TYPE_CONST_P (type) + /* C++20 permits trivial default initialization in constexpr + context (P1331R2). */ + || (cxx_dialect < cxx2a + && (constexpr_context_p + || var_in_constexpr_fn (decl)))) && !DECL_NONTRIVIALLY_INITIALIZED_P (decl)) { tree field = default_init_uninitialized_part (type); @@ -5845,7 +5849,7 @@ check_for_uninitialized_const_var (tree decl, bool constexpr_context_p, bool show_notes = true; - if (!constexpr_context_p) + if (!constexpr_context_p || cxx_dialect >= cxx2a) { if (CP_TYPE_CONST_P (type)) { diff --git gcc/cp/method.c gcc/cp/method.c index acba6c6da8c..39782970716 100644 --- gcc/cp/method.c +++ gcc/cp/method.c @@ -1985,10 +1985,12 @@ walk_field_subobs (tree fields, special_function_kind sfk, tree fnname, if (bad && deleted_p) *deleted_p = true; - /* For an implicitly-defined default constructor to be constexpr, - every member must have a user-provided default constructor or - an explicit initializer. */ - if (constexpr_p && !CLASS_TYPE_P (mem_type) + /* Before C++20, for an implicitly-defined default constructor to + be constexpr, every member must have a user-provided default + constructor or an explicit initializer. */ + if (constexpr_p + && cxx_dialect < cxx2a + && !CLASS_TYPE_P (mem_type) && TREE_CODE (DECL_CONTEXT (field)) != UNION_TYPE) { *constexpr_p = false; diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-array6.C gcc/testsuite/g++.dg/cpp0x/constexpr-array6.C index 16eacdde440..48dae5d9609 100644 --- gcc/testsuite/g++.dg/cpp0x/constexpr-array6.C +++ gcc/testsuite/g++.dg/cpp0x/constexpr-array6.C @@ -4,7 +4,7 @@ struct A { int i; - constexpr A() {} // { dg-error "A::i" } + constexpr A() {} // { dg-error "A::i" "" { target c++17_down } } }; struct B @@ -12,4 +12,5 @@ struct B A a; }; -constexpr B b[] = { {} }; // { dg-error "A::A" } +constexpr B b[] = { {} }; // { dg-error "A::A" "" { target c++17_down } } +// { dg-error "is not a constant expression" "" { target c++2a } .-1 } diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C index 55beda7c49f..1d0fa479cbc 100644 --- gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C +++ gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C @@ -3,5 +3,5 @@ struct A { int i; - constexpr A() { } // { dg-error "A::i" } + constexpr A() { } // { dg-error "A::i" "" { target c++17_down } } }; diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C index e54b26c7f6a..1c43569615c 100644 --- gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C +++ gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C @@ -48,7 +48,7 @@ struct Def { int _M_i; // { dg-message "does not initialize" } - constexpr Def() = default; // { dg-error "implicit declaration is not .constexpr." } + constexpr Def() = default; // { dg-error "implicit declaration is not .constexpr." "" { target c++17_down } } }; constexpr Def defobj; // { dg-error "uninitialized" } diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C index 13ca6fa2390..c603bdd1a00 100644 --- gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C +++ gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C @@ -21,5 +21,5 @@ struct A1 struct B1 { A1 a1; - constexpr B1() {} // { dg-error "B1::a1" } + constexpr B1() {} // { dg-error "B1::a1" "" { target c++17_down } } }; diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C index a5893563eec..9d6d5ff587c 100644 --- gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C +++ gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C @@ -6,7 +6,7 @@ struct A { int i; - constexpr A(int _i) { i = _i; } // { dg-error "empty body|A::i" } + constexpr A(int _i) { i = _i; } // { dg-error "empty body|A::i" "" { target c++17_down } } }; template diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C index 12a8d42b31f..71eb559a24c 100644 --- gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C +++ gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C @@ -3,7 +3,7 @@ template struct A { T t; - constexpr A() { } // { dg-error "::t" } + constexpr A() { } // { dg-error "::t" "" { target c++17_down } } }; int main() diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-union2.C gcc/testsuite/g++.dg/cpp0x/constexpr-union2.C index 1a5e832ac34..c22ecc99efb 100644 --- gcc/testsuite/g++.dg/cpp0x/constexpr-union2.C +++ gcc/testsuite/g++.dg/cpp0x/constexpr-union2.C @@ -14,5 +14,5 @@ union bar int x; short y; - constexpr bar() = default; // { dg-error "constexpr" } + constexpr bar() = default; // { dg-error "constexpr" "" { target c++17_down } } }; diff --git gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C index 15b8b79ecbc..7894ef3051e 100644 --- gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C +++ gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C @@ -47,17 +47,6 @@ struct S { []{return 3;}()); }; -template struct R { - static int x; -}; -// "int i;" makes the op() non-constexpr in C++17. -template int R::x = []{int i; return 1;}(); -template int R::x; -// Type of lambda in intializer of R::x: N1RIiE1xMUlvE_E -// Corresponding operator(): _ZNK1RIiE1xMUlvE_clEv -// { dg-final { scan-assembler "_ZNK1RIiE1xMUlvE_clEv" } } -// { dg-final { scan-assembler "weak\[^\n\r\]*_?_ZNK1RIiE1xMUlvE_clEv" { target { ! { *-*-mingw* *-*-cygwin } } } } } - void bar() { // lambdas in non-vague linkage functions have internal linkage. diff --git gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle6.C gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle6.C new file mode 100644 index 00000000000..9ec13e79bbf --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle6.C @@ -0,0 +1,15 @@ +// Test lambda mangling +// { dg-do compile { target { c++11 && c++17_down } } } +// { dg-require-weak "" } +// { dg-options "-fno-inline" } + +template struct R { + static int x; +}; +// "int i;" makes the op() non-constexpr in C++17. In C++20, it does not. +template int R::x = []{int i; return 1;}(); +template int R::x; +// Type of lambda in intializer of R::x: N1RIiE1xMUlvE_E +// Corresponding operator(): _ZNK1RIiE1xMUlvE_clEv +// { dg-final { scan-assembler "_ZNK1RIiE1xMUlvE_clEv" } } +// { dg-final { scan-assembler "weak\[^\n\r\]*_?_ZNK1RIiE1xMUlvE_clEv" { target { ! { *-*-mingw* *-*-cygwin } } } } } diff --git gcc/testsuite/g++.dg/cpp0x/pr79118.C gcc/testsuite/g++.dg/cpp0x/pr79118.C index 5db22a96dd4..616b51ea29a 100644 --- gcc/testsuite/g++.dg/cpp0x/pr79118.C +++ gcc/testsuite/g++.dg/cpp0x/pr79118.C @@ -13,7 +13,7 @@ struct One constexpr One () : a(), b() {} // { dg-error "multiple" } constexpr One (int) : a() {} constexpr One (unsigned) : b () {} - constexpr One (void *) {} // { dg-error "exactly one" } + constexpr One (void *) {} // { dg-error "exactly one" "" { target c++17_down } } }; One a (); @@ -30,10 +30,10 @@ struct Two }; constexpr Two () : a(), b() {} - constexpr Two (int) : a() {} // { dg-error "b' must be initialized" } - constexpr Two (unsigned) : b () {} // { dg-error "a' must be initialized" } - constexpr Two (void *) {} // { dg-error "a' must be initialized" } - // { dg-error "b' must be initialized" "" { target *-*-* } .-1 } + constexpr Two (int) : a() {} // { dg-error "b' must be initialized" "" { target c++17_down } } + constexpr Two (unsigned) : b () {} // { dg-error "a' must be initialized" "" { target c++17_down } } + constexpr Two (void *) {} // { dg-error "a' must be initialized" "" { target c++17_down } } + // { dg-error "b' must be initialized" "" { target c++17_down } .-1 } }; Two e (); diff --git gcc/testsuite/g++.dg/cpp1y/constexpr-83921-3.C gcc/testsuite/g++.dg/cpp1y/constexpr-83921-3.C index 4b1ed5c3a87..2f1218693e0 100644 --- gcc/testsuite/g++.dg/cpp1y/constexpr-83921-3.C +++ gcc/testsuite/g++.dg/cpp1y/constexpr-83921-3.C @@ -2,4 +2,4 @@ // { dg-do compile { target c++14 } } struct Foo { int m; }; -constexpr void test() { Foo f; } // { dg-error "uninitialized" } +constexpr void test() { Foo f; } // { dg-error "uninitialized" "" { target c++17_down } } diff --git gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C index d82dbada1bf..53f0f1f7a2b 100644 --- gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C +++ gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C @@ -8,7 +8,7 @@ constexpr int f(int i) { goto foo; // { dg-error "goto" } foo: asm("foo"); // { dg-error "asm" "" { target c++17_down } } - int k; // { dg-error "uninitialized" } + int k; // { dg-error "uninitialized" "" { target c++17_down } } A a; // { dg-error "non-literal" } return i; } diff --git gcc/testsuite/g++.dg/cpp1z/constexpr-lambda12.C gcc/testsuite/g++.dg/cpp1z/constexpr-lambda12.C index a59bf497b30..93b53273741 100644 --- gcc/testsuite/g++.dg/cpp1z/constexpr-lambda12.C +++ gcc/testsuite/g++.dg/cpp1z/constexpr-lambda12.C @@ -3,7 +3,7 @@ void f(int i) { [i]() constexpr { - int j; // { dg-error "uninitialized" } + int j; // { dg-error "uninitialized" "" { target c++17_down } } j = i; return j; }(); diff --git gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C index a18d6aea985..aee1d692a4e 100644 --- gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C +++ gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C @@ -1,5 +1,4 @@ -// { dg-do compile { target c++17 } } -// { dg-options "-I${srcdir}/g++.dg/cpp1y -I${srcdir}/g++.dg/cpp1y/testinc" } +// { dg-options "-std=c++17 -I${srcdir}/g++.dg/cpp1y -I${srcdir}/g++.dg/cpp1y/testinc" } // C++98 features: diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C new file mode 100644 index 00000000000..b2248006c03 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C @@ -0,0 +1,100 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } +// Test basic use. + +struct S { + int i; + constexpr S(bool b) { + if (b) + i = 42; + } +}; +constexpr S s1(true); +constexpr S s2(false); // { dg-error "not a constant expression" } + +constexpr int +fn1 (int x) +{ + int a; + a = 5; + return x + a; +} + +static_assert (fn1 (2) == 7); + +constexpr int +fn2 (int x) +{ + const int a; // { dg-error "uninitialized .const a." } + constexpr int b; // { dg-error "uninitialized .const b." } + return x; +} + +constexpr int +fn3 (int x) +{ + int a; // { dg-message ".int a. is not const" } + return x + a; +} + +constexpr int a = fn3 (5); // { dg-error "the value of .a. is not usable in a constant expression" } +// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 } + +constexpr int +fn4 () +{ + struct S { int a = -5; int b; } s; + return s.a; +} + +static_assert (fn4 () == -5); + +constexpr int +fn5 () +{ + struct S { int a = 9; int b; } s; + return s.b; +} + +constexpr int b = fn5 (); // { dg-error "accessing uninitialized member" } +// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 } + +constexpr int +fn6 () +{ + int a; + return 42; +} + +static_assert (fn6 () == 42); + +constexpr int +fn7 (bool b) +{ + int a; // { dg-message ".int a. is not const" } + if (b) + a = 42; + return a; +} + +static_assert (fn7 (true) == 42); +static_assert (fn7 (false) == 42); // { dg-error "non-constant condition|the value of .a. is not usable" } +// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 } + +constexpr int +fn8 (int n) +{ + int r; + switch (n) + { + case 1: + r = n; + return r; + case 42: + r = n; + return r; + } +} + +static_assert (fn8 (1) == 1); +static_assert (fn8 (42) == 42); diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-init10.C gcc/testsuite/g++.dg/cpp2a/constexpr-init10.C new file mode 100644 index 00000000000..0d7b724a040 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/constexpr-init10.C @@ -0,0 +1,11 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } +// ??? In c++2a we don't emit a call to _ZN3FooI3ArgEC1Ev. + +struct Arg; +struct Base { + int i; + virtual ~Base(); +}; +template struct Foo : Base { }; +Foo a; diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-init2.C gcc/testsuite/g++.dg/cpp2a/constexpr-init2.C new file mode 100644 index 00000000000..541da1c023f --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/constexpr-init2.C @@ -0,0 +1,15 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct A +{ + int i; + constexpr A() : i{} {} +}; + +struct B +{ + A a; +}; + +constexpr B b[] = { {} }; diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-init3.C gcc/testsuite/g++.dg/cpp2a/constexpr-init3.C new file mode 100644 index 00000000000..dd2735289cb --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/constexpr-init3.C @@ -0,0 +1,16 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct A +{ + int i; + constexpr A() {} +}; + +struct B +{ + A a; +}; + +// A::i not initialized. +constexpr B b[] = { {} }; // { dg-error "is not a constant expression" } diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-init4.C gcc/testsuite/g++.dg/cpp2a/constexpr-init4.C new file mode 100644 index 00000000000..dd614ede2c6 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/constexpr-init4.C @@ -0,0 +1,61 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +// This bullet in [dcl.constexpr] is now gone: +// - every non-static data member and base class sub-object shall be initialized + +struct A { + int i; + constexpr A(int _i) { i = _i; } +}; + +struct B { + int i; + constexpr B() { } +}; + +// Anonymous members. +struct E { + int a; + union { + char b; + __extension__ struct { + double c; + long d; + }; + union { + char e; + void *f; + }; + }; + __extension__ struct { + long long g; + __extension__ struct { + int h; + double i; + }; + union { + char *j; + E *k; + }; + }; + + // Completely initialized. + constexpr E(int(&)[1]) : a(), b(), g(), h(), i(), j() {} + constexpr E(int(&)[3]) : a(), e(), g(), h(), i(), k() {} + constexpr E(int(&)[7]) : a(), b(), g(), h(), i(), j() {} + constexpr E(int(&)[8]) : a(), f(), g(), h(), i(), k() {} + constexpr E(int(&)[9]) : a(), c(), d(), g(), h(), i(), k() {} + + // Missing d, i, j/k union init. + constexpr E(int(&)[2]) : a(), c(), g(), h() {} + + // Missing h, j/k union init. + constexpr E(int(&)[4]) : a(), c(), d(), g(), i() {} + + // Missing b/c/d/e/f union init. + constexpr E(int(&)[5]) : a(), g(), h(), i(), k() {} + + // Missing a, b/c/d/e/f union, g/h/i/j/k struct init. + constexpr E(int(&)[6]) {} +}; diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-init5.C gcc/testsuite/g++.dg/cpp2a/constexpr-init5.C new file mode 100644 index 00000000000..5c2b545086c --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/constexpr-init5.C @@ -0,0 +1,23 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct S { int i; }; + +constexpr void +fn () +{ + S s; + + []() constexpr { + int i; + }(); +} + +constexpr int +fn2 () +{ + return __extension__ ({ int n; n; }); +} + +constexpr int i = fn2 (); // { dg-error "not usable in a constant expression" } +// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 } diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-init6.C gcc/testsuite/g++.dg/cpp2a/constexpr-init6.C new file mode 100644 index 00000000000..a2994f5272c --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/constexpr-init6.C @@ -0,0 +1,26 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +/* We used to get the "constexpr constructor for union S:: + must initialize exactly one non-static data member" error, but not anymore + in C++20. */ + +struct S { + union { + int i; + double d; + }; + constexpr S() { } +}; + +union U { + int a; + constexpr U() { } +}; + +struct W { + union { + int a; + }; + constexpr W() { } +}; diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-init7.C gcc/testsuite/g++.dg/cpp2a/constexpr-init7.C new file mode 100644 index 00000000000..dd2741efa8c --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/constexpr-init7.C @@ -0,0 +1,63 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct S { + int a = 1; + constexpr S() = default; +}; + +constexpr S s; + +union U { + int a = 1; + constexpr U() = default; +}; + +constexpr U u; + +struct S2 { + int a; + constexpr S2() = default; +}; + +constexpr S2 s2; // { dg-error "uninitialized .const s2." } + +union U2 { + int a; + constexpr U2() = default; +}; + +constexpr U2 u2; // { dg-error "uninitialized .const u2." } + +struct S3 { + // FIXME if it's anonymous union, we don't give the error below + union { + int a; + } u; + constexpr S3() = default; +}; + +constexpr S3 s3; // { dg-error "uninitialized .const s3." } + +struct S4 { + // FIXME if it's anonymous union, we don't give the error below + union { + int n; + } u; + constexpr S4() = default; +}; + +constexpr S4 s4; // { dg-error "uninitialized .const s4." } + +struct S5 { + union { + int n = 0; + }; + // FIXME if it's anonymous union, we don't give the error below + union { + int m; + } u; + constexpr S5() = default; +}; + +constexpr S5 s5; // { dg-error "uninitialized .const s5.|not a constant expression" } diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-init8.C gcc/testsuite/g++.dg/cpp2a/constexpr-init8.C new file mode 100644 index 00000000000..0d5a4a79c90 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/constexpr-init8.C @@ -0,0 +1,15 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct S { + constexpr S(int) {} +}; + +struct W { + constexpr W(int) : s(8), p() {} + + S s; + int *p; +}; + +constexpr auto a = W(42); diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-init9.C gcc/testsuite/g++.dg/cpp2a/constexpr-init9.C new file mode 100644 index 00000000000..b44098cc89b --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/constexpr-init9.C @@ -0,0 +1,17 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct S { + constexpr S(int) {} +}; + +struct W { + constexpr W(int (&)[8]) : W(8) { } + constexpr W(int) : s(8), p() {} + + S s; + int *p; +}; + +int arr[8]; +constexpr auto a = W(arr); diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C index 47cdce88e36..3b51bf7c901 100644 --- gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C +++ gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C @@ -4,13 +4,13 @@ constexpr int foo () try { // { dg-warning "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } } - int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" } + int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" "" { target c++17_down } } static double b = 1.0;// { dg-error "'b' declared 'static' in 'constexpr' function" } goto l; // { dg-error "'goto' in 'constexpr' function" } l:; return 0; } catch (...) { - long int c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" } + long int c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" "" { target c++17_down } } static float d = 2.0f;// { dg-error "'d' declared 'static' in 'constexpr' function" } goto l2; // { dg-error "'goto' in 'constexpr' function" } l2:; @@ -19,19 +19,19 @@ try { // { dg-warning "function-try-block body of 'constexpr' function only av constexpr int bar () { - int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" } + int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" "" { target c++17_down } } static long double b = 3.0;// { dg-error "'b' declared 'static' in 'constexpr' function" } goto l; // { dg-error "'goto' in 'constexpr' function" } l:; try { // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } } - short c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" } + short c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" "" { target c++17_down } } static float d; // { dg-error "'d' declared 'static' in 'constexpr' function" } - // { dg-error "uninitialized variable 'd' in 'constexpr' function" "" { target *-*-* } .-1 } + // { dg-error "uninitialized variable 'd' in 'constexpr' function" "" { target c++17_down } .-1 } goto l2; // { dg-error "'goto' in 'constexpr' function" } l2:; return 0; } catch (int) { - char e; // { dg-error "uninitialized variable 'e' in 'constexpr' function" } + char e; // { dg-error "uninitialized variable 'e' in 'constexpr' function" "" { target c++17_down } } static int f = 5; // { dg-error "'f' declared 'static' in 'constexpr' function" } goto l3; // { dg-error "'goto' in 'constexpr' function" } l3:; diff --git gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C index 95251c2f5c6..7b96b76a3f3 100644 --- gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C +++ gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C @@ -134,8 +134,8 @@ #ifndef __cpp_constexpr # error "__cpp_constexpr" -#elif __cpp_constexpr != 201603 -# error "__cpp_constexpr != 201603" +#elif __cpp_constexpr != 201907 +# error "__cpp_constexpr != 201907" #endif #ifndef __cpp_decltype_auto diff --git gcc/testsuite/g++.dg/cpp2a/lambda-mangle.C gcc/testsuite/g++.dg/cpp2a/lambda-mangle.C new file mode 100644 index 00000000000..8ee9b0327a5 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/lambda-mangle.C @@ -0,0 +1,15 @@ +// Test lambda mangling +// { dg-do compile { target c++2a } } +// { dg-require-weak "" } +// { dg-options "-fno-inline" } + +template struct R { + static int x; +}; +// "int i;" makes the op() non-constexpr in C++17. In C++20, it does not. +template int R::x = []{int i; return 1;}(); +template int R::x; +// Type of lambda in intializer of R::x: N1RIiE1xMUlvE_E +// Corresponding operator(): _ZNK1RIiE1xMUlvE_clEv +// { dg-final { scan-assembler-not "_ZNK1RIiE1xMUlvE_clEv" } } +// { dg-final { scan-assembler-not "weak\[^\n\r\]*_?_ZNK1RIiE1xMUlvE_clEv" } } diff --git gcc/testsuite/g++.dg/debug/dwarf2/pr44641.C gcc/testsuite/g++.dg/debug/dwarf2/pr44641.C index d50df25f693..1139f412fda 100644 --- gcc/testsuite/g++.dg/debug/dwarf2/pr44641.C +++ gcc/testsuite/g++.dg/debug/dwarf2/pr44641.C @@ -1,5 +1,5 @@ // Origin: PR 44641 -// { dg-do compile } +// { dg-do compile { target c++17_down } } // { dg-options "-gdwarf-2 -O0 -dA" } template struct MisplacedDbg; @@ -40,3 +40,11 @@ struct MisplacedDbg // { dg-function-on-line {_ZN12MisplacedDbgI3ArgEC[12]Ev} { static MisplacedDbg static_var1; static MisplacedDbg static_var2; static MisplacedDbg static_var3; + +// This test is skipped in C++20 because we consider the default constructor +// MisplacedDbg() constexpr despite the uninitialized member "int i;". So +// the calls to +// MisplacedDbg::MisplacedDbg() +// MisplacedDbg::MisplacedDbg() +// MisplacedDbg::MisplacedDbg() +// are elided. (This comment is here not to mess up the line numbers.) diff --git gcc/testsuite/g++.dg/ext/stmtexpr21.C gcc/testsuite/g++.dg/ext/stmtexpr21.C index 259cb2f1913..97052a117a7 100644 --- gcc/testsuite/g++.dg/ext/stmtexpr21.C +++ gcc/testsuite/g++.dg/ext/stmtexpr21.C @@ -7,7 +7,7 @@ struct test { const int *addr; }; const test* setup() { static constexpr test atest = - { ({ int inner; (const int*)(0); }) }; // { dg-error "uninitialized" } + { ({ int inner; (const int*)(0); }) }; // { dg-error "uninitialized" "" { target c++17_down } } return &atest; }