From patchwork Wed Dec 8 10:35:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 48628 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DBADE385841D for ; Wed, 8 Dec 2021 10:36:03 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DBADE385841D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1638959763; bh=oYFPn9FNJotU5j1ZNKUkoHEt82hhdzex3L4Gl/bwm8I=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=kY+/8GBMtIHSCLKUBLYp2vJkL0zYDnziHG7SSxUVOGt0zq7tOEW6gN0oab3eiT53V u13mhnFpaH4d0jigz1XubNGdF8766v2manFI+GXoL1aAQcoG30rLRkVlV+DdSRRjUZ a0F7XAV813aMgupv0mePn+ldd9bW58VAp5QGqx6o= 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 1F3A33858D3C for ; Wed, 8 Dec 2021 10:35:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 1F3A33858D3C Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-515-stns7wA8Px2X66JOWN1UnQ-1; Wed, 08 Dec 2021 05:35:33 -0500 X-MC-Unique: stns7wA8Px2X66JOWN1UnQ-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 41F1B185302A for ; Wed, 8 Dec 2021 10:35:32 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.194.188]) by smtp.corp.redhat.com (Postfix) with ESMTPS id CF74E19C59; Wed, 8 Dec 2021 10:35:31 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.16.1/8.16.1) with ESMTPS id 1B8AZT9t1086930 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Wed, 8 Dec 2021 11:35:29 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.16.1/8.16.1/Submit) id 1B8AZSju1086929; Wed, 8 Dec 2021 11:35:28 +0100 Date: Wed, 8 Dec 2021 11:35:28 +0100 To: Jason Merrill , Jonathan Wakely Subject: [PATCH] c++: Support &typeid(x) == &typeid(y) and typeid(x) == typeid(y) in constant evaluation [PR103600] Message-ID: <20211208103528.GE2646553@tucnak> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-5.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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 Cc: gcc-patches@gcc.gnu.org Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Hi! If the tinfo vars are emitted in the current TU, they are emitted at the end of the compilation, and for some types they are exported from libstdc++/libsupc++ and not emitted in the current TU at all. The following patch allows constant folding of comparisons of typeid addresses and makes it possible to implement P1328R1 - making type_info operator== constexpr (Jonathan has a patch for that). As mentioned in the PR, the varpool/middle-end code is trying to be conservative with address comparisons of different vars if those vars don't bind locally, because of possible aliases in other TUs etc. and so while match.pd folds &typeid(int) == &typeid(int) because it is equality comparison with the same operands, for different typeids it doesn't fold it. The first constexpr.c hunk takes care of that during constant evaluation. As the std::type_info class has a protected member __name only, I think people shouldn't be comparing anything but the starts of those vars, so we don't need to deal with offsets into those vars etc. The other constexpr.c hunk and rtti.c change is to allow constexpr operator== that will in the manifestly constant evaluation just compare the __name members for equality. Again, the _ZTS* variables aren't constructed yet and for some types will not be at all. So, what this patch does is when evaluating typeid(whatever).__name fold the INDIRECT_REF on (const std::type_info *) &_ZTIwhatever into a CONSTRUCTOR_NO_CLEARING ctor with just __name field initialized to &"1S" etc. Testcase coverage includes just the &typeid comparison, for typeid comparison it will be in the libstdc++ patch. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2021-12-08 Jakub Jelinek PR c++/103600 * cp-tree.h (tinfo_for_constant_evaluation): Declare. * constexpr.c (cxx_eval_binary_expression): Evaluate &typeid(x) == &typeid(y) to true or false depending on whether the typeid is the same or not. (cxx_eval_indirect_ref): Fold typeid(S) to {.__name="1S"}. * rtti.c (tinfo_for_constant_evaluation): New function. * g++.dg/cpp0x/constexpr-typeid2.C: New test. Jakub --- gcc/cp/cp-tree.h.jj 2021-12-04 11:02:03.925646583 +0100 +++ gcc/cp/cp-tree.h 2021-12-07 16:58:06.698802940 +0100 @@ -7376,6 +7376,7 @@ extern tree build_dynamic_cast (locati tsubst_flags_t); extern void emit_support_tinfos (void); extern bool emit_tinfo_decl (tree); +extern tree tinfo_for_constant_evaluation (tree); extern unsigned get_pseudo_tinfo_index (tree); extern tree get_pseudo_tinfo_type (unsigned); extern tree build_if_nonnull (tree, tree, tsubst_flags_t); --- gcc/cp/constexpr.c.jj 2021-12-04 11:02:03.949646241 +0100 +++ gcc/cp/constexpr.c 2021-12-07 17:32:07.324739082 +0100 @@ -3346,6 +3346,25 @@ cxx_eval_binary_expression (const conste lhs = cplus_expand_constant (lhs); else if (TREE_CODE (rhs) == PTRMEM_CST) rhs = cplus_expand_constant (rhs); + + /* Fold &typeid(x) == &typeid(y) to + whether the DECL_TINFO_P vars are the same or not. */ + if (flag_rtti) + { + tree op0 = lhs; + tree op1 = rhs; + STRIP_NOPS (op0); + STRIP_NOPS (op1); + if (TREE_CODE (op0) == ADDR_EXPR + && VAR_P (TREE_OPERAND (op0, 0)) + && DECL_TINFO_P (TREE_OPERAND (op0, 0)) + && TREE_CODE (op1) == ADDR_EXPR + && VAR_P (TREE_OPERAND (op1, 0)) + && DECL_TINFO_P (TREE_OPERAND (op1, 0))) + r = constant_boolean_node ((TREE_OPERAND (op0, 0) + != TREE_OPERAND (op1, 0)) + ^ is_code_eq, type); + } } if (code == POINTER_PLUS_EXPR && !*non_constant_p && integer_zerop (lhs) && !integer_zerop (rhs)) @@ -5261,6 +5280,18 @@ cxx_eval_indirect_ref (const constexpr_c STRIP_NOPS (sub); if (TREE_CODE (sub) == ADDR_EXPR) { + /* For *(const std::type_info *)&_ZTIwhatever return + a constructor with no clearing and __name being the + tinfo name. */ + if (flag_rtti + && VAR_P (TREE_OPERAND (sub, 0)) + && DECL_TINFO_P (TREE_OPERAND (sub, 0)) + && !lval + && TREE_TYPE (t) == const_type_info_type_node) + if (tree ret + = tinfo_for_constant_evaluation (TREE_OPERAND (sub, 0))) + return ret; + gcc_assert (!similar_type_p (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t))); /* DR 1188 says we don't have to deal with this. */ --- gcc/cp/rtti.c.jj 2021-09-15 08:55:37.569497474 +0200 +++ gcc/cp/rtti.c 2021-12-07 17:17:50.943944129 +0100 @@ -1700,4 +1700,39 @@ emit_tinfo_decl (tree decl) return false; } +/* For constant evaluation purposes, return for _ZTI* DECL a CONSTRUCTOR + containing just __name initialized to the tinfo_name string. */ + +tree +tinfo_for_constant_evaluation (tree decl) +{ + gcc_assert (DECL_TINFO_P (decl)); + + tree type = TREE_TYPE (DECL_NAME (decl)); + if (typeinfo_in_lib_p (type)) + ; + else if (involves_incomplete_p (type)) + return NULL_TREE; + + tree field + = next_initializable_field (TYPE_FIELDS (const_type_info_type_node)); + if (field == NULL_TREE) + return NULL_TREE; + field = next_initializable_field (DECL_CHAIN (field)); + if (field == NULL_TREE + || TREE_CODE (TREE_TYPE (field)) != POINTER_TYPE + || TREE_TYPE (TREE_TYPE (field)) == error_mark_node + || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (field))) != char_type_node + || !TYPE_READONLY (TREE_TYPE (TREE_TYPE (field)))) + return NULL_TREE; + + tree str = tinfo_name (type, !TREE_PUBLIC (decl)); + str = build_fold_addr_expr (str); + str = fold_convert (TREE_TYPE (field), str); + + tree init = build_constructor_single (const_type_info_type_node, field, str); + CONSTRUCTOR_NO_CLEARING (init) = true; + return init; +} + #include "gt-cp-rtti.h" --- gcc/testsuite/g++.dg/cpp0x/constexpr-typeid2.C.jj 2021-12-07 19:12:02.233350194 +0100 +++ gcc/testsuite/g++.dg/cpp0x/constexpr-typeid2.C 2021-12-07 19:11:43.071623082 +0100 @@ -0,0 +1,14 @@ +// PR c++/103600 +// { dg-do compile { target c++11 } } + +#include + +struct S { int i; }; +namespace { + struct T { int i; }; +}; +constexpr bool a = &typeid (int) == &typeid (int); +constexpr bool b = &typeid (int) == &typeid (long); +constexpr bool c = &typeid (double) != &typeid (int); +constexpr bool d = &typeid (S) != &typeid (T); +static_assert (a && !b && c && d, "");