From patchwork Thu Aug 10 15:35:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 134046 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp503890vqi; Thu, 10 Aug 2023 08:36:04 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHWzb33lqQpiMO8ym+tjQQ34GVeZnGJsCDtJzKCyQ85ggPiFTgDmjNSqlrX2VqqSSRSy5aE X-Received: by 2002:a17:906:5346:b0:98e:16b7:e038 with SMTP id j6-20020a170906534600b0098e16b7e038mr2628587ejo.23.1691681764423; Thu, 10 Aug 2023 08:36:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1691681764; cv=none; d=google.com; s=arc-20160816; b=qovRqsIUCdkBWSHXPoU9DdheywKiGYN2S7hEaWlqKh2JwPl6ZQV5FN0pITk9zHPUyg +Cwz6UAXxBW7ERkqyyOjlBE1mwVjkebKo/TjCjmcrvIGh9Q8h2WYaB1berwfGZQSk3yg TrsEPnyAUBBRrnQQXaT6MTqrHMOnl4f36FzNG1dsGdIJg2MUuj6QUE38CnXpPYEX93/X qldWS0f8QqKpu3heSSQRgYf0M/hngzCiAPPfbWJdh7u1GOzOlaBtuula7D32WOCFXUuy EaB1rxLdCcT9Kos+9xGos6xMF07UjDvmPjGsO1l0lUgnLiri8iMg6C0ygyEbQu1LtgCx YeYg== 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-disposition:in-reply-to:mime-version:references:message-id :subject:to:date:dmarc-filter:delivered-to:dkim-signature :dkim-filter; bh=mY+mGiVYaSuJAh//d/CXMLyx7M2QjeLYjGPAwACV+cg=; fh=a9XWAXFKupnMkifJ7pUFYfWW4zl2NlP6nOEIveLmtiY=; b=nfEzTETxCNJDbVKmkhMSG+xJhEzWBIVXwAEIZUOKCr0wlhab+0anBjaMpbzULBFbqh T3//EMdtMfG3HYlkwK16P8b1vLuCJDAqLnK+EHEU7OYxM/WePjoV1+mWHKgZZ3kdRbPu v8ASKF1A8T3LBsI2b4AEKGFyoA7ErYvXd3+mY35j5Z9hNWPkGWtPL3TdKCTlrmivB8jA MFEbqlVshxfhQ3M27DPjOVPIOg70wteNrPutuN1eZXvoKu1gV+IS/Exr7tkOM7DiKY8/ V9Ab/3B9FW6kHb2tfX/4+eMZd6INdmYlkXls6xk3XSHFqoT/MsFUr5RSuo8YVE7fbJ9J iLlw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=W6hoTTOt; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id h3-20020a1709060f4300b009927d850155si1614999ejj.892.2023.08.10.08.36.04 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Aug 2023 08:36:04 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=W6hoTTOt; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id F30513857B98 for ; Thu, 10 Aug 2023 15:36:02 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F30513857B98 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1691681763; bh=mY+mGiVYaSuJAh//d/CXMLyx7M2QjeLYjGPAwACV+cg=; h=Date:To:Subject:References:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=W6hoTTOtTi1P44xlblMqRx1GUdSihzIimeGFu4fs8qHfz4lAN2rOEObrnjxIaXjHp 2G6dHQkbcsFIdDhJCu9PyAYyW4QjOwLr+UXtpSLQPdAAcATyxSWKX6m9z5LUX5xJti OBSd5/AJ7mD6aQi+YGqOusOwCgFvg+7v7rAP3pVo= 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.129.124]) by sourceware.org (Postfix) with ESMTPS id 00AA03858288 for ; Thu, 10 Aug 2023 15:35:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 00AA03858288 Received: from mimecast-mx02.redhat.com (66.187.233.73 [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-183-M0e4EwmiPiyGiexUAt4HPQ-1; Thu, 10 Aug 2023 11:35:13 -0400 X-MC-Unique: M0e4EwmiPiyGiexUAt4HPQ-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id CF4E52812942; Thu, 10 Aug 2023 15:35:12 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.45.225.169]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 717ABC15BAE; Thu, 10 Aug 2023 15:35:12 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 37AFZAaB2356860 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Thu, 10 Aug 2023 17:35:10 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 37AFZ9vU2356859; Thu, 10 Aug 2023 17:35:09 +0200 Date: Thu, 10 Aug 2023 17:35:09 +0200 To: "Joseph S. Myers" , Marek Polacek , Jason Merrill , gcc-patches@gcc.gnu.org Subject: [PATCH] c, c++, v2: Accept __builtin_classify_type (typename) Message-ID: References: MIME-Version: 1.0 In-Reply-To: X-Scanned-By: MIMEDefang 3.1 on 10.11.54.8 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-14.8 required=5.0 tests=BAYES_00, DKIM_INVALID, DKIM_SIGNED, KAM_DMARC_NONE, KAM_DMARC_STATUS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=no 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: Jakub Jelinek via Gcc-patches From: Jakub Jelinek Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1773856898078116950 X-GMAIL-MSGID: 1773856898078116950 Hi! I'd like to ping this patch. Reposting it as I found a typo in the documentation - s/builtin-in/built-in/. Bootstrapped/regtested again on x86_64-linux and i686-linux, ok for trunk? On Mon, Jun 12, 2023 at 09:57:17PM +0200, Jakub Jelinek via Gcc-patches wrote: > As mentioned in my stdckdint.h mail, __builtin_classify_type has > a problem that argument promotion (the argument is passed to ... > prototyped builtin function) means that certain type classes will > simply never appear. > I think it is too late to change how it behaves, lots of code in the > wild might rely on the current behavior. > > So, the following patch adds option to use a typename rather than > expression as the operand to the builtin, making it behave similarly > to sizeof, typeof or say the clang _Generic extension where the > first argument can be there not just expression, but also typename. > > I think we have other prior art here, e.g. __builtin_va_arg also > expects typename. > > I've added this to both C and C++, because it would be weird if it > supported it only in C and not in C++. 2023-08-10 Jakub Jelinek gcc/ * builtins.h (type_to_class): Declare. * builtins.cc (type_to_class): No longer static. Return int rather than enum. * doc/extend.texi (__builtin_classify_type): Document. gcc/c/ * c-parser.cc (c_parser_postfix_expression_after_primary): Parse __builtin_classify_type call with typename as argument. gcc/cp/ * parser.cc (cp_parser_postfix_expression): Parse __builtin_classify_type call with typename as argument. * pt.cc (tsubst_copy_and_build): Handle __builtin_classify_type with dependent typename as argument. gcc/testsuite/ * c-c++-common/builtin-classify-type-1.c: New test. * g++.dg/ext/builtin-classify-type-1.C: New test. * g++.dg/ext/builtin-classify-type-2.C: New test. * gcc.dg/builtin-classify-type-1.c: New test. Jakub --- gcc/builtins.h.jj 2023-01-03 00:20:34.856089856 +0100 +++ gcc/builtins.h 2023-06-12 09:35:20.841902572 +0200 @@ -156,5 +156,6 @@ extern internal_fn associated_internal_f extern internal_fn replacement_internal_fn (gcall *); extern bool builtin_with_linkage_p (tree); +extern int type_to_class (tree); #endif /* GCC_BUILTINS_H */ --- gcc/builtins.cc.jj 2023-05-20 15:31:09.066663352 +0200 +++ gcc/builtins.cc 2023-06-12 09:35:31.709751296 +0200 @@ -113,7 +113,6 @@ static rtx expand_builtin_apply_args (vo static rtx expand_builtin_apply_args_1 (void); static rtx expand_builtin_apply (rtx, rtx, rtx); static void expand_builtin_return (rtx); -static enum type_class type_to_class (tree); static rtx expand_builtin_classify_type (tree); static rtx expand_builtin_mathfn_3 (tree, rtx, rtx); static rtx expand_builtin_mathfn_ternary (tree, rtx, rtx); @@ -1852,7 +1851,7 @@ expand_builtin_return (rtx result) /* Used by expand_builtin_classify_type and fold_builtin_classify_type. */ -static enum type_class +int type_to_class (tree type) { switch (TREE_CODE (type)) --- gcc/doc/extend.texi.jj 2023-06-10 19:58:26.197478291 +0200 +++ gcc/doc/extend.texi 2023-06-12 18:06:24.629413024 +0200 @@ -14354,6 +14354,30 @@ need not be a constant. @xref{Object Si description of the function. @enddefbuiltin +@defbuiltin{int __builtin_classify_type (@var{arg})} +@defbuiltinx{int __builtin_classify_type (@var{type})} +The @code{__builtin_classify_type} returns a small integer with a category +of @var{arg} argument's type, like void type, integer type, enumeral type, +boolean type, pointer type, reference type, offset type, real type, complex +type, function type, method type, record type, union type, array type, +string type, etc. When the argument is an expression, for +backwards compatibility reason the argument is promoted like arguments +passed to @code{...} in varargs function, so some classes are never returned +in certain languages. Alternatively, the argument of the built-in +function can be a typename, such as the @code{typeof} specifier. + +@smallexample +int a[2]; +__builtin_classify_type (a) == __builtin_classify_type (int[5]); +__builtin_classify_type (a) == __builtin_classify_type (void*); +__builtin_classify_type (typeof (a)) == __builtin_classify_type (int[5]); +@end smallexample + +The first comparison will never be true, as @var{a} is implicitly converted +to pointer. The last two comparisons will be true as they classify +pointers in the second case and arrays in the last case. +@enddefbuiltin + @defbuiltin{double __builtin_huge_val (void)} Returns a positive infinity, if supported by the floating-point format, else @code{DBL_MAX}. This function is suitable for implementing the --- gcc/c/c-parser.cc.jj 2023-06-10 19:22:15.577205685 +0200 +++ gcc/c/c-parser.cc 2023-06-12 17:32:31.007413019 +0200 @@ -11213,6 +11213,32 @@ c_parser_postfix_expression_after_primar literal_zero_mask = 0; if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) exprlist = NULL; + else if (TREE_CODE (expr.value) == FUNCTION_DECL + && fndecl_built_in_p (expr.value, BUILT_IN_CLASSIFY_TYPE) + && c_parser_next_tokens_start_typename (parser, + cla_prefer_id)) + { + /* __builtin_classify_type (type) */ + c_inhibit_evaluation_warnings++; + in_typeof++; + struct c_type_name *type = c_parser_type_name (parser); + c_inhibit_evaluation_warnings--; + in_typeof--; + struct c_typespec ret; + ret.expr = NULL_TREE; + ret.spec = error_mark_node; + ret.expr_const_operands = false; + if (type != NULL) + { + ret.spec = groktypename (type, &ret.expr, + &ret.expr_const_operands); + pop_maybe_used (c_type_variably_modified_p (ret.spec)); + } + parens.skip_until_found_close (parser); + expr.value = build_int_cst (integer_type_node, + type_to_class (ret.spec)); + break; + } else exprlist = c_parser_expr_list (parser, true, false, &origtypes, sizeof_arg_loc, sizeof_arg, --- gcc/cp/parser.cc.jj 2023-06-06 20:02:35.631211230 +0200 +++ gcc/cp/parser.cc 2023-06-12 16:19:04.892202240 +0200 @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. #include "c-family/known-headers.h" #include "contracts.h" #include "bitmap.h" +#include "builtins.h" /* The lexer. */ @@ -7850,6 +7851,50 @@ cp_parser_postfix_expression (cp_parser = parser->non_integral_constant_expression_p; parser->integral_constant_expression_p = false; } + else if (TREE_CODE (stripped_expression) == FUNCTION_DECL + && fndecl_built_in_p (stripped_expression, + BUILT_IN_CLASSIFY_TYPE)) + { + /* __builtin_classify_type (type) */ + auto cl1 = make_temp_override + (parser->type_definition_forbidden_message, + G_("types may not be defined in " + "%<__builtin_classify_type%> calls")); + auto cl2 = make_temp_override + (parser->type_definition_forbidden_message_arg, + NULL); + auto cl3 = make_temp_override (parser->in_type_id_in_expr_p, + true); + cp_evaluated ev; + ++cp_unevaluated_operand; + ++c_inhibit_evaluation_warnings; + tentative_firewall firewall (parser); + cp_parser_parse_tentatively (parser); + matching_parens parens; + parens.consume_open (parser); + tree type = cp_parser_type_id (parser); + parens.require_close (parser); + if (cp_parser_parse_definitely (parser)) + { + if (dependent_type_p (type)) + { + postfix_expression = build_vl_exp (CALL_EXPR, 4); + CALL_EXPR_FN (postfix_expression) + = stripped_expression; + CALL_EXPR_STATIC_CHAIN (postfix_expression) = type; + CALL_EXPR_ARG (postfix_expression, 0) + = build_min (SIZEOF_EXPR, size_type_node, type); + TREE_TYPE (postfix_expression) = integer_type_node; + } + else + { + postfix_expression + = build_int_cst (integer_type_node, + type_to_class (type)); + } + break; + } + } args = (cp_parser_parenthesized_expression_list (parser, non_attr, /*cast_p=*/false, /*allow_expansion_p=*/true, --- gcc/cp/pt.cc.jj 2023-06-06 20:02:35.000000000 +0200 +++ gcc/cp/pt.cc 2023-06-12 16:19:06.495180108 +0200 @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. #include "gcc-rich-location.h" #include "selftest.h" #include "target.h" +#include "builtins.h" /* The type of functions taking a tree, and some additional data, and returning an int. */ @@ -20963,6 +20964,25 @@ tsubst_copy_and_build (tree t, /*done=*/false, /*address_p=*/false); } + else if (CALL_EXPR_STATIC_CHAIN (t) + && TREE_CODE (function) == FUNCTION_DECL + && fndecl_built_in_p (function, BUILT_IN_CLASSIFY_TYPE)) + { + tree type = tsubst (CALL_EXPR_STATIC_CHAIN (t), args, complain, + in_decl); + if (dependent_type_p (type)) + { + ret = build_vl_exp (CALL_EXPR, 4); + CALL_EXPR_FN (ret) = function; + CALL_EXPR_STATIC_CHAIN (ret) = type; + CALL_EXPR_ARG (ret, 0) + = build_min (SIZEOF_EXPR, size_type_node, type); + TREE_TYPE (ret) = integer_type_node; + } + else + ret = build_int_cst (integer_type_node, type_to_class (type)); + RETURN (ret); + } else if (koenig_p && (identifier_p (function) || (TREE_CODE (function) == TEMPLATE_ID_EXPR --- gcc/testsuite/c-c++-common/builtin-classify-type-1.c.jj 2023-06-12 14:27:19.087986210 +0200 +++ gcc/testsuite/c-c++-common/builtin-classify-type-1.c 2023-06-12 16:23:07.029859079 +0200 @@ -0,0 +1,105 @@ +/* { dg-do run { target { c || c++11 } } } */ + +#if !defined(__cplusplus) && __STDC_VERSION__ <= 201710L +#define static_assert _Static_assert +#define bool _Bool +#define false ((_Bool) 0) +#endif +#ifdef __cplusplus +extern "C" void abort (); +#else +extern void abort (void); +#endif + +int +main () +{ + enum E { E1 } e = E1; + struct S { int s; } s = { 0 }; + union U { int u; } u = { 0 }; + int a[2] = { 0, 0 }; + bool b = false; + const char *p = (const char *) 0; + float f = 0.0; + _Complex double c = 0.0; +#ifdef __cplusplus + struct T { void foo (); }; + int &r = a[0]; + int S::*q = &S::s; +#endif + static_assert (__builtin_classify_type (void) == 0, ""); + static_assert (__builtin_classify_type (int) == 1, ""); + static_assert (__builtin_classify_type (enum E) == 3, ""); + static_assert (__builtin_classify_type (bool) == 4, ""); + static_assert (__builtin_classify_type (const char *) == 5, ""); +#ifdef __cplusplus + static_assert (__builtin_classify_type (int &) == 6, ""); + static_assert (__builtin_classify_type (int &&) == 6, ""); + static_assert (__builtin_classify_type (int S::*) == 7, ""); +#endif + static_assert (__builtin_classify_type (float) == 8, ""); + static_assert (__builtin_classify_type (_Complex double) == 9, ""); + static_assert (__builtin_classify_type (int (int, int)) == 10, ""); + static_assert (__builtin_classify_type (struct S) == 12, ""); + static_assert (__builtin_classify_type (union U) == 13, ""); + static_assert (__builtin_classify_type (int [2]) == 14, ""); + static_assert (__builtin_classify_type (__typeof__ (a[0])) == 1, ""); + static_assert (__builtin_classify_type (__typeof__ (e)) == 3, ""); + static_assert (__builtin_classify_type (__typeof__ (b)) == 4, ""); + static_assert (__builtin_classify_type (__typeof__ (p)) == 5, ""); +#ifdef __cplusplus + static_assert (__builtin_classify_type (decltype (r)) == 6, ""); + static_assert (__builtin_classify_type (__typeof__ (q)) == 7, ""); +#endif + static_assert (__builtin_classify_type (__typeof__ (f)) == 8, ""); + static_assert (__builtin_classify_type (__typeof__ (c)) == 9, ""); + static_assert (__builtin_classify_type (__typeof__ (main)) == 10, ""); + static_assert (__builtin_classify_type (__typeof__ (s)) == 12, ""); + static_assert (__builtin_classify_type (__typeof__ (u)) == 13, ""); + static_assert (__builtin_classify_type (__typeof__ (a)) == 14, ""); +#ifndef __cplusplus + static_assert (__builtin_classify_type (a[0]) == 1, ""); + static_assert (__builtin_classify_type (e) == 1, ""); + static_assert (__builtin_classify_type (b) == 1, ""); + static_assert (__builtin_classify_type (p) == 5, ""); + static_assert (__builtin_classify_type (f) == 8, ""); + static_assert (__builtin_classify_type (c) == 9, ""); + static_assert (__builtin_classify_type (main) == 5, ""); + static_assert (__builtin_classify_type (s) == 12, ""); + static_assert (__builtin_classify_type (u) == 13, ""); + static_assert (__builtin_classify_type (a) == 5, ""); +#endif + if (__builtin_classify_type (a[0]) != 1) + abort (); +#ifdef __cplusplus + if (__builtin_classify_type (e) != 3) + abort (); + if (__builtin_classify_type (b) != 4) + abort (); +#else + if (__builtin_classify_type (e) != 1) + abort (); + if (__builtin_classify_type (b) != 1) + abort (); +#endif + if (__builtin_classify_type (p) != 5) + abort (); +#ifdef __cplusplus + if (__builtin_classify_type (r) != 1) + abort (); + if (__builtin_classify_type (q) != 7) + abort (); +#endif + if (__builtin_classify_type (f) != 8) + abort (); + if (__builtin_classify_type (c) != 9) + abort (); + if (__builtin_classify_type (main) != 5) + abort (); + if (__builtin_classify_type (s) != 12) + abort (); + if (__builtin_classify_type (u) != 13) + abort (); + if (__builtin_classify_type (a) != 5) + abort (); +} --- gcc/testsuite/g++.dg/ext/builtin-classify-type-1.C.jj 2023-06-12 15:03:37.488813774 +0200 +++ gcc/testsuite/g++.dg/ext/builtin-classify-type-1.C 2023-06-12 16:24:17.787882132 +0200 @@ -0,0 +1,149 @@ +// { dg-do run { target c++11 } } + +extern "C" void abort (); + +template +void +foo () +{ + enum E { E1 } e = E1; + struct S { int s; } s = { 0 }; + union U { int u; } u = { 0 }; + int a[2] = { 0, 0 }; + bool b = false; + const char *p = (const char *) 0; + float f = 0.0; + _Complex double c = 0.0; + struct T { void foo (); }; + int &r = a[0]; + int S::*q = &S::s; + static_assert (__builtin_classify_type (void) == 0, ""); + static_assert (__builtin_classify_type (int) == 1, ""); + static_assert (__builtin_classify_type (enum E) == 3, ""); + static_assert (__builtin_classify_type (bool) == 4, ""); + static_assert (__builtin_classify_type (const char *) == 5, ""); + static_assert (__builtin_classify_type (int &) == 6, ""); + static_assert (__builtin_classify_type (int &&) == 6, ""); + static_assert (__builtin_classify_type (int S::*) == 7, ""); + static_assert (__builtin_classify_type (float) == 8, ""); + static_assert (__builtin_classify_type (_Complex double) == 9, ""); + static_assert (__builtin_classify_type (int (int, int)) == 10, ""); + static_assert (__builtin_classify_type (struct S) == 12, ""); + static_assert (__builtin_classify_type (union U) == 13, ""); + static_assert (__builtin_classify_type (int [2]) == 14, ""); + static_assert (__builtin_classify_type (__typeof__ (a[0])) == 1, ""); + static_assert (__builtin_classify_type (__typeof__ (e)) == 3, ""); + static_assert (__builtin_classify_type (__typeof__ (b)) == 4, ""); + static_assert (__builtin_classify_type (__typeof__ (p)) == 5, ""); + static_assert (__builtin_classify_type (decltype (r)) == 6, ""); + static_assert (__builtin_classify_type (__typeof__ (q)) == 7, ""); + static_assert (__builtin_classify_type (__typeof__ (f)) == 8, ""); + static_assert (__builtin_classify_type (__typeof__ (c)) == 9, ""); + static_assert (__builtin_classify_type (__typeof__ (abort)) == 10, ""); + static_assert (__builtin_classify_type (__typeof__ (s)) == 12, ""); + static_assert (__builtin_classify_type (__typeof__ (u)) == 13, ""); + static_assert (__builtin_classify_type (__typeof__ (a)) == 14, ""); + if (__builtin_classify_type (a[0]) != 1) + abort (); + if (__builtin_classify_type (e) != 3) + abort (); + if (__builtin_classify_type (b) != 4) + abort (); + if (__builtin_classify_type (p) != 5) + abort (); + if (__builtin_classify_type (r) != 1) + abort (); + if (__builtin_classify_type (q) != 7) + abort (); + if (__builtin_classify_type (f) != 8) + abort (); + if (__builtin_classify_type (c) != 9) + abort (); + if (__builtin_classify_type (abort) != 5) + abort (); + if (__builtin_classify_type (s) != 12) + abort (); + if (__builtin_classify_type (u) != 13) + abort (); + if (__builtin_classify_type (a) != 5) + abort (); +} + +template +void +bar () +{ + E e = (E) 0; + S s = { 0 }; + U u = { 0 }; + A a = { 0, 0 }; + B b = false; + P p = (P) 0; + F f = 0.0; + C c = 0.0; + R1 r = a[0]; + PM q = &S::s; + static_assert (__builtin_classify_type (V) == 0, ""); + static_assert (__builtin_classify_type (I) == 1, ""); + static_assert (__builtin_classify_type (E) == 3, ""); + static_assert (__builtin_classify_type (B) == 4, ""); + static_assert (__builtin_classify_type (P) == 5, ""); + static_assert (__builtin_classify_type (R1) == 6, ""); + static_assert (__builtin_classify_type (R2) == 6, ""); + static_assert (__builtin_classify_type (PM) == 7, ""); + static_assert (__builtin_classify_type (F) == 8, ""); + static_assert (__builtin_classify_type (C) == 9, ""); + static_assert (__builtin_classify_type (FN) == 10, ""); + static_assert (__builtin_classify_type (S) == 12, ""); + static_assert (__builtin_classify_type (U) == 13, ""); + static_assert (__builtin_classify_type (A) == 14, ""); + static_assert (__builtin_classify_type (__typeof__ (a[0])) == 1, ""); + static_assert (__builtin_classify_type (__typeof__ (e)) == 3, ""); + static_assert (__builtin_classify_type (__typeof__ (b)) == 4, ""); + static_assert (__builtin_classify_type (__typeof__ (p)) == 5, ""); + static_assert (__builtin_classify_type (decltype (r)) == 6, ""); + static_assert (__builtin_classify_type (__typeof__ (q)) == 7, ""); + static_assert (__builtin_classify_type (__typeof__ (f)) == 8, ""); + static_assert (__builtin_classify_type (__typeof__ (c)) == 9, ""); + static_assert (__builtin_classify_type (__typeof__ (abort)) == 10, ""); + static_assert (__builtin_classify_type (__typeof__ (s)) == 12, ""); + static_assert (__builtin_classify_type (__typeof__ (u)) == 13, ""); + static_assert (__builtin_classify_type (__typeof__ (a)) == 14, ""); + if (__builtin_classify_type (a[0]) != 1) + abort (); + if (__builtin_classify_type (e) != 3) + abort (); + if (__builtin_classify_type (b) != 4) + abort (); + if (__builtin_classify_type (p) != 5) + abort (); + if (__builtin_classify_type (r) != 1) + abort (); + if (__builtin_classify_type (q) != 7) + abort (); + if (__builtin_classify_type (f) != 8) + abort (); + if (__builtin_classify_type (c) != 9) + abort (); + if (__builtin_classify_type (abort) != 5) + abort (); + if (__builtin_classify_type (s) != 12) + abort (); + if (__builtin_classify_type (u) != 13) + abort (); + if (__builtin_classify_type (a) != 5) + abort (); +} + +int +main () +{ + enum E { E1 }; + struct S { int s; }; + union U { int u; }; + foo <0> (); + bar (); +} --- gcc/testsuite/g++.dg/ext/builtin-classify-type-2.C.jj 2023-06-12 16:28:17.120577700 +0200 +++ gcc/testsuite/g++.dg/ext/builtin-classify-type-2.C 2023-06-12 16:29:57.860186807 +0200 @@ -0,0 +1,11 @@ +// { dg-do compile { target c++11 } } +// { dg-options "" } + +void +foo (int n) +{ + __builtin_classify_type (enum E { E1, E2 }); // { dg-error "types may not be defined in '__builtin_classify_type' calls" } + __builtin_classify_type (struct S { int s; });// { dg-error "types may not be defined in '__builtin_classify_type' calls" } + __builtin_classify_type (union U { int u; }); // { dg-error "types may not be defined in '__builtin_classify_type' calls" } + __builtin_classify_type (int [2 * n + 36]); +} --- gcc/testsuite/gcc.dg/builtin-classify-type-1.c.jj 2023-06-12 17:28:47.118495177 +0200 +++ gcc/testsuite/gcc.dg/builtin-classify-type-1.c 2023-06-12 17:43:46.420114514 +0200 @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ + +void +foo (int n) +{ + _Static_assert (__builtin_classify_type (enum E { E1, E2 }) == 3, ""); + _Static_assert (__builtin_classify_type (struct S { int s; }) == 12, ""); + _Static_assert (__builtin_classify_type (union U { int u; }) == 13, ""); + _Static_assert (__builtin_classify_type (int [2 * n + 36]) == 14, ""); +}