From patchwork Sat Jun 1 18:07:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Gillespie X-Patchwork-Id: 1108805 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-502148-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=swgillespie.me 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 45GTn558MRz9sNp for ; Sun, 2 Jun 2019 04:07:30 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:references:in-reply-to :content-type:content-transfer-encoding:mime-version; q=dns; s= default; b=ry0McJSpzwL50MNY7VTvXoz0IJjiIrwEuw4YDeWMyTzRVeyKTVCN4 Eft50LCUtNtRKsjhz+MONV3iIhcboV6N8d0zReLX6d9m77oky9UZKMMO9Z0yXD51 Mtzkt7FNk+fklBBtJNMuqddhR//HvIelIQSl34xHOW/6CaAWLeP6IQ= 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:from :to:cc:subject:date:message-id:references:in-reply-to :content-type:content-transfer-encoding:mime-version; s=default; bh=YlCILShJypNw2nEcRvlWubzzz3k=; b=MbymWIsiHxoYyKpq5v1C7ocg9odK 3QxzoVeYCk/sHiwJ4AgTFyhrc6jbkPfLWCaLggQllFOX7fS2fZKKyTnULQJoYwcD I20pNFoHNppF6T5YU3yGbL7QvFnhdQFawQxqmyoPZcaKxE83qHo9d5iew1/qaBBR IrFFkWt1fiDO/+g= Received: (qmail 127226 invoked by alias); 1 Jun 2019 18:07:22 -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 127218 invoked by uid 89); 1 Jun 2019 18:07:21 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.2 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_INFOUSMEBIZ, MIME_BASE64_BLANKS, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.1 spammy=aligned, sk:decl_no, destructors, @group X-HELO: NAM01-SN1-obe.outbound.protection.outlook.com Received: from mail-eopbgr820093.outbound.protection.outlook.com (HELO NAM01-SN1-obe.outbound.protection.outlook.com) (40.107.82.93) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 01 Jun 2019 18:07:19 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=NETORGFT2371311.onmicrosoft.com; s=selector1-NETORGFT2371311-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=jyNzJ1f1pm+DnUf65u3xSuZCY3iWlqDxSnLrizAl0Ss=; b=OBwRDKNQTMI84iX5b3CnwUeycbefNOguO9jV2+h29fZs6FyyiPs09weDOup0M7fFbM42rsgMf/1pV090PwJftuPflY50TOyyTx6UH10yim2PWmJvHCx4NiBDrFQRLrSVd5pOw2r4zSJAYF/Kbc9xi3AqEOR0DRpKDwiYnDZR0NQ= Received: from DM6PR10MB3259.namprd10.prod.outlook.com (20.179.162.76) by DM6PR10MB3209.namprd10.prod.outlook.com (20.179.161.142) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1943.16; Sat, 1 Jun 2019 18:07:16 +0000 Received: from DM6PR10MB3259.namprd10.prod.outlook.com ([fe80::8d4a:edfb:11ec:d13d]) by DM6PR10MB3259.namprd10.prod.outlook.com ([fe80::8d4a:edfb:11ec:d13d%7]) with mapi id 15.20.1943.018; Sat, 1 Jun 2019 18:07:16 +0000 From: Sean Gillespie To: "gcc-patches@gcc.gnu.org" CC: Sean Gillespie Subject: [PATCH v2] PR71482: Add -Wglobal-constructors Date: Sat, 1 Jun 2019 18:07:16 +0000 Message-ID: <20190601180655.4671-1-sean@swgillespie.me> References: <9de82d0c-ecad-e42b-014b-3ec3389393be@gmail.com> In-Reply-To: <9de82d0c-ecad-e42b-014b-3ec3389393be@gmail.com> authentication-results: spf=none (sender IP is ) smtp.mailfrom=sean@swgillespie.me; x-ms-oob-tlc-oobclassifiers: OLM:9508; received-spf: None (protection.outlook.com: swgillespie.me does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 MIME-Version: 1.0 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: sean@swgillespie.me This adds a new warning, -Wglobal-constructors, that warns whenever a decl requires a global constructor or destructor. Global destructors are required whenever a decl with thread_local or global storage is declared with a type with a nontrivial destructor. Global constructors are required whenever a declaration's initializer is a non-trivial, non-constant initializtion. This warning mirrors the Clang option -Wglobal-constructors, which warns on the same thing. -Wglobal-constructors was present in Apple's GCC and later made its way into Clang. Bootstrapped and regression-tested on x86-64 linux, new tests passing. gcc/ChangeLog: 2019-05-28 Sean Gillespie PR c++/71482 * doc/invoke.texi: Add new flag -Wglobal-constructors. gcc/c-family/ChangeLog: 2019-05-28 Sean Gillespie PR c++/71482 * c.opt: Add new flag -Wglobal-constructors. gcc/cp/ChangeLog: 2019-05-28 Sean Gillespie PR c++/71482 * decl.c (expand_static_init): Warn if a thread local or static decl requires a non-trivial constructor or destructor. gcc/testsuite/ChangeLog: 2019-05-28 Sean Gillespie PR c++/71482 * g++.dg/warn/global-constructors-1.C: New test. * g++.dg/warn/global-constructors-2.C: New test. --- gcc/c-family/c.opt | 4 ++ gcc/cp/decl.c | 22 ++++++-- gcc/doc/invoke.texi | 35 ++++++++++++ .../g++.dg/warn/global-constructors-1.C | 53 +++++++++++++++++++ .../g++.dg/warn/global-constructors-2.C | 49 +++++++++++++++++ 5 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/global-constructors-1.C create mode 100644 gcc/testsuite/g++.dg/warn/global-constructors-2.C diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 046d489f7eb..21f12d4f7b2 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -613,6 +613,10 @@ Wformat-truncation= C ObjC C++ LTO ObjC++ Joined RejectNegative UInteger Var(warn_format_trunc) Warning LangEnabledBy(C ObjC C++ LTO ObjC++,Wformat=, warn_format >= 1, 0) IntegerRange(0, 2) Warn about calls to snprintf and similar functions that truncate output. +Wglobal-constructors +C++ ObjC++ Var(warn_global_constructors) Warning +Warn about objects with static storage duration that require dynamic initialization or have nontrivial destructors. + Wif-not-aligned C ObjC C++ ObjC++ Var(warn_if_not_aligned) Init(1) Warning Warn when the field in a struct is not aligned. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 19d14a6a5e9..8dc366aa0c6 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -8324,10 +8324,10 @@ expand_static_init (tree decl, tree init) return; } + location_t dloc = DECL_SOURCE_LOCATION (decl); if (CP_DECL_THREAD_LOCAL_P (decl) && DECL_GNU_TLS_P (decl) && !DECL_FUNCTION_SCOPE_P (decl)) { - location_t dloc = DECL_SOURCE_LOCATION (decl); if (init) error_at (dloc, "non-local variable %qD declared %<__thread%> " "needs dynamic initialization", decl); @@ -8467,10 +8467,24 @@ expand_static_init (tree decl, tree init) finish_then_clause (if_stmt); finish_if_stmt (if_stmt); } - else if (CP_DECL_THREAD_LOCAL_P (decl)) - tls_aggregates = tree_cons (init, decl, tls_aggregates); else - static_aggregates = tree_cons (init, decl, static_aggregates); + { + if (CP_DECL_THREAD_LOCAL_P (decl)) + tls_aggregates = tree_cons (init, decl, tls_aggregates); + else + static_aggregates = tree_cons (init, decl, static_aggregates); + + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl))) + { + warning_at (dloc, OPT_Wglobal_constructors, + "declaration requires a global destructor"); + return; + } + + if (DECL_NONTRIVIALLY_INITIALIZED_P (decl) && !decl_constant_var_p (decl)) + warning_at (dloc, OPT_Wglobal_constructors, + "declaration requires a global constructor"); + } } diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 4964cc41ba3..77d324584ec 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -312,6 +312,7 @@ Objective-C and Objective-C++ Dialects}. -Wformat-security -Wformat-signedness -Wformat-truncation=@var{n} @gol -Wformat-y2k -Wframe-address @gol -Wframe-larger-than=@var{byte-size} -Wno-free-nonheap-object @gol +-Wglobal-constructors @gol -Wjump-misses-init @gol -Whsa -Wif-not-aligned @gol -Wignored-qualifiers -Wignored-attributes -Wincompatible-pointer-types @gol @@ -6509,6 +6510,40 @@ to @option{-Wframe-larger-than=}@samp{SIZE_MAX} or larger. Do not warn when attempting to free an object that was not allocated on the heap. +@item -Wglobal-constructors @r{(C++ and Objective-C++ only)} +@opindex Wglobal-constructors +@opindex Wno-global-constructors +Warn whenever an object with static storage duration either requires dynamic +initialization or has a nontrivial destructor. The compiler will issue a +warning if a declaration's initializer is not a constant expression, as shown +in the following examples: + +@smallexample +@group +const char* const tmp = getenv ("TMP"); +// warning: declaration requires a global constructor + +static int initialize() { return 42; } +static int global = initialize (); +// warning: declaration requires a global constructor + +@end group +@end smallexample + +In cases where the compiler can treat the initializer as a constant expression, +no warning is raised, as in the following example: + +@smallexample +@group + +constexpr int initialize() { return 42; } +static int i = initialize (); +// no warning: initialize in this case is a constant expression + +@end group +@end smallexample + + @item -Wstack-usage=@var{byte-size} @opindex Wstack-usage @opindex Wno-stack-usage diff --git a/gcc/testsuite/g++.dg/warn/global-constructors-1.C b/gcc/testsuite/g++.dg/warn/global-constructors-1.C new file mode 100644 index 00000000000..eb08379b680 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/global-constructors-1.C @@ -0,0 +1,53 @@ +// { dg-do compile } +// { dg-options "-Wglobal-constructors" } + +struct with_ctor { + int x; + with_ctor() : x(42) {} +}; + +struct with_dtor { + ~with_dtor() {} +}; + +struct with_both { + int x; + with_both() : x(42) {} + ~with_both() {} +}; + +struct with_default_ctor { + int x; + with_default_ctor() = default; +}; + +struct with_constexpr_ctor { + int x; + constexpr with_constexpr_ctor() : x(42) {} + constexpr with_constexpr_ctor(int x) : x(x) {} +}; + +with_ctor global_var; /* { dg-warning "declaration requires a global constructor" } */ +with_dtor global_var2; /* { dg-warning "declaration requires a global destructor" } */ +with_both global_var3; /* { dg-warning "declaration requires a global destructor" } */ +with_default_ctor global_var4; /* { dg-bogus "declaration requires a global constructor" } */ +with_constexpr_ctor global_var5; /* { dg-bogus "declaration requires a global constructor" } */ + +int initialize() { + return 42; +} + +int global_var6 = initialize(); /* { dg-warning "declaration requires a global constructor" } */ +with_constexpr_ctor global_var7(initialize()); /* { dg-warning "declaration requires a global constructor" } */ + +constexpr int initialize_const() { + return 42; +} + +int global_var8 = initialize_const(); /* { dg-bogus "declaration requires a global constructor" } */ +constexpr int global_var9 = initialize_const(); /* { dg-bogus "declaration requires a global constructor" } */ + + +int main() { + static with_ctor global_var; /* { dg-bogus "declaration requires a global constructor" } */ +} diff --git a/gcc/testsuite/g++.dg/warn/global-constructors-2.C b/gcc/testsuite/g++.dg/warn/global-constructors-2.C new file mode 100644 index 00000000000..e96da348458 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/global-constructors-2.C @@ -0,0 +1,49 @@ +// { dg-do compile } +// { dg-require-effective-target c++11 } +// { dg-options "-Wglobal-constructors" } + +struct with_ctor { + int x; + with_ctor() : x(42) {} +}; + +struct with_dtor { + ~with_dtor() {} +}; + +struct with_both { + int x; + with_both() : x(42) {} + ~with_both() {} +}; + +struct with_default_ctor { + int x; + with_default_ctor() = default; +}; + +struct with_constexpr_ctor { + int x; + constexpr with_constexpr_ctor() : x(42) {} + constexpr with_constexpr_ctor(int x) : x(x) {} +}; + +thread_local with_ctor global_var; /* { dg-warning "declaration requires a global constructor" } */ +thread_local with_dtor global_var2; /* { dg-warning "declaration requires a global destructor" } */ +thread_local with_both global_var3; /* { dg-warning "declaration requires a global destructor" } */ +thread_local with_default_ctor global_var4; /* { dg-bogus "declaration requires a global constructor" } */ +thread_local with_constexpr_ctor global_var5; /* { dg-bogus "declaration requires a global constructor" } */ + +int initialize() { + return 42; +} + +thread_local int global_var6 = initialize(); /* { dg-warning "declaration requires a global constructor" } */ +thread_local with_constexpr_ctor global_var7(initialize()); /* { dg-warning "declaration requires a global constructor" } */ + +constexpr int initialize_const() { + return 42; +} + +thread_local int global_var8 = initialize_const(); /* { dg-bogus "declaration requires a global constructor" } */ +thread_local constexpr int global_var9 = initialize_const(); /* { dg-bogus "declaration requires a global constructor" } */