Message ID | 20210310012815.3797974-1-equinox@diac24.net |
---|---|
State | New |
Headers | show |
Series | c: don't drop typedef information in casts | expand |
On Wed, Mar 10, 2021 at 02:28:15AM +0100, David Lamparter wrote: > 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. I hope I didn't produce any glaring SNAFUs in submitting this patch, I haven't previously contributed to GCC. I've run the testsuite on x86_64 and seen no breakage from this. The delta (compared to this run: https://gcc.gnu.org/pipermail/gcc-testresults/2021-March/662078.html) is: $ diff -U0 /tmp/before.sum /tmp/after.sum --- /tmp/before.sum 2021-03-09 22:48:26.989146223 +0100 +++ /tmp/after.sum 2021-03-10 01:46:46.209935875 +0100 @@ -89 +89,2 @@ -FAIL: g++.old-deja/g++.other/virtual2.C -std=c++2a execution test +FAIL: g++.dg/modules/xtreme-header-5_c.C -std=c++17 (internal compiler error) +FAIL: g++.dg/modules/xtreme-header-5_c.C -std=c++17 (test for excess errors) None of which seems to be related to the patch. (The 2 new fails are "xtreme-header-5_c.C:3:30: internal compiler error: same canonical type node for different types 'void' and 'std::__void_t<typename _Func::is_transparent>'") Cheers, David
On 3/9/21 6:46 PM, David Lamparter wrote: > On Wed, Mar 10, 2021 at 02:28:15AM +0100, David Lamparter wrote: >> 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. > > I hope I didn't produce any glaring SNAFUs in submitting this patch, I > haven't previously contributed to GCC. > > I've run the testsuite on x86_64 and seen no breakage from this. The > delta (compared to this run: > https://gcc.gnu.org/pipermail/gcc-testresults/2021-March/662078.html) is: Thanks for the patch and for clarifying how you tested the change! > > $ diff -U0 /tmp/before.sum /tmp/after.sum > --- /tmp/before.sum 2021-03-09 22:48:26.989146223 +0100 > +++ /tmp/after.sum 2021-03-10 01:46:46.209935875 +0100 > @@ -89 +89,2 @@ > -FAIL: g++.old-deja/g++.other/virtual2.C -std=c++2a execution test > +FAIL: g++.dg/modules/xtreme-header-5_c.C -std=c++17 (internal compiler error) > +FAIL: g++.dg/modules/xtreme-header-5_c.C -std=c++17 (test for excess errors) > > None of which seems to be related to the patch. (The 2 new fails are > "xtreme-header-5_c.C:3:30: internal compiler error: same canonical type node for different types 'void' and 'std::__void_t<typename _Func::is_transparent>'") Yes, these are unrelated C++ failures. A few comments on the patch. It took me a bit at first to see the problem it tries to solve. I see the improvement but I'm not sure it's quite correct, or what in the test verifies the desired outcome. The warning on line 12 before the change is: cast-5.c:13:7: warning: conversion from ‘int’ to ‘unsigned char’ may change value [-Wconversion] and after: cast-5.c:13:7: warning: conversion from ‘qualtypedefname’ {aka ‘int’} to ‘unsigned char’ may change value [-Wconversion] There's no volatile, so the test passes either way. More important, though, qualtypedefname is a typedef for volatile int but the AKA type says it's int. So the new output doesn't seem right. In any case, the test should fail without the patch. Using dg-warning to look for both the expected typedef name and the AKA type would seem like a better to do that than dg-bogus. As an aside, although it's not a requirement, it's helpful to open a bug first, before submitting a patch. It's more overhead but it gives the problem more visibility, lets us track regressions and related bugs, and help decide what fixes should be backported. In this case, the same improvement can also be made to the C++ front end and having a bug might help highlight that. Finally, GCC is in a regression-fixing stage now, so unless this problem is one (having a bug report would also help determine that), this patch will likely need to wait until general development reopens sometime in May. In any case, it's a maintainer's call to approve it. Thanks again! Martin
On Wed, Mar 10, 2021 at 10:01:39AM -0700, Martin Sebor wrote: > On 3/9/21 6:46 PM, David Lamparter wrote: > > On Wed, Mar 10, 2021 at 02:28:15AM +0100, David Lamparter wrote: > >> 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. > A few comments on the patch. It took me a bit at first to see > the problem it tries to solve. I see the improvement but I'm not > sure it's quite correct, or what in the test verifies the desired > outcome. I've tried making it a bit more clear in a bug opened as requested: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99526 > The warning on line 12 before the change is: > > cast-5.c:13:7: warning: conversion from ‘int’ to ‘unsigned char’ may > change value [-Wconversion] > > and after: > > cast-5.c:13:7: warning: conversion from ‘qualtypedefname’ {aka ‘int’} to > ‘unsigned char’ may change value [-Wconversion] > > There's no volatile, so the test passes either way. More important, > though, qualtypedefname is a typedef for volatile int but the AKA > type says it's int. So the new output doesn't seem right. The new output is actually correct since casts produce rvalues. I was trying to put together a test for that to make sure the volatile is NOT there (in an earlier version it was, and that actually broke things.) That said, I seem to have b0rked the test anyway since on closer look it says: "ERROR: gcc.dg/cast-5.c: unknown dg option: */ for */" (I had missed that since I looked for PASS/FAIL...) - so need to fix that anyway. > In any case, the test should fail without the patch. Using > dg-warning to look for both the expected typedef name and the AKA > type would seem like a better to do that than dg-bogus. Thanks for the input, I need to look a bit more at how this whole stuff works. Going to poke it a bit more... Also, in seeing your response re. the volatile, it occured to me that stripping qualifiers on a typedef and still calling it the typedef is unhelpful. Ideally, my goal is: typedef int i; typedef const int ci; typeof((i)x) = i typeof((ci)x) = int (<-- w/ my patch = ci; this is confusing) typeof((const i)x) = i (Without my patch, all 3 typeofs come out as plain int.) So I think I need to somehow check whether the qualifiers are part of the typedef or not; essentially peel typedefs until it's one without qualifiers. > As an aside, although it's not a requirement, it's helpful to open > a bug first, before submitting a patch. [...] Linked above :) > Finally, GCC is in a regression-fixing stage now, so unless this > problem is one (having a bug report would also help determine that), > this patch will likely need to wait until general development > reopens sometime in May. In any case, it's a maintainer's call > to approve it. Ah, I hadn't seen that. My bad. Thanks for the input! -David
On Wed, Mar 10, 2021 at 08:02:16PM +0100, David Lamparter wrote: > Also, in seeing your response re. the volatile, it occured to me that > stripping qualifiers on a typedef and still calling it the typedef is > unhelpful. Ideally, my goal is: > > typedef int i; > typedef const int ci; > typeof((i)x) = i > typeof((ci)x) = int (<-- w/ my patch = ci; this is confusing) Clarification: with the current patch, the type of (ci)x is *called* "ci", but doesn't actually have the const qualifier. That's the confusing part. The const (or volatile) is stripped off the typedef in the added build_qualified_type() call, but that now-different type is still referred to as "ci"... > typeof((const i)x) = i
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 4e6d369c4c9c..0f67753be4d7 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -5816,6 +5816,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; tree value; bool int_operands = EXPR_INT_CONST_OPERANDS (expr); @@ -5836,7 +5837,9 @@ 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); - type = TYPE_MAIN_VARIANT (type); + /* rvalue - retain typedefs w/o qualifier, but use actual type for checks */ + res_type = build_qualified_type (type, TYPE_UNQUALIFIED); + type = TYPE_MAIN_VARIANT (res_type); if (TREE_CODE (type) == ARRAY_TYPE) { @@ -5864,7 +5867,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) { @@ -6018,7 +6021,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)) @@ -6054,7 +6057,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-5.c b/gcc/testsuite/gcc.dg/cast-5.c new file mode 100644 index 000000000000..dcd9b290653d --- /dev/null +++ b/gcc/testsuite/gcc.dg/cast-5.c @@ -0,0 +1,19 @@ +/* Test cast <> typedef interactions */ +/* Origin: David Lamparter <equinox@diac24.net> */ +/* { dg-do compile } */ +/* { dg-options "-Wconversion" } */ + +typedef int typedefname; +typedef volatile int qualtypedefname; + +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 ((qualtypedefname) val); /* { dg-warning "qualtypedefname" } */ /* { dg-bogus "volatile" } */ +}