From patchwork Fri May 7 16:09:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lamparter X-Patchwork-Id: 1475585 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: 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@gcc.gnu.org; receiver=) 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 RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FcFlR09kMz9sSs for ; Sat, 8 May 2021 02:09:55 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D43D63A0C81D; Fri, 7 May 2021 16:09:47 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from eidolon.nox.tf (eidolon.nox.tf [IPv6:2a07:2ec0:2185::]) by sourceware.org (Postfix) with ESMTPS id E85D23894C1F for ; Fri, 7 May 2021 16:09:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org E85D23894C1F Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=diac24.net Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=equinox@diac24.net Received: from equinox by eidolon.nox.tf with local (Exim 4.94.2) (envelope-from ) id 1lf32r-00D7qi-6h; Fri, 07 May 2021 18:09:41 +0200 From: David Lamparter To: gcc-patches Subject: [PATCH] c: don't drop typedef information in casts Date: Fri, 7 May 2021 18:09:35 +0200 Message-Id: <20210507160935.3080237-1-equinox@diac24.net> X-Mailer: git-send-email 2.26.3 MIME-Version: 1.0 X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) 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: , Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" The TYPE_MAIN_VARIANT() here was, for casts to a typedef'd type name, resulting in all information about the typedef's involvement getting lost. This drops necessary information for warnings and can make them confusing or even misleading. It also makes specialized warnings for unspecified-size system types (pid_t, uid_t, ...) impossible. gcc/c/ChangeLog: 2021-03-09 David Lamparter PR c/99526 * c-typeck.c (build_c_cast): retain (unqualified) typedefs in casts rather than stripping down to basic type. --- gcc/c/c-typeck.c | 39 ++++++++++++++++++++++++++--- gcc/testsuite/gcc.dg/cast-typedef.c | 35 ++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/cast-typedef.c --- Hi GCC hackers, now that gcc 12 is open for development, I'd like to submit this patch for reconsideration. I've already gone through a bit of feedback while the gcc 11 release was happening, cf. here: https://gcc.gnu.org/pipermail/gcc-patches/2021-March/566513.html I've repeated my testing (full bootstrap & make check on x86_64) and found nothing changed. Cheers, -David diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index fdc7bb6125c2..ba6014726a4b 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -5876,6 +5876,7 @@ c_safe_function_type_cast_p (tree t1, tree t2) tree build_c_cast (location_t loc, tree type, tree expr) { + tree res_type, walk_type; tree value; bool int_operands = EXPR_INT_CONST_OPERANDS (expr); @@ -5896,7 +5897,39 @@ build_c_cast (location_t loc, tree type, tree expr) if (objc_is_object_ptr (type) && objc_is_object_ptr (TREE_TYPE (expr))) return build1 (NOP_EXPR, type, expr); + /* Want to keep typedef information, but at the same time we need to strip + qualifiers for a proper rvalue. Unfortunately, we don't know if any + qualifiers on a typedef are part of the typedef or were locally supplied. + So grab the original typedef and use that only if it has no qualifiers. + cf. cast-typedef testcase */ + + res_type = NULL; + + for (walk_type = type; + walk_type && TYPE_NAME (walk_type) + && TREE_CODE (TYPE_NAME (walk_type)) == TYPE_DECL; + walk_type = DECL_ORIGINAL_TYPE (TYPE_NAME (walk_type))) + { + tree walk_unqual, orig_type, orig_decl; + + walk_unqual = build_qualified_type (walk_type, TYPE_UNQUALIFIED); + + orig_decl = lookup_name (TYPE_IDENTIFIER (walk_type)); + if (!orig_decl || TREE_CODE (orig_decl) != TYPE_DECL) + continue; + orig_type = TREE_TYPE (orig_decl); + + if (walk_unqual == orig_type) + { + res_type = walk_unqual; + break; + } + } + type = TYPE_MAIN_VARIANT (type); + if (!res_type) + res_type = type; + gcc_assert (TYPE_MAIN_VARIANT (res_type) == type); if (TREE_CODE (type) == ARRAY_TYPE) { @@ -5924,7 +5957,7 @@ build_c_cast (location_t loc, tree type, tree expr) "ISO C forbids casting nonscalar to the same type"); /* Convert to remove any qualifiers from VALUE's type. */ - value = convert (type, value); + value = convert (res_type, value); } else if (TREE_CODE (type) == UNION_TYPE) { @@ -6078,7 +6111,7 @@ build_c_cast (location_t loc, tree type, tree expr) " from %qT to %qT", otype, type); ovalue = value; - value = convert (type, value); + value = convert (res_type, value); /* Ignore any integer overflow caused by the cast. */ if (TREE_CODE (value) == INTEGER_CST && !FLOAT_TYPE_P (otype)) @@ -6114,7 +6147,7 @@ build_c_cast (location_t loc, tree type, tree expr) && INTEGRAL_TYPE_P (TREE_TYPE (expr))) || TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == COMPLEX_CST))) - value = build1 (NOP_EXPR, type, value); + value = build1 (NOP_EXPR, res_type, value); /* If the expression has integer operands and so can occur in an unevaluated part of an integer constant expression, ensure the diff --git a/gcc/testsuite/gcc.dg/cast-typedef.c b/gcc/testsuite/gcc.dg/cast-typedef.c new file mode 100644 index 000000000000..3058e5a0b190 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cast-typedef.c @@ -0,0 +1,35 @@ +/* Test cast <> typedef interactions */ +/* Origin: David Lamparter */ +/* { dg-do compile } */ +/* { dg-options "-Wconversion" } */ + +typedef int typedefname; +typedef volatile int qual1; +typedef volatile typedefname qual2; + +extern int val; +extern void f2(unsigned char arg); + +void +f (void) +{ + /* -Wconversion just used to print out the actual type */ + + f2 ((typedefname) val); /* { dg-warning "typedefname" } */ + f2 ((volatile typedefname) val); /* { dg-warning "typedefname" } */ + f2 ((qual1) val); /* { dg-warning "int" } */ + f2 ((qual2) val); /* { dg-warning "typedefname" } */ + + /* { dg-bogus "volatile" "qualifiers should be stripped" { target { "*-*-*" } } 19 } */ + /* { dg-bogus "volatile" "qualifiers should be stripped" { target { "*-*-*" } } 20 } */ + /* { dg-bogus "volatile" "qualifiers should be stripped" { target { "*-*-*" } } 21 } */ + + /* { dg-bogus "qual1" "typedef with qualifier should not be used" { target { "*-*-*" } } 20 } */ + /* { dg-bogus "qual2" "typedef with qualifier should not be used" { target { "*-*-*" } } 21 } */ + + /* shadow "typedefname" & make sure it's not used */ + typedef short typedefname; + f2 ((qual2) val); /* { dg-warning "int" } */ + + /* { dg-bogus "typedefname" "retaining a shadowed typedef would be confusing" { target { "*-*-*" } } 32 } */ +}