From patchwork Wed Jun 28 03:29:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 113681 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8633718vqr; Tue, 27 Jun 2023 20:30:50 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7LANBr7YegdZYhM8p46JGdBEKYt1Ln/+I+cyUN1of0kxc1G3SUCXQ9odVhV94Oqmt4y9LV X-Received: by 2002:aa7:cd55:0:b0:51d:9352:132f with SMTP id v21-20020aa7cd55000000b0051d9352132fmr6571856edw.18.1687923050521; Tue, 27 Jun 2023 20:30:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687923050; cv=none; d=google.com; s=arc-20160816; b=CwNSFUc2FfXc1+vg1bPgtXGyQu0DDsRkenpXcMN/0s4i6pPQ5rmb7uQxV+M4Nd0W9f yObpV1Z2fUGi6LOF48+P8ce013ihgau1fySU3KywToCrec8iX6aLNnpiqPvpJM02sQsh rs186rRwX5pZ1lfFxmGqa3qJuas0fmggjvlWteQVf1wBCuRRf6EDc8+dn24X2/COogjf j4qY/9MOMNgNLJs+RvGEcOHwjty/D58FEg75lrVj85sW93/goitm9slH0MCkl8tLA2L0 rahoO+FSKIs5Xmm7DhhFrzG7IlWewluJza3f6pEN/kQCeV/S3JU3heS7rVbW1X8tCDrL 8xOg== 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 :content-transfer-encoding:mime-version:message-id:date:subject:to :dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=hBme8+iZThKKd4FFIl0P9tyPMdrufTPO7comB37XtIc=; fh=hPrbWPhweUx4V0GV9uXJqbyAzg2ABmTz7kczrAQqMmM=; b=lC0hJUwawb3a45I1f27X4oe9rtnbOlOL8rCjVeGtMvDqlD5El07irDNKNZiKpFruW+ FJYQUqTbvxjVDgaoqVRJr07bjuC3gZAgmZUlq4DBqvEWY4B13o9U1I4DMcbgFGuE4X7V bPfRC56QH7DN7lB6M++2CpwROLFVfFoTtxVVoLh7ubqXeik1PzU4kzZuAgzXGUAgUeAe xYGQMmJEcpsdBHRmcHJNexFrfz1HfPc3j0H1xMfT3cHivwiXpljPwp7x87q9NLky+jsR ONTxScaOkoczCu40GUwlA7zgLI56wd7koE+/IM035eTtbEB4/zhe2NJuPGkIBUGDr8C4 1KpA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b="P/X+N8L/"; 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 sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id y7-20020aa7ccc7000000b0051dd020c51asi228457edt.366.2023.06.27.20.30.50 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Jun 2023 20:30:50 -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="P/X+N8L/"; 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 8EA94385841E for ; Wed, 28 Jun 2023 03:30:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8EA94385841E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1687923042; bh=hBme8+iZThKKd4FFIl0P9tyPMdrufTPO7comB37XtIc=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=P/X+N8L/bdEqnh2FJ2UQEnpB5Z88i2vfsMvgtiErRqVFhsa6UickHKeBxc7txmUCo aivx9MmMx+nt7HpuFs7rUPDP6tMNyWv01TFBkrnW7QmhCMiKjR79Wgvry+ioxMPewy oooko3UMgm4nLc7IBKfFnMzPclLG5rXvwmcwjLUY= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 365CF3858412 for ; Wed, 28 Jun 2023 03:29:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 365CF3858412 Received: from mail-qt1-f197.google.com (mail-qt1-f197.google.com [209.85.160.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-612-fj5JdqhnO9SdCRR8GdZNMA-1; Tue, 27 Jun 2023 23:29:38 -0400 X-MC-Unique: fj5JdqhnO9SdCRR8GdZNMA-1 Received: by mail-qt1-f197.google.com with SMTP id d75a77b69052e-3fde20eded9so57573601cf.2 for ; Tue, 27 Jun 2023 20:29:38 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687922978; x=1690514978; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=hBme8+iZThKKd4FFIl0P9tyPMdrufTPO7comB37XtIc=; b=GOk4cmm0PdnR1fHffae0JNoLtf4UyTC3x86HAMCl7QcM7VuiDq5V+Vmu6Jekm+6Vi+ BdpCeTPwWRFNGuOtMd25ipjTPVdw1j91MHRaNodgElGgQq4fcmnFdsWll81PV3WDYho8 3Gzb0DnyRf9txBYS063qEbwn6xAx/1YZW7R2yOzq28B6np1LO9K9vi7Zyjup9kT+sHiY n3ExQ8BRt9rmIc9Zq3xTPVfnY1+Orn5nqIIJiwgOzfOw7tWtCfeNEkP+wCAdIPcG41/y mqnQ2YTM1vKWs5SswZmZkvTgBLOLngUN5KgkEqIsvs3JpY++0kPERi+wi0HzexKkCLyG Bwyw== X-Gm-Message-State: AC+VfDx5bg+oKUngQFDNBU+FiLokf1s6HH8x+uad4OTSmv6U2L+Q/LZQ H4yAbXCoWAfxqKiGbbGOEkjIYcQeYKqJ9i6BhQ3byhesUzihCkiv+IEMq7vERVx73PiRNDldPKk KnCxIWBa7J+H6mpcTD4mNjV3mTEZMXxjeLl1gv5pxmbysDvplfwc/yBdw5POAR1udRStW4khn+w == X-Received: by 2002:a05:622a:1baa:b0:400:80ac:badc with SMTP id bp42-20020a05622a1baa00b0040080acbadcmr19083441qtb.33.1687922977619; Tue, 27 Jun 2023 20:29:37 -0700 (PDT) X-Received: by 2002:a05:622a:1baa:b0:400:80ac:badc with SMTP id bp42-20020a05622a1baa00b0040080acbadcmr19083413qtb.33.1687922976892; Tue, 27 Jun 2023 20:29:36 -0700 (PDT) Received: from jason.com (130-44-146-16.s12558.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.146.16]) by smtp.gmail.com with ESMTPSA id f14-20020ac859ce000000b003f9c6a311e1sm3470479qtf.47.2023.06.27.20.29.35 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Jun 2023 20:29:36 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [pushed] c++: C++26 constexpr cast from void* [PR110344] Date: Tue, 27 Jun 2023 23:29:34 -0400 Message-Id: <20230628032934.2615167-1-jason@redhat.com> X-Mailer: git-send-email 2.39.3 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, 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: Jason Merrill via Gcc-patches From: Jason Merrill Reply-To: Jason Merrill Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769915600971660871?= X-GMAIL-MSGID: =?utf-8?q?1769915600971660871?= Tested x86_64-pc-linux-gnu, applying to trunk. -- 8< -- P2768 allows static_cast from void* to ob* in constant evaluation if the pointer does in fact point to an object of the appropriate type. cxx_fold_indirect_ref already does the work of finding such an object if it happens to be a subobject rather than the outermost object at that address, as in constexpr-voidptr2.C. P2768 PR c++/110344 gcc/c-family/ChangeLog: * c-cppbuiltin.cc (c_cpp_builtins): Update __cpp_constexpr. gcc/cp/ChangeLog: * constexpr.cc (cxx_eval_constant_expression): In C++26, allow cast from void* to the type of a pointed-to object. gcc/testsuite/ChangeLog: * g++.dg/cpp26/constexpr-voidptr1.C: New test. * g++.dg/cpp26/constexpr-voidptr2.C: New test. * g++.dg/cpp26/feat-cxx26.C: New test. --- gcc/c-family/c-cppbuiltin.cc | 8 +- gcc/cp/constexpr.cc | 11 + .../g++.dg/cpp26/constexpr-voidptr1.C | 35 + .../g++.dg/cpp26/constexpr-voidptr2.C | 15 + gcc/testsuite/g++.dg/cpp26/feat-cxx26.C | 597 ++++++++++++++++++ 5 files changed, 665 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp26/constexpr-voidptr1.C create mode 100644 gcc/testsuite/g++.dg/cpp26/constexpr-voidptr2.C create mode 100644 gcc/testsuite/g++.dg/cpp26/feat-cxx26.C base-commit: ebe7c586f62b1c5218b19c3c6853163287b3c887 prerequisite-patch-id: 8aff665478d425e404ede05fed4c0e4106a063f2 diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index 5d64625fcd7..6bd4c1261a7 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -1075,12 +1075,18 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_size_t_suffix=202011L"); cpp_define (pfile, "__cpp_if_consteval=202106L"); cpp_define (pfile, "__cpp_auto_cast=202110L"); - cpp_define (pfile, "__cpp_constexpr=202211L"); + if (cxx_dialect <= cxx23) + cpp_define (pfile, "__cpp_constexpr=202211L"); cpp_define (pfile, "__cpp_multidimensional_subscript=202211L"); cpp_define (pfile, "__cpp_named_character_escapes=202207L"); cpp_define (pfile, "__cpp_static_call_operator=202207L"); cpp_define (pfile, "__cpp_implicit_move=202207L"); } + if (cxx_dialect > cxx23) + { + /* Set feature test macros for C++26. */ + cpp_define (pfile, "__cpp_constexpr=202306L"); + } if (flag_concepts) { if (cxx_dialect >= cxx20) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 432b3a275e8..cca0435bafc 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -7681,6 +7681,17 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, && !is_std_construct_at (ctx->call) && !is_std_allocator_allocate (ctx->call)) { + /* P2738 (C++26): a conversion from a prvalue P of type "pointer to + cv void" to a pointer-to-object type T unless P points to an + object whose type is similar to T. */ + if (cxx_dialect > cxx23) + if (tree ob + = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (type), op)) + { + r = build1 (ADDR_EXPR, type, ob); + break; + } + /* Likewise, don't error when casting from void* when OP is &heap uninit and similar. */ tree sop = tree_strip_nop_conversions (op); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-voidptr1.C b/gcc/testsuite/g++.dg/cpp26/constexpr-voidptr1.C new file mode 100644 index 00000000000..ce0ccbef5f9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-voidptr1.C @@ -0,0 +1,35 @@ +// PR c++/110344 +// { dg-do compile { target c++26 } } + +#include +struct Sheep { + constexpr std::string_view speak() const noexcept { return "Baaaaaa"; } +}; +struct Cow { + constexpr std::string_view speak() const noexcept { return "Mooo"; } +}; +class Animal_View { +private: + const void *animal; + std::string_view (*speak_function)(const void *); +public: + template + constexpr Animal_View(const Animal &a) + : animal{&a}, speak_function{[](const void *object) { + return static_cast(object)->speak(); + }} {} + constexpr std::string_view speak() const noexcept { + return speak_function(animal); + } +}; +// This is the key bit here. This is a single concrete function +// that can take anything that happens to have the "Animal_View" +// interface +constexpr std::string_view do_speak(Animal_View av) { return av.speak(); } +int main() { + // A Cow is a cow. The only think that makes it special + // is that it has a "std::string_view speak() const" member + constexpr Cow cow; + constexpr auto result = do_speak(cow); + return static_cast(result.size()); +} diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-voidptr2.C b/gcc/testsuite/g++.dg/cpp26/constexpr-voidptr2.C new file mode 100644 index 00000000000..e746301e9f9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-voidptr2.C @@ -0,0 +1,15 @@ +// PR c++/110344 +// { dg-do compile { target c++26 } } + +struct A { int i; }; +struct B { A a; }; + +constexpr int f() +{ + B b { 42 }; + void *p = &b; + A* ap = static_cast(p); + return ap->i; +} + +static_assert (f() == 42); diff --git a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C new file mode 100644 index 00000000000..0977d964fe0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C @@ -0,0 +1,597 @@ +// { dg-options "-std=c++26 -I${srcdir}/g++.dg/cpp1y -I${srcdir}/g++.dg/cpp1y/testinc" } + +// C++98 features: + +#ifndef __cpp_rtti +# error "__cpp_rtti" +#elif __cpp_rtti != 199711 +# error "__cpp_rtti != 199711" +#endif + +#ifndef __cpp_exceptions +# error "__cpp_exceptions" +#elif __cpp_exceptions != 199711 +# error "__cpp_exceptions != 199711" +#endif + +// C++11 features: + +#ifndef __cpp_raw_strings +# error "__cpp_raw_strings" +#elif __cpp_raw_strings != 200710 +# error "__cpp_raw_strings != 200710" +#endif + +#ifndef __cpp_unicode_literals +# error "__cpp_unicode_literals" +#elif __cpp_unicode_literals != 200710 +# error "__cpp_unicode_literals != 200710" +#endif + +#ifndef __cpp_user_defined_literals +# error "__cpp_user_defined_literals" +#elif __cpp_user_defined_literals != 200809 +# error "__cpp_user_defined_literals != 200809" +#endif + +#ifndef __cpp_lambdas +# error "__cpp_lambdas" +#elif __cpp_lambdas != 200907 +# error "__cpp_lambdas != 200907" +#endif + +#ifndef __cpp_range_based_for +# error "__cpp_range_based_for" +#elif __cpp_range_based_for != 201603 +# error "__cpp_range_based_for != 201603" +#endif + +#ifndef __cpp_decltype +# error "__cpp_decltype" +#elif __cpp_decltype != 200707 +# error "__cpp_decltype != 200707" +#endif + +#ifndef __cpp_attributes +# error "__cpp_attributes" +#elif __cpp_attributes != 200809 +# error "__cpp_attributes != 200809" +#endif + +#ifndef __cpp_rvalue_references +# error "__cpp_rvalue_references" +#elif __cpp_rvalue_references != 200610 +# error "__cpp_rvalue_references != 200610" +#endif + +#ifndef __cpp_variadic_templates +# error "__cpp_variadic_templates" +#elif __cpp_variadic_templates != 200704 +# error "__cpp_variadic_templates != 200704" +#endif + +#ifndef __cpp_initializer_lists +# error "__cpp_initializer_lists" +#elif __cpp_initializer_lists != 200806 +# error "__cpp_initializer_lists != 200806" +#endif + +#ifndef __cpp_delegating_constructors +# error "__cpp_delegating_constructors" +#elif __cpp_delegating_constructors != 200604 +# error "__cpp_delegating_constructors != 200604" +#endif + +#ifndef __cpp_nsdmi +# error "__cpp_nsdmi" +#elif __cpp_nsdmi != 200809 +# error "__cpp_nsdmi != 200809" +#endif + +#ifndef __cpp_inheriting_constructors +# error "__cpp_inheriting_constructors" +#elif __cpp_inheriting_constructors!= 201511 +# error "__cpp_inheriting_constructors != 201511" +#endif + +#ifndef __cpp_ref_qualifiers +# error "__cpp_ref_qualifiers" +#elif __cpp_ref_qualifiers != 200710 +# error "__cpp_ref_qualifiers != 200710" +#endif + +#ifndef __cpp_alias_templates +# error "__cpp_alias_templates" +#elif __cpp_alias_templates != 200704 +# error "__cpp_alias_templates != 200704" +#endif + +#ifndef __cpp_threadsafe_static_init +# error "__cpp_threadsafe_static_init" +#elif __cpp_threadsafe_static_init != 200806 +# error "__cpp_threadsafe_static_init != 200806" +#endif + +// C++14 features: + +#ifndef __cpp_binary_literals +# error "__cpp_binary_literals" +#elif __cpp_binary_literals != 201304 +# error "__cpp_binary_literals != 201304" +#endif + +#ifndef __cpp_init_captures +# error "__cpp_init_captures" +#elif __cpp_init_captures != 201803 +# error "__cpp_init_captures != 201803" +#endif + +#ifndef __cpp_generic_lambdas +# error "__cpp_generic_lambdas" +#elif __cpp_generic_lambdas != 201707 +# error "__cpp_generic_lambdas != 201707" +#endif + +#ifndef __cpp_constexpr +# error "__cpp_constexpr" +#elif __cpp_constexpr != 202306L +# error "__cpp_constexpr != 202306L" +#endif + +#ifndef __cpp_decltype_auto +# error "__cpp_decltype_auto" +#elif __cpp_decltype_auto != 201304 +# error "__cpp_decltype_auto != 201304" +#endif + +#ifndef __cpp_return_type_deduction +# error "__cpp_return_type_deduction" +#elif __cpp_return_type_deduction != 201304 +# error "__cpp_return_type_deduction != 201304" +#endif + +#ifndef __cpp_aggregate_nsdmi +# error "__cpp_aggregate_nsdmi" +#elif __cpp_aggregate_nsdmi != 201304 +# error "__cpp_aggregate_nsdmi != 201304" +#endif + +#ifndef __cpp_variable_templates +# error "__cpp_variable_templates" +#elif __cpp_variable_templates != 201304 +# error "__cpp_variable_templates != 201304" +#endif + +#ifndef __cpp_digit_separators +# error "__cpp_digit_separators" +#elif __cpp_digit_separators != 201309 +# error "__cpp_digit_separators != 201309" +#endif + +#ifndef __cpp_sized_deallocation +# error "__cpp_sized_deallocation" +#elif __cpp_sized_deallocation != 201309 +# error "__cpp_sized_deallocation != 201309" +#endif + +// GNU VLA support: + +#ifndef __cpp_runtime_arrays +# error "__cpp_runtime_arrays" +#elif __cpp_runtime_arrays != 198712 +# error "__cpp_runtime_arrays != 198712" +#endif + +// C++11 attributes: + +#ifdef __has_cpp_attribute +# if ! __has_cpp_attribute(noreturn) +# error "__has_cpp_attribute(noreturn)" +# elif __has_cpp_attribute(noreturn) != 200809 +# error "__has_cpp_attribute(noreturn) != 200809" +# endif +#else +# error "__has_cpp_attribute" +#endif + +// Attribute carries_dependency not in yet. +//#ifdef __has_cpp_attribute +//# if ! __has_cpp_attribute(carries_dependency) +//# error "__has_cpp_attribute(carries_dependency)" +//# elif __has_cpp_attribute(carries_dependency) != 200809 +//# error "__has_cpp_attribute(carries_dependency) != 200809" +//# endif +//#else +//# error "__has_cpp_attribute" +//#endif + +// C++14 attributes: + +#ifdef __has_cpp_attribute +# if ! __has_cpp_attribute(deprecated) +# error "__has_cpp_attribute(deprecated)" +# elif __has_cpp_attribute(deprecated) != 201309 +# error "__has_cpp_attribute(deprecated) != 201309" +# endif +#else +# error "__has_cpp_attribute" +#endif + +// Include checks: + +// Check for __has_include macro. +#ifndef __has_include +# error "__has_include" +#endif + +// Try known bracket header (use operator). +#if __has_include () +#else +# error "" +#endif + +// Define and use a macro to invoke the operator. +#define sluggo(TXT) __has_include(TXT) + +#if sluggo() +#else +# error "" +#endif + +#if ! sluggo() +# error "" +#else +#endif + +// Quoted complex.h should find at least the bracket version. +#if __has_include("complex.h") +#else +# error "complex.h" +#endif + +// Try known local quote header. +#if __has_include("complex_literals.h") +#else +# error "\"complex_literals.h\"" +#endif + +// Try nonexistent bracket header. +#if __has_include() +# error "" +#else +#endif + +// Try nonexistent quote header. +#if __has_include("phlegm") +# error "\"phlegm\"" +#else +#endif + +// Test __has_include_next. +#if __has_include("phoobhar.h") +# include "phoobhar.h" +#else +# error "__has_include(\"phoobhar.h\")" +#endif + +// Try a macro. +#define COMPLEX_INC "complex.h" +#if __has_include(COMPLEX_INC) +#else +# error COMPLEX_INC +#endif + +// Realistic use of __has_include. +#if __has_include() +# define STD_ARRAY 1 +# include + template + using array = std::array<_Tp, _Num>; +#elif __has_include() +# define TR1_ARRAY 1 +# include + template + typedef std::tr1::array<_Tp, _Num> array; +#endif + +// C++17 features: + +#ifndef __cpp_unicode_characters +# error "__cpp_unicode_characters" +#elif __cpp_unicode_characters != 201411 +# error "__cpp_unicode_characters != 201411" +#endif + +#ifndef __cpp_static_assert +# error "__cpp_static_assert" +#elif __cpp_static_assert != 201411 +# error "__cpp_static_assert != 201411" +#endif + +#ifndef __cpp_namespace_attributes +# error "__cpp_namespace_attributes" +#elif __cpp_namespace_attributes != 201411 +# error "__cpp_namespace_attributes != 201411" +#endif + +#ifndef __cpp_enumerator_attributes +# error "__cpp_enumerator_attributes" +#elif __cpp_enumerator_attributes != 201411 +# error "__cpp_enumerator_attributes != 201411" +#endif + +#ifndef __cpp_nested_namespace_definitions +# error "__cpp_nested_namespace_definitions" +#elif __cpp_nested_namespace_definitions != 201411 +# error "__cpp_nested_namespace_definitions != 201411" +#endif + +#ifndef __cpp_fold_expressions +# error "__cpp_fold_expressions" +#elif __cpp_fold_expressions != 201603 +# error "__cpp_fold_expressions != 201603" +#endif + +#ifndef __cpp_nontype_template_args +# error "__cpp_nontype_template_args" +#elif __cpp_nontype_template_args != 201911 +# error "__cpp_nontype_template_args != 201911" +#endif + +#ifndef __cpp_hex_float +# error "__cpp_hex_float" +#elif __cpp_hex_float != 201603 +# error "__cpp_hex_float != 201603" +#endif + +#ifndef __cpp_aggregate_bases +# error "__cpp_aggregate_bases" +#elif __cpp_aggregate_bases != 201603 +# error "__cpp_aggregate_bases != 201603" +#endif + +#ifndef __cpp_deduction_guides +# error "__cpp_deduction_guides" +#elif __cpp_deduction_guides != 201907 +# error "__cpp_deduction_guides != 201907" +#endif + +#ifndef __cpp_if_constexpr +# error "__cpp_if_constexpr" +#elif __cpp_if_constexpr != 201606 +# error "__cpp_if_constexpr != 201606" +#endif + +#ifndef __cpp_aligned_new +# error "__cpp_aligned_new" +#elif __cpp_aligned_new != 201606 +# error "__cpp_aligned_new != 201606" +#endif + +#ifndef __cpp_template_auto +# error "__cpp_template_auto" +#elif __cpp_template_auto != 201606 +# error "__cpp_template_auto != 201606" +#endif + +#ifndef __cpp_inline_variables +# error "__cpp_inline_variables" +#elif __cpp_inline_variables != 201606 +# error "__cpp_inline_variables != 201606" +#endif + +#ifndef __cpp_capture_star_this +# error "__cpp_capture_star_this" +#elif __cpp_capture_star_this != 201603 +# error "__cpp_capture_star_this != 201603" +#endif + +#ifndef __cpp_noexcept_function_type +# error "__cpp_noexcept_function_type" +#elif __cpp_noexcept_function_type != 201510 +# error "__cpp_noexcept_function_type != 201510" +#endif + +#ifndef __cpp_structured_bindings +# error "__cpp_structured_bindings" +#elif __cpp_structured_bindings != 201606 +# error "__cpp_structured_bindings != 201606" +#endif + +#ifndef __cpp_template_template_args +# error "__cpp_template_template_args" +#elif __cpp_template_template_args != 201611 +# error "__cpp_template_template_args != 201611" +#endif + +#ifndef __cpp_variadic_using +# error "__cpp_variadic_using" +#elif __cpp_variadic_using != 201611 +# error "__cpp_variadic_using != 201611" +#endif + +#ifndef __cpp_guaranteed_copy_elision +# error "__cpp_guaranteed_copy_elision" +#elif __cpp_guaranteed_copy_elision != 201606 +# error "__cpp_guaranteed_copy_elision != 201606" +#endif + +#ifndef __cpp_nontype_template_parameter_auto +# error "__cpp_nontype_template_parameter_auto" +#elif __cpp_nontype_template_parameter_auto != 201606 +# error "__cpp_nontype_template_parameter_auto != 201606" +#endif + +// C++20 features: + +#ifndef __cpp_conditional_explicit +# error "__cpp_conditional_explicit" +#elif __cpp_conditional_explicit != 201806 +# error "__cpp_conditional_explicit != 201806" +#endif + +#ifndef __cpp_nontype_template_parameter_class +# error "__cpp_nontype_template_parameter_class" +#elif __cpp_nontype_template_parameter_class != 201806 +# error "__cpp_nontype_template_parameter_class != 201806" +#endif + +#ifndef __cpp_impl_destroying_delete +# error "__cpp_impl_destroying_delete" +#elif __cpp_impl_destroying_delete != 201806 +# error "__cpp_impl_destroying_delete != 201806" +#endif + +#ifndef __cpp_constinit +# error "__cpp_constinit" +#elif __cpp_constinit != 201907 +# error "__cpp_constinit != 201907" +#endif + +#ifndef __cpp_constexpr_dynamic_alloc +# error "__cpp_constexpr_dynamic_alloc" +#elif __cpp_constexpr_dynamic_alloc != 201907 +# error "__cpp_constexpr_dynamic_alloc != 201907" +#endif + +#ifndef __cpp_aggregate_paren_init +# error "__cpp_aggregate_paren_init" +#elif __cpp_aggregate_paren_init != 201902 +# error "__cpp_aggregate_paren_init != 201902" +#endif + +#ifndef __cpp_char8_t +# error "__cpp_char8_t" +#elif __cpp_char8_t != 202207 +# error "__cpp_char8_t != 202207" +#endif + +#ifndef __cpp_designated_initializers +# error "__cpp_designated_initializers" +#elif __cpp_designated_initializers != 201707 +# error "__cpp_designated_initializers != 201707" +#endif + +#ifndef __cpp_constexpr_in_decltype +# error "__cpp_constexpr_in_decltype" +#elif __cpp_constexpr_in_decltype != 201711 +# error "__cpp_constexpr_in_decltype != 201711" +#endif + +#ifndef __cpp_consteval +# error "__cpp_consteval" +#elif __cpp_consteval != 201811 +# error "__cpp_consteval != 201811" +#endif + +#ifndef __cpp_concepts +# error "__cpp_concepts" +#elif __cpp_concepts != 202002 +# error "__cpp_concepts != 202002" +#endif + +#ifndef __cpp_using_enum +# error "__cpp_using_enum" +#elif __cpp_using_enum != 201907 +# error "__cpp_using_enum != 201907" +#endif + +// C++20 attributes: + +#ifdef __has_cpp_attribute + +# if ! __has_cpp_attribute(maybe_unused) +# error "__has_cpp_attribute(maybe_unused)" +# elif __has_cpp_attribute(maybe_unused) != 201603 +# error "__has_cpp_attribute(maybe_unused) != 201603" +# endif + +# if ! __has_cpp_attribute(nodiscard) +# error "__has_cpp_attribute(nodiscard)" +# elif __has_cpp_attribute(nodiscard) != 201907 +# error "__has_cpp_attribute(nodiscard) != 201907" +# endif + +# if ! __has_cpp_attribute(fallthrough) +# error "__has_cpp_attribute(fallthrough)" +# elif __has_cpp_attribute(fallthrough) != 201603 +# error "__has_cpp_attribute(fallthrough) != 201603" +# endif + +# if ! __has_cpp_attribute(no_unique_address) +# error "__has_cpp_attribute(no_unique_address)" +# elif __has_cpp_attribute(no_unique_address) != 201803 +# error "__has_cpp_attribute(no_unique_address) != 201803" +# endif + +# if ! __has_cpp_attribute(likely) +# error "__has_cpp_attribute(likely)" +# elif __has_cpp_attribute(likely) != 201803 +# error "__has_cpp_attribute(likely) != 201803" +# endif + +# if ! __has_cpp_attribute(unlikely) +# error "__has_cpp_attribute(unlikely)" +# elif __has_cpp_attribute(unlikely) != 201803 +# error "__has_cpp_attribute(unlikely) != 201803" +# endif + +#else +# error "__has_cpp_attribute" +#endif + +// C++23 features: + +#ifndef __cpp_size_t_suffix +# error "__cpp_size_t_suffix" +#elif __cpp_size_t_suffix != 202011 +# error "__cpp_size_t_suffix != 202011" +#endif + +#ifndef __cpp_if_consteval +# error "__cpp_if_consteval" +#elif __cpp_if_consteval != 202106 +# error "__cpp_if_consteval != 202106" +#endif + +#ifndef __cpp_multidimensional_subscript +# error "__cpp_multidimensional_subscript" +#elif __cpp_multidimensional_subscript != 202211 +# error "__cpp_multidimensional_subscript != 202211" +#endif + +#ifndef __cpp_named_character_escapes +# error "__cpp_named_character_escapes" +#elif __cpp_named_character_escapes != 202207 +# error "__cpp_named_character_escapes != 202207" +#endif + +#ifndef __cpp_static_call_operator +# error "__cpp_static_call_operator" +#elif __cpp_static_call_operator != 202207 +# error "__cpp_static_call_operator != 202207" +#endif + +#ifndef __cpp_implicit_move +# error "__cpp_implicit_move" +#elif __cpp_implicit_move != 202207 +# error "__cpp_implicit_move != 202207" +#endif + +#ifndef __cpp_auto_cast +# error "__cpp_auto_cast" +#elif __cpp_auto_cast != 202110 +# error "__cpp_auto_cast != 202110" +#endif + +// C++23 attributes: + +#ifdef __has_cpp_attribute +# if ! __has_cpp_attribute(assume) +# error "__has_cpp_attribute(assume)" +# elif __has_cpp_attribute(assume) != 202207 +# error "__has_cpp_attribute(assume) != 202207" +# endif +#else +# error "__has_cpp_attribute" +#endif