From patchwork Tue May 9 12:07:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Coplan X-Patchwork-Id: 1778908 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=O3aB95Np; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QFxkT18Pfz214S for ; Tue, 9 May 2023 22:08:01 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2775D385800A for ; Tue, 9 May 2023 12:07:59 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2775D385800A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1683634079; bh=HdbtMeFnSDNEH6z2X7WykmEHChembYg5BBIytre6I2w=; h=Date:To:Cc:Subject:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=O3aB95NppmsPHUv9Gmxz1At7+m6ndRunEtvxKbnwQQSIggy1utdOhFgNFssWH42VJ mHhqDqloNDxCO0q3fos62fmr6vfT8JLtoiiPijgE+NctcgQoJHNRLb3JoOGgIUEVVN lxhuaoDueR0QZ7U4+Lfe6vEvCMvS78j9y7FtB+wQ= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from EUR05-DB8-obe.outbound.protection.outlook.com (mail-db8eur05on2069.outbound.protection.outlook.com [40.107.20.69]) by sourceware.org (Postfix) with ESMTPS id 898B63858C53 for ; Tue, 9 May 2023 12:07:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 898B63858C53 Received: from AS9PR06CA0047.eurprd06.prod.outlook.com (2603:10a6:20b:463::9) by AS8PR08MB10141.eurprd08.prod.outlook.com (2603:10a6:20b:631::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6363.32; Tue, 9 May 2023 12:07:28 +0000 Received: from AM7EUR03FT004.eop-EUR03.prod.protection.outlook.com (2603:10a6:20b:463:cafe::d3) by AS9PR06CA0047.outlook.office365.com (2603:10a6:20b:463::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6363.33 via Frontend Transport; Tue, 9 May 2023 12:07:28 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 63.35.35.123) smtp.mailfrom=arm.com; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com;dmarc=pass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 63.35.35.123 as permitted sender) receiver=protection.outlook.com; client-ip=63.35.35.123; helo=64aa7808-outbound-1.mta.getcheckrecipient.com; pr=C Received: from 64aa7808-outbound-1.mta.getcheckrecipient.com (63.35.35.123) by AM7EUR03FT004.mail.protection.outlook.com (100.127.140.210) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6387.18 via Frontend Transport; Tue, 9 May 2023 12:07:28 +0000 Received: ("Tessian outbound 8b05220b4215:v136"); Tue, 09 May 2023 12:07:28 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: 3207e16e1dceee30 X-CR-MTA-TID: 64aa7808 Received: from fcb7b12c0dd9.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id FF788D17-B531-4C61-9682-9E0DA0F3B15F.1; Tue, 09 May 2023 12:07:20 +0000 Received: from EUR05-DB8-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id fcb7b12c0dd9.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Tue, 09 May 2023 12:07:20 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=EfBdH/Ms7owlv3NvwZ6E3SUQ3yxNBsPSAflCe4l+5R5a/GcY0ohiYq7Wm6MIjTF/xLm3xGqkljSdNeQ+/eY+4cS96T2hx/2SpntkdF4z+WdbTtuoW1aKfAHI9HdFYq2mv9AX/MmSemjo027F1//J2M6wQtLH56m0ykX0i5b/N4agLZgIHURg8XMyBBNzEZnpfTBkOliROkK0RImsyg3/qy4Gjh7QH0VBaj/hcxplDZ2YBM35bp9adJXiONQM3by8KCheZyaxeFvGf85UJuyWsRUHqPdqvgo/G0P9vWqBRTjvGhqIqWFfsTsqa7g4uc4BpBERRjhLTEZo3qvHPJzL8A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=HdbtMeFnSDNEH6z2X7WykmEHChembYg5BBIytre6I2w=; b=BmfQ58WbHmZgwzk4p2fy+Fw9zAE+Bzm9WT1JHNyweMx4klLM6IeIxoocEBfeF75GqX6Gh9Crq7V08fupbq0RFpCECSVRr3hVCc+moFt70BVEn25LKoPvT8qlMoC3Iro4g8meenma3TFsfCJH0jMShOERpF98Sh1bNQPD/bRX5+8l6hThNyoUbbp0lRrY3jgqKH9pUu+gEMpFjSETpd9inlPeHdWQ670/+stksWWYjp1VcNCehszw6RyOQLw4jLKjGyDXCVBuRJ0XDaKlH9hDgrWU53XqIxGDTTh/UKIzP7GXyf2aKavlrp7hJBTooQ1DVqblYU5c2o2mYKg5S9IGdQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none Authentication-Results-Original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; Received: from PAXPR08MB7201.eurprd08.prod.outlook.com (2603:10a6:102:20b::17) by DU0PR08MB9077.eurprd08.prod.outlook.com (2603:10a6:10:471::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6363.29; Tue, 9 May 2023 12:07:15 +0000 Received: from PAXPR08MB7201.eurprd08.prod.outlook.com ([fe80::5b72:ef2:156a:296a]) by PAXPR08MB7201.eurprd08.prod.outlook.com ([fe80::5b72:ef2:156a:296a%4]) with mapi id 15.20.6363.033; Tue, 9 May 2023 12:07:15 +0000 Date: Tue, 9 May 2023 13:07:11 +0100 To: gcc-patches@gcc.gnu.org Cc: Iain Sandoe , Joseph Myers , Jason Merrill , Nathan Sidwell Subject: [PATCH][RFC] c-family: Implement __has_feature and __has_extension [PR60512] Message-ID: Content-Disposition: inline X-ClientProxiedBy: LO2P265CA0444.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:e::24) To PAXPR08MB7201.eurprd08.prod.outlook.com (2603:10a6:102:20b::17) MIME-Version: 1.0 X-MS-TrafficTypeDiagnostic: PAXPR08MB7201:EE_|DU0PR08MB9077:EE_|AM7EUR03FT004:EE_|AS8PR08MB10141:EE_ X-MS-Office365-Filtering-Correlation-Id: 6bb7aa1e-fc5d-4099-706e-08db5085f59d x-checkrecipientrouted: true NoDisclaimer: true X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Untrusted: BCL:0; X-Microsoft-Antispam-Message-Info-Original: vGEjTvf5ZaitF7HH4u71PPr4OV6BWeIwMrNsRmVKOl7ImldCkljM7H+PPj5Uo+lydPzxNYzUfdswl7dnmKbzPqqYi7Lc+lxomsh16BZvtsV3tO/Oej1RQ/SpDObWfDPqDW+tuwxF75JSA7YxObGXrrfxxWZwl5Ib/uGmEDkGKxlTbCFwJWwYKsYf9vqsS5tziOouUVhsvaXWpzE1TXOG8AmPJJh+96wVWNtPO+vsQS1gnWkmGh53jtJioFAIYbu7+eSfMoqqkViufeZzEziyepqngUZXIoap54b5HIjQyFJLaXMvMY3RLZUf+FB+uAFFsMYtyNnWOriz7vb6/QCssR1bC41UU1J7PVPDTEVNnRaan5QmiVp+sVY84TWxyWcRQTc0V+Q8qPALb7KyX2ZTJFAHrCHbB6pV7Uj2VG1GbbyNeMWi9r6Z8Ukbqw6IPx/DBAaYAQXaxmoeYieAUgPah78nttLMWc9tSRsL4HCmixvYpNR9gn4COF/OoVzRQjUG4gEjxWjf8zX2Z2nVqRV2qHbzD1bXf0FJos8KNmB/ZHXOREFiLyd+PszbYsszR4r86ycGgYcysdz31ovxUFyH7wpH+heQKK1TKEMZzEgeAb70UzJBxfTJQZGIcEQBuWpnrlfyK3pS3JFnrWyYfw3s0Xv7gNrBITFuLLKRvhyuoRU= X-Forefront-Antispam-Report-Untrusted: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PAXPR08MB7201.eurprd08.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230028)(4636009)(376002)(39860400002)(366004)(396003)(346002)(136003)(451199021)(966005)(6666004)(33964004)(21480400003)(6486002)(36756003)(186003)(2616005)(38100700002)(6506007)(86362001)(26005)(6512007)(44144004)(4326008)(84970400001)(2906002)(6916009)(66946007)(66556008)(66476007)(54906003)(235185007)(8676002)(41300700001)(44832011)(5660300002)(8936002)(316002)(478600001)(21314003)(2700100001); DIR:OUT; SFP:1101; X-MS-Exchange-Transport-CrossTenantHeadersStamped: DU0PR08MB9077 Original-Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; X-EOPAttributedMessage: 0 X-MS-Exchange-Transport-CrossTenantHeadersStripped: AM7EUR03FT004.eop-EUR03.prod.protection.outlook.com X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id-Prvs: 81bb8505-38d4-409d-2909-08db5085ed8e X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 95XMTjlMrHAH8JlORNwFjQa86GztTaJHHE21zBguTn5UqTMBXjWs3mHcyGLHMgZFGBEXkKgkva0fv7THW5l5A+u3s7Lcs3nTFZnOJb+etziZYFyR6HVOLioli7aHQBaGzIIGB0kUzmlifOGXOwag+MknXQknUI1uLgzA+SP4f/Bdoge4iF4wMplWYMNZ7TTQLrdZLbs+pl/n5nsAszO8MYIu8XKePERRCtJLICB6WxDq262UYuQJJZgOON/Wgxhc4Oq3eRjxXy4Uog4Ee3SiwUtZEgrOGJ+2l/OEqj5hR2vyZfcj37KzAPOkcVuojoyLRhcwNJXewsg6YY4JYViWkhJXHQWmvDeBRyPN6BDmZAB4R59Pdlbtyr2087Sjya6TO0r0QJ5EQ7SCys8/8hPuK3Am6D6ORvIZRI1WuuwmI52XPweFaHYww7N3m0u2AhZkuAaPil4wGN6s9OFmr553KJBXPm+mrHmzhA42TEYtPrlg08BF3F5l/cSFimkmqt+6ZgZfbkesD7rxNlIWkU+RLkHeqTespaY2uWN0EWKCT4KDwSHnj/Axxpo956oM07PKrH6FBBt4ENcBHhCdyZ9u0pCa+bXysktatlZ6/zOp6ROAHnkqhjHi6DMQsfzJ7kx+m7JMTrmW/QWQTglqO0FfG1QxhGMov+AaGoaoLaAso2oXJok/cc3OlV47hpOKf5JkUEfovRVNEzU8LpcGcI9QTnsiLALqWamGSBvrtkRdEFpfkAKw28rc4wFFaFZzXmo72B6bZrYICpGuXjZl5k7BK8njBjIQVe2cTihUdtG2sjA= X-Forefront-Antispam-Report: CIP:63.35.35.123; CTRY:IE; LANG:en; SCL:1; SRV:; IPV:CAL; SFV:NSPM; H:64aa7808-outbound-1.mta.getcheckrecipient.com; PTR:ec2-63-35-35-123.eu-west-1.compute.amazonaws.com; CAT:NONE; SFS:(13230028)(4636009)(376002)(396003)(39860400002)(346002)(136003)(451199021)(46966006)(36840700001)(40470700004)(84970400001)(36860700001)(36756003)(40460700003)(44832011)(2906002)(8936002)(8676002)(40480700001)(86362001)(70586007)(70206006)(6916009)(235185007)(81166007)(82310400005)(316002)(41300700001)(5660300002)(82740400003)(966005)(336012)(47076005)(186003)(26005)(6512007)(6506007)(54906003)(6486002)(21480400003)(6666004)(44144004)(478600001)(33964004)(2616005)(4326008)(356005)(21314003)(2700100001); DIR:OUT; SFP:1101; X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 May 2023 12:07:28.3884 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 6bb7aa1e-fc5d-4099-706e-08db5085f59d X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=f34e5979-57d9-4aaa-ad4d-b122a662184d; Ip=[63.35.35.123]; Helo=[64aa7808-outbound-1.mta.getcheckrecipient.com] X-MS-Exchange-CrossTenant-AuthSource: AM7EUR03FT004.eop-EUR03.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: AS8PR08MB10141 X-Spam-Status: No, score=-12.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_NONE, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE, UNPARSEABLE_RELAY 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: Alex Coplan via Gcc-patches From: Alex Coplan Reply-To: Alex Coplan Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Hi, This patch implements clang's __has_feature and __has_extension in GCC. Currently the patch aims to implement all documented features (and some undocumented ones) following the documentation at https://clang.llvm.org/docs/LanguageExtensions.html with the following omissions: - C++ type traits. - Objective-C-specific features. C++ type traits aren't currently implemented since, as the clang documentation notes, __has_builtin is the correct "modern" way to query for these (which GCC already implements). Of course there's an argument that we should recognize the legacy set of C++ type traits that can be queried through __has_feature for backwards compatibility with older code. I'm happy to do this if reviewers think that's a good idea. There are some comments in the patch marked with XXX, I'm looking for review comments from C/C++ maintainers on those areas in particular. Bootstrapped/regtested on aarch64-linux-gnu. Any comments? Thanks, Alex gcc/c-family/ChangeLog: PR c++/60512 * c-common.cc (struct hf_feature_info): New. (has_generic_feature_p): New. * c-common.h (c_common_has_feature): New. (has_generic_feature_p): New. (has_lang_feature_p): New. * c-lex.cc (init_c_lex): Plumb through has_feature callback. (c_common_has_builtin): Adapt into more generic helper function. Rename to ... (c_common_lex_availability_macro): ... this. (c_common_has_feature): New. * c-ppoutput.cc (init_pp_output): Plumb through has_feature callback. gcc/c/ChangeLog: PR c++/60512 * c-objc-common.cc (struct c_feature_info): New. (has_lang_feature_p): New. gcc/cp/ChangeLog: PR c++/60512 * cp-objcp-common.cc (struct cp_feature_selector): New. (cp_feature_selector::has_feature): New. (struct cp_feature_info): New. (has_lang_feature_p): New. gcc/ChangeLog: PR c++/60512 * doc/cpp.texi: Document __has_{feature,extension}. libcpp/ChangeLog: PR c++/60512 * include/cpplib.h (struct cpp_callbacks): Add has_feature callback. (enum cpp_builtin_type): Add types for __has_{feature,extension}. * init.cc (builtin_array): Add entries for __has_{feature,extension}. * macro.cc (_cpp_builtin_macro_text): Handle BT_HAS_{FEATURE,EXTENSION}. gcc/testsuite/ChangeLog: PR c++/60512 * c-c++-common/has-feature-common.c: New test. * g++.dg/ext/has-feature.C: New test. * gcc.dg/asan/has-feature-asan.c: New test. * gcc.dg/has-feature.c: New test. diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 2b4c82facf7..5b8429244b2 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -311,6 +311,34 @@ const struct fname_var_t fname_vars[] = {NULL, 0, 0}, }; +enum +{ + HF_FLAG_EXT = 1, /* Available only as an extension. */ + HF_FLAG_SANITIZE = 2, /* Availability depends on sanitizer flags. */ +}; + +struct hf_feature_info +{ + const char *ident; + unsigned flags; + unsigned mask; +}; + +static const hf_feature_info has_feature_table[] = +{ + { "address_sanitizer", HF_FLAG_SANITIZE, SANITIZE_ADDRESS }, + { "thread_sanitizer", HF_FLAG_SANITIZE, SANITIZE_THREAD }, + { "leak_sanitizer", HF_FLAG_SANITIZE, SANITIZE_LEAK }, + { "hwaddress_sanitizer", HF_FLAG_SANITIZE, SANITIZE_HWADDRESS }, + { "undefined_behavior_sanitizer", HF_FLAG_SANITIZE, SANITIZE_UNDEFINED }, + { "attribute_deprecated_with_message", 0, 0 }, + { "attribute_unavailable_with_message", 0, 0 }, + { "enumerator_attributes", 0, 0 }, + { "tls", 0, 0 }, + { "gnu_asm_goto_with_outputs", HF_FLAG_EXT, 0 }, + { "gnu_asm_goto_with_outputs_full", HF_FLAG_EXT, 0 } +}; + /* Global visibility options. */ struct visibility_flags visibility_options; @@ -9545,4 +9573,25 @@ c_strict_flex_array_level_of (tree array_field) return strict_flex_array_level; } +bool +has_generic_feature_p (const char *feat, bool strict_p) +{ + for (unsigned i = 0; i < ARRAY_SIZE (has_feature_table); i++) + { + const hf_feature_info *info = has_feature_table + i; + if (strcmp (info->ident, feat)) + continue; + + if ((info->flags & HF_FLAG_EXT) && strict_p) + return false; + + if (info->flags & HF_FLAG_SANITIZE) + return flag_sanitize & info->mask; + + return true; + } + + return has_lang_feature_p (feat, strict_p); +} + #include "gt-c-family-c-common.h" diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index f96350b64af..38fd30312a0 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1121,6 +1121,9 @@ extern bool c_cpp_diagnostic (cpp_reader *, enum cpp_diagnostic_level, ATTRIBUTE_GCC_DIAG(5,0); extern int c_common_has_attribute (cpp_reader *, bool); extern int c_common_has_builtin (cpp_reader *); +extern int c_common_has_feature (cpp_reader *, bool); +extern bool has_generic_feature_p (const char *, bool); +extern bool has_lang_feature_p (const char *, bool); extern bool parse_optimize_options (tree, bool); diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc index 6eb0fae2f53..3301d90d6ab 100644 --- a/gcc/c-family/c-lex.cc +++ b/gcc/c-family/c-lex.cc @@ -82,6 +82,7 @@ init_c_lex (void) cb->read_pch = c_common_read_pch; cb->has_attribute = c_common_has_attribute; cb->has_builtin = c_common_has_builtin; + cb->has_feature = c_common_has_feature; cb->get_source_date_epoch = cb_get_source_date_epoch; cb->get_suggestion = cb_get_suggestion; cb->remap_filename = remap_macro_filename; @@ -429,16 +430,16 @@ c_common_has_attribute (cpp_reader *pfile, bool std_syntax) return result; } -/* Callback for has_builtin. */ +/* Helper for __has_{builtin,feature,extension}. */ -int -c_common_has_builtin (cpp_reader *pfile) +static const char * +c_common_lex_availability_macro (cpp_reader *pfile, const char *builtin) { const cpp_token *token = get_token_no_padding (pfile); if (token->type != CPP_OPEN_PAREN) { cpp_error (pfile, CPP_DL_ERROR, - "missing '(' after \"__has_builtin\""); + "missing '(' after \"__has_%s\"", builtin); return 0; } @@ -458,7 +459,7 @@ c_common_has_builtin (cpp_reader *pfile) else { cpp_error (pfile, CPP_DL_ERROR, - "macro \"__has_builtin\" requires an identifier"); + "macro \"__has_%s\" requires an identifier", builtin); if (token->type == CPP_CLOSE_PAREN) return 0; } @@ -477,9 +478,35 @@ c_common_has_builtin (cpp_reader *pfile) break; } + return name; +} + +/* Callback for has_builtin. */ + +int +c_common_has_builtin (cpp_reader *pfile) +{ + const char *name = c_common_lex_availability_macro (pfile, "builtin"); + if (!name) + return 0; + return names_builtin_p (name); } +/* Callback for has_feature. STRICT_P is true for has_feature and false + for has_extension. */ + +int +c_common_has_feature (cpp_reader *pfile, bool strict_p) +{ + const char *builtin = strict_p ? "feature" : "extension"; + const char *name = c_common_lex_availability_macro (pfile, builtin); + if (!name) + return 0; + + return has_generic_feature_p (name, strict_p); +} + /* Read a token and return its type. Fill *VALUE with its value, if applicable. Fill *CPP_FLAGS with the token's flags, if it is diff --git a/gcc/c-family/c-ppoutput.cc b/gcc/c-family/c-ppoutput.cc index 4aa2bef2c0f..a1488c6f086 100644 --- a/gcc/c-family/c-ppoutput.cc +++ b/gcc/c-family/c-ppoutput.cc @@ -162,6 +162,7 @@ init_pp_output (FILE *out_stream) cb->has_attribute = c_common_has_attribute; cb->has_builtin = c_common_has_builtin; + cb->has_feature = c_common_has_feature; cb->get_source_date_epoch = cb_get_source_date_epoch; cb->remap_filename = remap_macro_filename; diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc index e4aed61ed00..30e6c491421 100644 --- a/gcc/c/c-objc-common.cc +++ b/gcc/c/c-objc-common.cc @@ -34,6 +34,48 @@ along with GCC; see the file COPYING3. If not see static bool c_tree_printer (pretty_printer *, text_info *, const char *, int, bool, bool, bool, bool *, const char **); +struct c_feature_info +{ + const char *ident; + const int *enable_flag; +}; + +static const c_feature_info c_feature_table[] = +{ + { "c_alignas", &flag_isoc11 }, + { "c_alignof", &flag_isoc11 }, + { "c_atomic", &flag_isoc11 }, + { "c_generic_selections", &flag_isoc11 }, + { "c_static_assert", &flag_isoc11 }, + { "c_thread_local", &flag_isoc11 }, + + /* XXX: Binary literals are available as a standard feature in + C2x. They are standardised in C++14 and available as an extension + in all C versions. Would it make more sense to have + cxx_binary_literals always report as an extension (in C) and add a + new c_binary_literals that reports as a feature for -std=c2x and an + extension below that? */ + { "cxx_binary_literals", &flag_isoc2x } +}; + +bool +has_lang_feature_p (const char *feat, bool strict_p) +{ + for (unsigned i = 0; i < ARRAY_SIZE (c_feature_table); i++) + { + const c_feature_info *info = c_feature_table + i; + if (strcmp (info->ident, feat)) + continue; + + if (info->enable_flag && strict_p && !*info->enable_flag) + return false; + + return true; + } + + return false; +} + bool c_missing_noreturn_ok_p (tree decl) { diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc index 93b027b80ce..494f72b5ca1 100644 --- a/gcc/cp/cp-objcp-common.cc +++ b/gcc/cp/cp-objcp-common.cc @@ -23,10 +23,127 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "cp-tree.h" #include "cp-objcp-common.h" +#include "c-family/c-common.h" #include "dwarf2.h" #include "stringpool.h" #include "contracts.h" +struct cp_feature_selector +{ + enum + { + DIALECT, + FLAG + } kind; + + union + { + const int *enable_flag; + struct { + enum cxx_dialect feat; + enum cxx_dialect ext; + } dialect; + }; + + constexpr cp_feature_selector (const int *flag) + : kind (FLAG), enable_flag (flag) {} + constexpr cp_feature_selector (enum cxx_dialect feat, + enum cxx_dialect ext) + : kind (DIALECT), dialect{feat, ext} {} + constexpr cp_feature_selector (enum cxx_dialect feat) + : cp_feature_selector (feat, feat) {} + + bool has_feature (bool strict_p) const; +}; + +bool cp_feature_selector::has_feature (bool strict_p) const +{ + switch (kind) + { + case DIALECT: + if (!strict_p) + return cxx_dialect >= dialect.ext; + return cxx_dialect >= dialect.feat; + case FLAG: + return *enable_flag; + } + gcc_unreachable (); +} + +struct cp_feature_info +{ + const char *ident; + cp_feature_selector selector; +}; + +static const cp_feature_info cp_feature_table[] = +{ + { "cxx_exceptions", &flag_exceptions }, + { "cxx_rtti", &flag_rtti }, + { "cxx_access_control_sfinae", { cxx11, cxx98 } }, + { "cxx_alias_templates", cxx11 }, + { "cxx_alignas", cxx11 }, + { "cxx_alignof", cxx11 }, + { "cxx_attributes", cxx11 }, + { "cxx_constexpr", cxx11 }, + { "cxx_constexpr_string_builtins", cxx11 }, + { "cxx_decltype", cxx11 }, + { "cxx_decltype_incomplete_return_types", cxx11 }, + { "cxx_default_function_template_args", cxx11 }, + { "cxx_defaulted_functions", cxx11 }, /* XXX: extension in c++98? */ + { "cxx_delegating_constructors", { cxx11, cxx98 } }, + { "cxx_deleted_functions", cxx11 }, + { "cxx_explicit_conversions", { cxx11, cxx98 } }, + { "cxx_generalized_initializers", cxx11 }, + { "cxx_implicit_moves", cxx11 }, + { "cxx_inheriting_constructors", cxx11 }, /* XXX: extension in c++98? */ + { "cxx_inline_namespaces", { cxx11, cxx98 } }, + { "cxx_lambdas", cxx11 }, /* XXX: extension in c++98? */ + { "cxx_local_type_template_args", cxx11 }, + { "cxx_noexcept", cxx11 }, + { "cxx_nonstatic_member_init", { cxx11, cxx98 } }, + { "cxx_nullptr", cxx11 }, + { "cxx_override_control", { cxx11, cxx98 } }, + { "cxx_reference_qualified_functions", cxx11 }, + { "cxx_range_for", cxx11 }, + { "cxx_raw_string_literals", cxx11 }, + { "cxx_rvalue_references", cxx11 }, + { "cxx_static_assert", cxx11 }, + { "cxx_thread_local", cxx11 }, + { "cxx_auto_type", cxx11 }, + { "cxx_strong_enums", cxx11 }, + { "cxx_trailing_return", cxx11 }, + { "cxx_unicode_literals", cxx11 }, + { "cxx_unrestricted_unions", cxx11 }, + { "cxx_user_literals", cxx11 }, + { "cxx_variadic_templates", { cxx11, cxx98 } }, + { "cxx_binary_literals", { cxx14, cxx98 } }, + { "cxx_contextual_conversions", { cxx14, cxx98 } }, + { "cxx_decltype_auto", cxx14 }, + { "cxx_aggregate_nsdmi", cxx14 }, + { "cxx_init_captures", { cxx14, cxx11 } }, + { "cxx_generic_lambdas", cxx14 }, + { "cxx_relaxed_constexpr", cxx14 }, + { "cxx_return_type_deduction", cxx14 }, + { "cxx_variable_templates", { cxx14, cxx98 } }, + { "modules", &flag_modules }, +}; + +bool +has_lang_feature_p (const char *feat, bool strict_p) +{ + for (unsigned i = 0; i < ARRAY_SIZE (cp_feature_table); i++) + { + const cp_feature_info *info = cp_feature_table + i; + if (strcmp (info->ident, feat)) + continue; + + return info->selector.has_feature (strict_p); + } + + return false; +} + /* Special routine to get the alias set for C++. */ alias_set_type diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi index b0a2ce3ac6b..9ed96786249 100644 --- a/gcc/doc/cpp.texi +++ b/gcc/doc/cpp.texi @@ -3198,6 +3198,8 @@ directive}: @samp{#if}, @samp{#ifdef} or @samp{#ifndef}. * @code{__has_cpp_attribute}:: * @code{__has_c_attribute}:: * @code{__has_builtin}:: +* @code{__has_feature}:: +* @code{__has_extension}:: * @code{__has_include}:: @end menu @@ -3560,6 +3562,30 @@ the operator is as follows: #endif @end smallexample +@node @code{__has_feature} +@subsection @code{__has_feature} +@cindex @code{__has_feature} + +The special operator @code{__has_feature (@var{operand})} may be used in +constant integer contexts and in preprocessor @samp{#if} and @samp{#elif} +expressions to test whether the identifier given in @var{operand} is recognized +as a feature supported by GCC given the current options and, in the case of +standard language features, whether the feature is available in the chosen +version of the language standard. + +@node @code{__has_extension} +@subsection @code{__has_extension} +@cindex @code{__has_extension} + +The special operator @code{__has_extension (@var{operand})} may be used in +constant integer contexts and in preprocessor @samp{#if} and @samp{#elif} +expressions to test whether the identifier given in @var{operand} is recognized +as an extension supported by GCC given the current options. In any given +context, the features accepted by @code{__has_extension} are a strict superset +of those accepted by @code{__has_feature}. Unlike @code{__has_feature}, +@code{__has_extension} tests whether a given feature is available regardless of +strict language standards conformance. + @node @code{__has_include} @subsection @code{__has_include} @cindex @code{__has_include} diff --git a/gcc/testsuite/c-c++-common/has-feature-common.c b/gcc/testsuite/c-c++-common/has-feature-common.c new file mode 100644 index 00000000000..9a57b11e8e2 --- /dev/null +++ b/gcc/testsuite/c-c++-common/has-feature-common.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* Test __has_{feature,extension} for generic features. */ + +#define FEAT(x) (__has_feature (x) && __has_extension (x)) +#define EXT(x) (__has_extension (x) && !__has_feature (x)) + +#if __has_feature (unknown_feature) || __has_extension (unknown_feature) +#error unknown feature is known! +#endif + +#if !__has_extension (gnu_asm_goto_with_outputs) +#error +#endif + +#if !EXT (gnu_asm_goto_with_outputs) +#error +#endif + +#if !EXT (gnu_asm_goto_with_outputs_full) +#error +#endif + +#if !FEAT (enumerator_attributes) +#error +#endif + +#if !FEAT (attribute_deprecated_with_message) +#error +#endif + +#if !FEAT (attribute_unavailable_with_message) +#error +#endif + +#if !FEAT (enumerator_attributes) +#error +#endif + +#if !FEAT (tls) +#error +#endif + +#if defined (__SANITIZE_ADDRESS__) != __has_feature (address_sanitizer) +#error +#endif + +#if defined (__SANITIZE_ADDRESS__) != __has_extension (address_sanitizer) +#error +#endif + +#if defined (__SANITIZE_THREAD__) != __has_feature (thread_sanitizer) +#error +#endif + +#if defined (__SANITIZE_THREAD__) != __has_extension (thread_sanitizer) +#error +#endif diff --git a/gcc/testsuite/g++.dg/ext/has-feature.C b/gcc/testsuite/g++.dg/ext/has-feature.C new file mode 100644 index 00000000000..58d0057c30d --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/has-feature.C @@ -0,0 +1,225 @@ +// { dg-do compile } + +#define FEAT(x) (__has_feature(x) && __has_extension(x)) +#define CXX11 (__cplusplus >= 201103L) +#define CXX14 (__cplusplus >= 201402L) + +#if !FEAT(cxx_exceptions) || !FEAT(cxx_rtti) +#error +#endif + +#if __has_feature (cxx_access_control_sfinae) != CXX11 +#error +#endif + +#if !__has_extension (cxx_access_control_sfinae) +#error +#endif + +#if FEAT(cxx_alias_templates) != CXX11 +#error +#endif + +#if FEAT(cxx_alignas) != CXX11 +#error +#endif + +#if FEAT(cxx_alignof) != CXX11 +#error +#endif + +#if FEAT(cxx_attributes) != CXX11 +#error +#endif + +#if FEAT(cxx_constexpr) != CXX11 +#error +#endif + +#if FEAT(cxx_decltype) != CXX11 +#error +#endif + +#if FEAT(cxx_decltype_incomplete_return_types) != CXX11 +#error +#endif + +#if FEAT(cxx_default_function_template_args) != CXX11 +#error +#endif + +#if FEAT(cxx_defaulted_functions) != CXX11 +#error +#endif + +#if !__has_extension (cxx_delegating_constructors) +#error +#endif + +#if __has_feature (cxx_delegating_constructors) != CXX11 +#error +#endif + +#if FEAT (cxx_deleted_functions) != CXX11 +#error +#endif + +#if !__has_extension (cxx_explicit_conversions) +#error +#endif + +#if __has_feature (cxx_explicit_conversions) != CXX11 +#error +#endif + +#if FEAT (cxx_generalized_initializers) != CXX11 +#error +#endif + +#if FEAT (cxx_implicit_moves) != CXX11 +#error +#endif + +#if FEAT (cxx_inheriting_constructors) != CXX11 +#error +#endif + +#if !__has_extension (cxx_inline_namespaces) +#error +#endif + +#if __has_feature (cxx_inline_namespaces) != CXX11 +#error +#endif + +#if FEAT (cxx_lambdas) != CXX11 +#error +#endif + +#if FEAT (cxx_local_type_template_args) != CXX11 +#error +#endif + +#if FEAT (cxx_noexcept) != CXX11 +#error +#endif + +#if !__has_extension (cxx_nonstatic_member_init) +#error +#endif + +#if __has_feature (cxx_nonstatic_member_init) != CXX11 +#error +#endif + +#if FEAT (cxx_nullptr) != CXX11 +#error +#endif + +#if !__has_extension (cxx_override_control) +#error +#endif + +#if __has_feature (cxx_override_control) != CXX11 +#error +#endif + +#if FEAT (cxx_reference_qualified_functions) != CXX11 +#error +#endif + +#if FEAT (cxx_range_for) != CXX11 +#error +#endif + +#if FEAT (cxx_raw_string_literals) != CXX11 +#error +#endif + +#if FEAT (cxx_rvalue_references) != CXX11 +#error +#endif + +#if FEAT (cxx_static_assert) != CXX11 +#error +#endif + +#if FEAT (cxx_thread_local) != CXX11 +#error +#endif + +#if FEAT (cxx_auto_type) != CXX11 +#error +#endif + +#if FEAT (cxx_strong_enums) != CXX11 +#error +#endif + +#if FEAT (cxx_trailing_return) != CXX11 +#error +#endif + +#if FEAT (cxx_unicode_literals) != CXX11 +#error +#endif + +#if FEAT (cxx_unrestricted_unions) != CXX11 +#error +#endif + +#if FEAT (cxx_user_literals) != CXX11 +#error +#endif + +#if !__has_extension (cxx_variadic_templates) +#error +#endif + +#if __has_feature (cxx_variadic_templates) != CXX11 +#error +#endif + +#if !__has_extension (cxx_binary_literals) +#error +#endif + +#if __has_feature (cxx_binary_literals) != CXX14 +#error +#endif + +#if FEAT (cxx_decltype_auto) != CXX14 +#error +#endif + +#if FEAT (cxx_aggregate_nsdmi) != CXX14 +#error +#endif + +#if __has_extension (cxx_init_captures) != CXX11 +#error +#endif + +#if __has_feature (cxx_init_captures) != CXX14 +#error +#endif + +#if FEAT (cxx_generic_lambdas) != CXX14 +#error +#endif + +#if FEAT (cxx_relaxed_constexpr) != CXX14 +#error +#endif + +#if FEAT (cxx_return_type_deduction) != CXX14 +#error +#endif + +#if !__has_extension (cxx_variable_templates) +#error +#endif + +#if __has_feature (cxx_variable_templates) != CXX14 +#error +#endif diff --git a/gcc/testsuite/gcc.dg/asan/has-feature-asan.c b/gcc/testsuite/gcc.dg/asan/has-feature-asan.c new file mode 100644 index 00000000000..810b69b8fc8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/has-feature-asan.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize=address" } */ +#define FEAT(x) (__has_feature (x) && __has_extension (x)) +#if !FEAT (address_sanitizer) +#error +#endif diff --git a/gcc/testsuite/gcc.dg/has-feature.c b/gcc/testsuite/gcc.dg/has-feature.c new file mode 100644 index 00000000000..19d27699a92 --- /dev/null +++ b/gcc/testsuite/gcc.dg/has-feature.c @@ -0,0 +1,63 @@ +/* { dg-do compile } */ +/* Test __has_{feature,extension} for C language features. */ + +#if !__has_extension (c_alignas) || !__has_extension (c_alignof) +#error +#endif + +#if !__has_extension (c_atomic) || !__has_extension (c_generic_selections) +#error +#endif + +#if !__has_extension (c_static_assert) || !__has_extension (c_thread_local) +#error +#endif + +#if !__has_extension (cxx_binary_literals) +#error +#endif + +#if __STDC_VERSION__ >= 201112L +/* Have C11 features. */ +#if !__has_feature (c_alignas) || !__has_feature (c_alignof) +#error +#endif + +#if !__has_feature (c_atomic) || !__has_feature (c_generic_selections) +#error +#endif + +#if !__has_feature (c_static_assert) || !__has_feature (c_thread_local) +#error +#endif + +#else +/* Don't have C11 features. */ +#if __has_feature (c_alignas) || __has_feature (c_alignof) +#error +#endif + +#if __has_feature (c_atomic) || __has_feature (c_generic_selections) +#error +#endif + +#if __has_feature (c_static_assert) || __has_feature (c_thread_local) +#error +#endif + +#endif + +#if __STDC_VERSION__ >= 202000L +/* Have C2x features. */ +#if !__has_feature (cxx_binary_literals) +#error +#endif + +#else +/* Don't have C2x features. */ +#if __has_feature (cxx_binary_literals) +#error +#endif +#endif + +enum { just_here_to_make_this_tu_nonempty }; diff --git a/gcc/testsuite/gcc.dg/ubsan/has-feature-ubsan.c b/gcc/testsuite/gcc.dg/ubsan/has-feature-ubsan.c new file mode 100644 index 00000000000..e5da1cc5628 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ubsan/has-feature-ubsan.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize=undefined" } */ +#define FEAT(x) (__has_feature (x) && __has_extension (x)) +#if !FEAT (undefined_behavior_sanitizer) +#error +#endif diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index a6f0abd894c..8f39a6a3a66 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -755,6 +755,9 @@ struct cpp_callbacks /* Callback to determine whether a built-in function is recognized. */ int (*has_builtin) (cpp_reader *); + /* Callback to determine whether a feature is available. */ + int (*has_feature) (cpp_reader *, bool); + /* Callback that can change a user lazy into normal macro. */ void (*user_lazy_macro) (cpp_reader *, cpp_macro *, unsigned); @@ -959,7 +962,9 @@ enum cpp_builtin_type BT_HAS_STD_ATTRIBUTE, /* `__has_c_attribute(x)' */ BT_HAS_BUILTIN, /* `__has_builtin(x)' */ BT_HAS_INCLUDE, /* `__has_include(x)' */ - BT_HAS_INCLUDE_NEXT /* `__has_include_next(x)' */ + BT_HAS_INCLUDE_NEXT, /* `__has_include_next(x)' */ + BT_HAS_FEATURE, /* `__has_feature(x)' */ + BT_HAS_EXTENSION /* `__has_extension(x)' */ }; #define CPP_HASHNODE(HNODE) ((cpp_hashnode *) (HNODE)) diff --git a/libcpp/init.cc b/libcpp/init.cc index c508f06112a..465dafefe9d 100644 --- a/libcpp/init.cc +++ b/libcpp/init.cc @@ -433,6 +433,8 @@ static const struct builtin_macro builtin_array[] = B("__has_builtin", BT_HAS_BUILTIN, true), B("__has_include", BT_HAS_INCLUDE, true), B("__has_include_next",BT_HAS_INCLUDE_NEXT, true), + B("__has_feature", BT_HAS_FEATURE, true), + B("__has_extension", BT_HAS_EXTENSION, true), /* Keep builtins not used for -traditional-cpp at the end, and update init_builtins() if any more are added. */ B("_Pragma", BT_PRAGMA, true), diff --git a/libcpp/macro.cc b/libcpp/macro.cc index d4238d4f621..d2e8f9bd411 100644 --- a/libcpp/macro.cc +++ b/libcpp/macro.cc @@ -677,6 +677,12 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node, number = builtin_has_include (pfile, node, node->value.builtin == BT_HAS_INCLUDE_NEXT); break; + + case BT_HAS_FEATURE: + case BT_HAS_EXTENSION: + number = pfile->cb.has_feature (pfile, + node->value.builtin == BT_HAS_FEATURE); + break; } if (result == NULL)