From bee50c9b1551d178c1248be3a582ee3d198ef6e8 Mon Sep 17 00:00:00 2001 From: Erick Ochoa Date: Wed, 13 May 2020 11:49:17 +0200 Subject: Successfully understand how incomplete types are compared --- gcc/compare-types.c | 25 ++++++++++++++++++++++++- gcc/compare-types.h | 1 + gcc/ipa-hello-world.c | 3 +++ gcc/testsuite/gcc.dg/ipa/type-playground-02.c | 19 +++++++++++++++++++ gcc/testsuite/gcc.dg/ipa/type-playground-03.c | 25 +++++++++++++++++++++++++ gcc/testsuite/gcc.dg/ipa/type-playground-04.c | 25 +++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/ipa/type-playground-02.c create mode 100644 gcc/testsuite/gcc.dg/ipa/type-playground-03.c create mode 100644 gcc/testsuite/gcc.dg/ipa/type-playground-04.c diff --git a/gcc/compare-types.c b/gcc/compare-types.c index 33021d5feb0..e8a2611eca0 100644 --- a/gcc/compare-types.c +++ b/gcc/compare-types.c @@ -32,6 +32,14 @@ #include "types-inlines.h" #include "name-types.h" +static bool +is_incomplete_type(const_tree a) +{ + gcc_assert(a); + const_tree type_size = TYPE_SIZE(a); + return NULL_TREE == type_size; +} + bool eq_main_variant(const_tree a, const_tree b) { @@ -43,7 +51,7 @@ eq_main_variant(const_tree a, const_tree b) return are_equal; } -static bool +bool eq_canonical_internal(const_tree a, const_tree b) { gcc_assert(a && b); @@ -296,9 +304,24 @@ bool eq_types(const_tree a, const_tree b, const bool force_structural) { gcc_assert(a && b); + // This should be before comparing incomplete types. + // This is not enabled by default, and it is used for + // testing structural equality limitations. if (force_structural) return eq_structural(a, b, force_structural); + // eq_structural (a-incomplete, a-complete) = false + // eq_main_variant(a-incomplete, a-complete) = false + // eq_canonical (a-incomplete, a-complete) = false + // Fallback to eq_identifier only here. + // This should be the only static call to eq_identifier! + const bool is_a_incomplete = is_incomplete_type(a); + const bool is_b_incomplete = is_incomplete_type(b); + const bool compare_incomplete_types = is_a_incomplete || is_b_incomplete; + if (compare_incomplete_types) return eq_identifier(a, b); + + if (eq_main_variant(a, b)) return true; + if (!eq_canonical(a, b)) return false; // optimistic... diff --git a/gcc/compare-types.h b/gcc/compare-types.h index 7f33684e927..2c690fc3081 100644 --- a/gcc/compare-types.h +++ b/gcc/compare-types.h @@ -5,6 +5,7 @@ extern bool eq_identifier(const_tree a, const_tree b); extern bool eq_pointer(const_tree a, const_tree b); extern bool eq_main_variant(const_tree a, const_tree b); extern bool eq_canonical(const_tree a, const_tree b); +extern bool eq_canonical_internal(const_tree a, const_tree b); extern bool eq_type_compare(const_tree a, const_tree b); extern bool eq_type_structural(const_tree a, const_tree b); extern bool eq_types(const_tree a, const_tree b, const bool force_structural = false); diff --git a/gcc/ipa-hello-world.c b/gcc/ipa-hello-world.c index 4f2622cec5f..8aa305f8812 100644 --- a/gcc/ipa-hello-world.c +++ b/gcc/ipa-hello-world.c @@ -43,6 +43,7 @@ enum type_comparison_func_enum { EQ_MAIN_VARIANT, EQ_CANONICAL, EQ_STRUCTURAL, + EQ_CANONICAL_STRICT, EQ_COMPARE, EQ_END }; @@ -52,6 +53,7 @@ static const char* names[type_comparisons] = { "EQ_IDENTIFIER", "EQ_MAIN_VARIANT", "EQ_CANONICAL", + "EQ_CANONICAL_STRICT", "EQ_STRUCTURAL", "EQ_COMPARE" }; @@ -61,6 +63,7 @@ static type_comparison_func_t comparisons[type_comparisons] = { eq_identifier, eq_main_variant, eq_canonical, + eq_canonical_internal, eq_type_structural, eq_type_compare }; diff --git a/gcc/testsuite/gcc.dg/ipa/type-playground-02.c b/gcc/testsuite/gcc.dg/ipa/type-playground-02.c new file mode 100644 index 00000000000..e45f0ae7038 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/type-playground-02.c @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world -ftp-comparison-functions=EQ_MAIN_VARIANT -ftp-types-compared=astruct_s" } */ + +struct astruct_s { + struct astruct_s* a; +}; + +int +main(int argc, char* argv) +{ + struct astruct_s a; +} + +// This is proof that an incomplete type cannot be compared +// via main variant equality. + +// 0,64:astruct_s {0,64:astruct_s {}*;} x 0,0:astruct_s {} = f, +// I am not an expert on regex +/* { dg-final { scan-wpa-ipa-dump "0,64:astruct_s .0,64:astruct_s ..... x 0,0:astruct_s .. = f," "hello-world" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/type-playground-03.c b/gcc/testsuite/gcc.dg/ipa/type-playground-03.c new file mode 100644 index 00000000000..515215aefae --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/type-playground-03.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world -ftp-comparison-functions=EQ_IDENTIFIER -ftp-types-compared=astruct_s" } */ + +struct astruct_s { + struct astruct_s* a; +}; + +int +main(int argc, char* argv) +{ + struct astruct_s a; +} + +// This is proof that an incomplete type **CAN** be compared +// via identifier identity. +// Intuitevely, identifier identity may give false positives (and maybe false negatives too?) +// So, it must be the last resort comparisons. +// +// If we say that an identifier comparison may give false positives and false negatives +// then maybe it would be useful to documents attempts to explicitly produce false positives +// and false negatives to better understand what causes them. + +// 0,64:astruct_s {0,64:astruct_s {}*;} x 0,0:astruct_s {} = t, +// I am not an expert on regex +/* { dg-final { scan-wpa-ipa-dump "0,64:astruct_s .0,64:astruct_s ..... x 0,0:astruct_s .. = t," "hello-world" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/type-playground-04.c b/gcc/testsuite/gcc.dg/ipa/type-playground-04.c new file mode 100644 index 00000000000..ba1f7361c92 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/type-playground-04.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world -ftp-comparison-functions=EQ_CANONICAL -ftp-types-compared=astruct_s" } */ + +struct astruct_s { + struct astruct_s* a; +}; + +int +main(int argc, char* argv) +{ + struct astruct_s a; +} + +// This is proof that an incomplete type **CAN** be compared +// via identifier identity. +// Intuitevely, identifier identity may give false positives (and maybe false negatives too?) +// So, it must be the last resort comparisons. +// +// If we say that an identifier comparison may give false positives and false negatives +// then maybe it would be useful to documents attempts to explicitly produce false positives +// and false negatives to better understand what causes them. + +// 0,64:astruct_s {0,64:astruct_s {}*;} x 0,0:astruct_s {} = f, +// I am not an expert on regex +/* { dg-final { scan-wpa-ipa-dump "0,64:astruct_s .0,64:astruct_s ..... x 0,0:astruct_s .. = f," "hello-world" } } */ -- cgit v1.2.3