Bug 40752 - -Wconversion generates false warnings for operands not larger than target type
Summary: -Wconversion generates false warnings for operands not larger than target type
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.4.0
: P3 normal
Target Milestone: 10.0
Assignee: Jason Merrill
URL: http://gcc.gnu.org/ml/gcc-patches/200...
Keywords: diagnostic
: 41274 50519 52703 61029 67764 91312 (view as bug list)
Depends on:
Blocks:
 
Reported: 2009-07-14 19:17 UTC by photon
Modified: 2022-01-20 03:58 UTC (History)
18 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2009-07-14 22:30:09


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description photon 2009-07-14 19:17:10 UTC
-Wconversion generates false warnings for the following clean code:

{
	char c = 1;
	char c2 = 2;

	// warning: conversion to ‘char’ from ‘int’ may alter its value
	c >>= 1;
	c += (char) 1;
	c += c2;
	c = ~c2;
}
Comment 1 Andrew Pinski 2009-07-14 19:21:09 UTC
Theses are not false warnings:
        c >>= 1;

is really c = (int)c >> 1;

        c += (char) 1;

c =  (int)c + (int)(char)1;

        c += c2;

c = (int)c + (int) c2;


        c = ~c2;

c = ~(int)c2;

Only the last one might be a false warning depending on if c2 is negative or unsigned or not.  The rest are correct because of the way C/C++ define arithmetic operations and automatic promotions.


Comment 2 Manuel López-Ibáñez 2009-07-14 20:55:51 UTC
Andrew, what you say is true, but in this case the warning is not very useful. I'd prefer to warn only when the operator is larger than the target of the assignment. I would like to hear other opinions.
Comment 3 Manuel López-Ibáñez 2009-07-14 20:56:13 UTC
Joseph, could you comment on this?
Comment 4 Ian Lance Taylor 2009-07-14 22:23:50 UTC
Manu, I agree that these warnings are in some sense technically correct but they are not useful.  They can't point to any actual bug.  I guess would be that if every input to the expression has the size of the target of the expression, then the warning should be suppressed.
Comment 5 Manuel López-Ibáñez 2009-07-14 22:30:09 UTC
Then, let's keep this around as an enhancement request. 
Comment 6 photon 2009-07-15 07:50:47 UTC
(In reply to comment #1)
> Theses are not false warnings:
>         c >>= 1;
> 
> is really c = (int)c >> 1;

They are false warnings. The implicit conversion cannot alter the value.
Comment 7 photon 2009-07-15 07:54:46 UTC
(In reply to comment #5)
> Then, let's keep this around as an enhancement request. 
> 

I think this is actually a bug as the specification of the warning is: Warn for implicit conversions that may alter a value. This is not the case here.
Comment 8 Andrew Pinski 2009-07-15 08:13:58 UTC
For:

        c += (char) 1;

The value can change as you have a wrapping if c is CHAR_MAX.

Likewise with:
    c += c2;
Comment 9 Ian Lance Taylor 2009-07-15 14:00:10 UTC
Sure, it can wrap, but -Wconversion is not for wrapping warnings.
Comment 10 jsm-csl@polyomino.org.uk 2009-07-15 14:15:38 UTC
Subject: Re:  -Wconversion: do not warn for operands not larger
 than target type

On Wed, 15 Jul 2009, ian at airs dot com wrote:

> Sure, it can wrap, but -Wconversion is not for wrapping warnings.

It's for warnings about implicit conversions changing a value; the 
arithmetic, in a wider type (deliberately or otherwise), does not wrap, 
but the value gets changed by the implicit conversion back to char.  If 
the user had explicit casts to int in their arithmetic, there could be no 
doubt that the warning is appropriate.

Comment 11 photon 2009-07-15 16:55:48 UTC
(In reply to comment #8)
> For:
> 
>         c += (char) 1;
> 
> The value can change as you have a wrapping if c is CHAR_MAX.
> 
> Likewise with:
>     c += c2;
> 

The value cannot change even if an overflow occurs.

{
	unsigned char c = 0xff;
	c += 1;
	// c is 0 here

	c = 0xff;
	c = (unsigned int)c + 1;
	// c is 0 here
}
Comment 12 Andrew Pinski 2009-07-15 16:58:37 UTC
Except it does alter its value from 0x100 to 0x00 :).
Comment 13 Andrew Pinski 2009-07-15 17:00:03 UTC
Or rather from SCHAR_MAX + 1 to SCHAR_MIN :).  Since it is 0x7F + 1 == (int)0x80.  So we have a negative value now from a positive value.
Comment 14 photon 2009-07-15 18:24:10 UTC
(In reply to comment #13)
> Or rather from SCHAR_MAX + 1 to SCHAR_MIN :).  Since it is 0x7F + 1 ==
> (int)0x80.  So we have a negative value now from a positive value.
> 

This occurs regardless of the implicit conversion. The implicit conversion cannot alter the result. Therefore, the warning is false in this case too.

{
	char c = 0x7f;
	++c;
	// c is 0x80 here

	c = 0x7f;
	c = (int)c + 1;
	// c is 0x80 here
}
Comment 15 Manuel López-Ibáñez 2009-07-23 15:35:39 UTC
Patch: http://gcc.gnu.org/ml/gcc-patches/2009-07/msg01179.html
Comment 16 Manuel López-Ibáñez 2009-09-05 14:05:20 UTC
*** Bug 41274 has been marked as a duplicate of this bug. ***
Comment 17 Manuel López-Ibáñez 2010-06-11 20:22:05 UTC
The patch was rejected but it may be accepted by using a new -Wno-* option to disable these warnings. Perhaps -Wno-conversion-after-promotion?

Suggestions are welcome.
Comment 18 photon 2010-06-12 16:46:24 UTC
(In reply to comment #17)
> The patch was rejected but it may be accepted by using a new -Wno-* option to
> disable these warnings. Perhaps -Wno-conversion-after-promotion?
> 
> Suggestions are welcome.
> 


-Wconversion should be fixed to work as specified. No warning should be generated for the following code:

char c = 2;
// warning: conversion to ‘char’ from ‘int’ may alter its value
c >>= 1;

Comment 19 Manuel López-Ibáñez 2011-09-25 21:12:33 UTC
*** Bug 50519 has been marked as a duplicate of this bug. ***
Comment 20 Manuel López-Ibáñez 2012-03-24 19:27:54 UTC
*** Bug 52703 has been marked as a duplicate of this bug. ***
Comment 21 David Stone 2012-03-24 21:25:08 UTC
Why was this patch rejected, and is there a way to improve it so that obviously safe cases (such as PR52703) are not warned about without having to specify a '-Wno-' option?

Yes, according to the standard (C++03 5/9), calculations done on variables smaller than int are first promoted to int, then the calculation is done, then the value is converted back to the target size. However, C++03 1.8/3, the "as-if rule", states that it the program can't tell the difference, you can do whatever you want (see my answer to a similar question on Stack Overflow here: http://stackoverflow.com/questions/5563000/implicit-type-conversion-rules-in-c-operators/8935697#8935697).

The C++ standard does not require a diagnostic for this, and the apparent behavior is identical. Therefore, there can be no appeals to the C++ standard on the behavior of the warning.

Because this is a purely option warning for which gcc defines the rules, we should define it to be useful. If gcc can prove that all of the values are greater than 0 (for instance, if all of the values are unsigned prior to implicit promotion or are positive integral constant expressions), then there is no possibility of having a negative value. Thanks to signed integer overflow being undefined, there is no risk of creating a negative value that way, either. Therefore, we should not warn. Having to manually say "Turn off stuff that no one could ever possibly want to see" seems like a sure way to make this warning useless.
Comment 22 Wes 2012-05-05 15:09:22 UTC
I agree with David.  My code has many instances of things like
a+=2
where a is a char and this makes -Wconversion useless to me.

It's too bad, since it would really be helpful as I am in the process of changing some data types in the code.

If someone really thinks there should be a warning for this behavior, how about adding a separate
-Wchar-arithmetic
warning which warns on all char arithmetic and see how much people use it.
Comment 23 Manuel López-Ibáñez 2012-05-05 15:30:06 UTC
(In reply to comment #22)
> If someone really thinks there should be a warning for this behavior, how about
> adding a separate
> -Wchar-arithmetic
> warning which warns on all char arithmetic and see how much people use it.

I think adding a new option Wconversion-after-promotion that covers all cases where the conversion occurs to the same type that was originally promoted from would be the most appropriate. I have a feeling that it should not be hard to implement, but I am not sure how, and I have many other things I would like to do first. So, please David, Wes, photon, give it a try. The code is in c-family/c-common.c (conversion_warning).
Comment 24 Mikhail Veltishchev 2012-06-20 14:57:31 UTC
Well, please fix this. My cases are instructions like
unsigned short x = 100;
unsigned short y = 200;
// gives a warning
x += y;
Comment 25 Chengnian Sun 2014-02-10 01:14:12 UTC
Today I encountered a similar case as follows. The conversion warning by gcc is not true as right-shifting an unsigned short decreases the value. 

BTW clang does not emit warnings for this code snippet. 


$: cat s1.c
unsigned short fn(unsigned short a, int right) {
  return a >> right;
}
$: gcc-trunk -c -Wconversion s1.c
s1.c: In function ‘fn’:
s1.c:2:3: warning: conversion to ‘short unsigned int’ from ‘int’ may alter its value [-Wconversion]
   return a >> right;
   ^
$: clang-trunk -c -Wconversion s1.c
$:
Comment 26 Manuel López-Ibáñez 2014-05-01 18:07:15 UTC
*** Bug 61029 has been marked as a duplicate of this bug. ***
Comment 27 hariharan.gcc 2014-09-16 21:07:05 UTC
I encountered a similar problem with -Wconversion. This option is useless if it would warn for cases like

short int i;
i += 5;

I concede Andrew's point about this being technically a place to warn, but in practice, i would like for it to warn only when the target is a "smaller" than any of the inputs.
Comment 28 Marcin Ślusarz 2015-10-07 09:49:14 UTC
*** Bug 67764 has been marked as a duplicate of this bug. ***
Comment 29 Eric Gallager 2018-09-21 01:21:55 UTC
This came up on the gcc mailing list again here: 
https://gcc.gnu.org/ml/gcc/2018-09/msg00076.html
Comment 30 Jason Merrill 2020-01-10 18:52:36 UTC
New patch: https://gcc.gnu.org/ml/gcc-patches/2020-01/msg00624.html
Comment 31 Jason Merrill 2020-01-10 19:20:45 UTC
*** Bug 91312 has been marked as a duplicate of this bug. ***
Comment 32 GCC Commits 2020-01-21 23:41:10 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:c77074d05691053ee7347d9e44ab89b3adb23fb1

commit r10-6126-gc77074d05691053ee7347d9e44ab89b3adb23fb1
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Jan 7 12:20:26 2020 -0500

    PR c++/40752 - useless -Wconversion with short +=.
    
    This is a longstanding issue with lots of duplicates; people are not
    interested in a -Wconversion warning about mychar += 1.  So now that warning
    depends on -Warith-conversion; otherwise we only warn if operands of the
    arithmetic have conversion issues.
    
    	* c.opt (-Warith-conversion): New.
    	* c-warn.c (conversion_warning): Recurse for operands of
    	operators.  Only warn about the whole expression with
    	-Warith-conversion.
Comment 33 Jason Merrill 2020-01-22 01:47:39 UTC
Fixed for GCC 10.
Comment 34 Christophe Lyon 2020-01-22 09:32:46 UTC
(In reply to Jason Merrill from comment #33)
> Fixed for GCC 10.

Hi,

I've noticed that the new tests fail:
c-c++-common/Wconversion-pr40752.c  -Wc++-compat   (test for warnings, line 34)
c-c++-common/Wconversion-pr40752.c  -Wc++-compat   (test for warnings, line 38)
c-c++-common/Wconversion-pr40752.c  -Wc++-compat   (test for warnings, line 40)
c-c++-common/Wconversion-pr40752.c  -Wc++-compat   (test for warnings, line 42)
c-c++-common/Wconversion-pr40752.c  -Wc++-compat  (test for excess errors)
c-c++-common/Wconversion-pr40752a.c  -Wc++-compat   (test for warnings, line 17)
c-c++-common/Wconversion-pr40752a.c  -Wc++-compat   (test for warnings, line 19)
c-c++-common/Wconversion-pr40752a.c  -Wc++-compat   (test for warnings, line 40)
c-c++-common/Wconversion-pr40752a.c  -Wc++-compat   (test for warnings, line 42)


As a side note, the commit r10-6126-gc77074d05691053ee7347d9e44ab89b3adb23fb1 lacks ChangeLog entries for doc and testsuite, and the commit message does not mention the doc and testsuite changes either.
Comment 35 seurer 2020-01-22 16:46:08 UTC
I see even more failures on powerpc64 both BE and LE:

> FAIL: c-c++-common/Wconversion-pr40752.c  -Wc++-compat   (test for warnings, line 34)
> FAIL: c-c++-common/Wconversion-pr40752.c  -Wc++-compat   (test for warnings, line 38)
> FAIL: c-c++-common/Wconversion-pr40752.c  -Wc++-compat   (test for warnings, line 40)
> FAIL: c-c++-common/Wconversion-pr40752.c  -Wc++-compat   (test for warnings, line 42)
> FAIL: c-c++-common/Wconversion-pr40752.c  -Wc++-compat  (test for excess errors)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++14  (test for warnings, line 34)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++14  (test for warnings, line 36)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++14  (test for warnings, line 38)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++14  (test for warnings, line 40)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++14  (test for warnings, line 42)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++17  (test for warnings, line 34)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++17  (test for warnings, line 36)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++17  (test for warnings, line 38)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++17  (test for warnings, line 40)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++17  (test for warnings, line 42)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++2a  (test for warnings, line 34)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++2a  (test for warnings, line 36)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++2a  (test for warnings, line 38)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++2a  (test for warnings, line 40)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++2a  (test for warnings, line 42)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++98  (test for warnings, line 34)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++98  (test for warnings, line 36)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++98  (test for warnings, line 38)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++98  (test for warnings, line 40)
> FAIL: c-c++-common/Wconversion-pr40752.c  -std=gnu++98  (test for warnings, line 42)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -Wc++-compat   (test for warnings, line 17)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -Wc++-compat   (test for warnings, line 19)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -Wc++-compat   (test for warnings, line 40)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -Wc++-compat   (test for warnings, line 42)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++14  (test for warnings, line 12)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++14  (test for warnings, line 17)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++14  (test for warnings, line 19)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++14  (test for warnings, line 36)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++17  (test for warnings, line 12)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++17  (test for warnings, line 17)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++17  (test for warnings, line 19)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++17  (test for warnings, line 36)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++2a  (test for warnings, line 12)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++2a  (test for warnings, line 17)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++2a  (test for warnings, line 19)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++2a  (test for warnings, line 36)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++98  (test for warnings, line 12)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++98  (test for warnings, line 17)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++98  (test for warnings, line 19)
> FAIL: c-c++-common/Wconversion-pr40752a.c  -std=gnu++98  (test for warnings, line 36)
Comment 36 GCC Commits 2020-01-22 22:59:32 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:55b7df8bfb12938e7716445d4e2dc0d2ddf44bac

commit r10-6157-g55b7df8bfb12938e7716445d4e2dc0d2ddf44bac
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jan 22 14:21:06 2020 -0500

    c-family: Fix problems with blender and PPC from PR 40752 patch.
    
    blender in SPEC is built with -funsigned-char, which is also the default on
    PPC, and exposed -Wsign-conversion issues that weren't seen by the x86_64
    testsuite.  In blender we were complaining about operands to an expression
    that we didn't't previously complain about as a whole.  So only check
    operands after we check the whole expression.  Also, to fix the PR 40752
    testcases on -funsigned-char targets, don't consider -Wsign-conversion for
    the second operand of PLUS_EXPR, especially since fold changes
    "x - 5" to "x + (-5)".  And don't use SCHAR_MAX with plain char.
    
    	PR testsuite/93391 - PR 40752 test fails with unsigned plain char.
    	PR c++/40752
    	* c-warn.c (conversion_warning): Check operands only after checking
    	the whole expression.  Don't check second operand of + for sign.
Comment 37 GCC Commits 2020-01-23 16:14:49 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:6d00f052ef209bacdd93f503b0c5fb428cc6c434

commit r10-6181-g6d00f052ef209bacdd93f503b0c5fb428cc6c434
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Jan 23 10:37:18 2020 -0500

    c-family: One more 40752 tweak for unsigned char.
    
    My last patch didn't fix all the failures on unsignd char targets.  We were
    missing one warning because by suppressing -Wsign-conversion for the second
    operand of + we missed an overflow that we want to warn about, and we
    properly don't warn about unsigned / or %.
    
    	PR testsuite/93391 - PR 40752 test fails with unsigned plain char.
    	* c-warn.c (conversion_warning): Change -Wsign-conversion handling.
    	* lib/target-supports.exp (check_effective_target_unsigned_char):
    	New.