diff options
author | Xi Ruoyao <xry111@mengyan1223.wang> | 2021-07-10 17:46:29 +0800 |
---|---|---|
committer | Xi Ruoyao <xry111@mengyan1223.wang> | 2021-07-30 15:43:38 +0800 |
commit | 291416d3782e12e983483a3f7b2154a3dbfc9e1f (patch) | |
tree | 5c434a2b48ab252e5f65bcfeb7b1e028aa839353 | |
parent | e41ba804ba5f5ca433e09238d561b1b4c8b10985 (diff) | |
download | gcc-291416d3782e12e983483a3f7b2154a3dbfc9e1f.zip gcc-291416d3782e12e983483a3f7b2154a3dbfc9e1f.tar.gz gcc-291416d3782e12e983483a3f7b2154a3dbfc9e1f.tar.bz2 |
ipa-devirt: check precision mismatch of enum values [PR101396]
We are comparing enum values (in wide_int) to check ODR violation.
However, if we compare two wide_int values with different precision,
we'll trigger an assert, leading to ICE. With enum-base introduced
in C++11, it's easy to sink into this situation.
To fix the issue, we need to explicitly check this kind of mismatch,
and emit a proper warning message if there is such one.
gcc/
PR ipa/101396
* ipa-devirt.c (ipa_odr_read_section): Compare the precision of
enum values, and emit a warning if they mismatch.
gcc/testsuite/
PR ipa/101396
* g++.dg/lto/pr101396_0.C: New test.
* g++.dg/lto/pr101396_1.C: New test.
-rw-r--r-- | gcc/ipa-devirt.c | 9 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lto/pr101396_0.C | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lto/pr101396_1.C | 10 |
3 files changed, 31 insertions, 0 deletions
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index 8cd1100..8deec75 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -4193,6 +4193,8 @@ ipa_odr_read_section (struct lto_file_decl_data *file_data, const char *data, if (do_warning != -1 || j >= this_enum.vals.length ()) continue; if (strcmp (id, this_enum.vals[j].name) + || (val.get_precision() != + this_enum.vals[j].val.get_precision()) || val != this_enum.vals[j].val) { warn_name = xstrdup (id); @@ -4260,6 +4262,13 @@ ipa_odr_read_section (struct lto_file_decl_data *file_data, const char *data, "name %qs differs from name %qs defined" " in another translation unit", this_enum.vals[j].name, warn_name); + else if (this_enum.vals[j].val.get_precision() != + warn_value.get_precision()) + inform (this_enum.vals[j].locus, + "name %qs is defined as %u-bit while another " + "translation unit defines it as %u-bit", + warn_name, this_enum.vals[j].val.get_precision(), + warn_value.get_precision()); /* FIXME: In case there is easy way to print wide_ints, perhaps we could do it here instead of overflow check. */ else if (wi::fits_shwi_p (this_enum.vals[j].val) diff --git a/gcc/testsuite/g++.dg/lto/pr101396_0.C b/gcc/testsuite/g++.dg/lto/pr101396_0.C new file mode 100644 index 0000000..b7a2947 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr101396_0.C @@ -0,0 +1,12 @@ +/* { dg-lto-do link } */ + +enum A : __UINT32_TYPE__ { // { dg-lto-warning "6: type 'A' violates the C\\+\\+ One Definition Rule" } + a, // { dg-lto-note "3: name 'a' is defined as 32-bit while another translation unit defines it as 64-bit" } + b, + c +}; + +int main() +{ + return (int) A::a; +} diff --git a/gcc/testsuite/g++.dg/lto/pr101396_1.C b/gcc/testsuite/g++.dg/lto/pr101396_1.C new file mode 100644 index 0000000..a6d032d --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr101396_1.C @@ -0,0 +1,10 @@ +enum A : __UINT64_TYPE__ { // { dg-lto-note "6: an enum with different value name is defined in another translation unit" } + a, // { dg-lto-note "3: mismatching definition" } + b, + c +}; + +int f(enum A x) +{ + return (int) x; +} |