summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErick Ochoa <erick.ochoa@theobroma-systems.com>2020-05-13 11:49:17 +0200
committerErick Ochoa <erick.ochoa@theobroma-systems.com>2020-05-14 14:46:21 +0200
commitbee50c9b1551d178c1248be3a582ee3d198ef6e8 (patch)
treebe8c69c90c602b9a8098454522be3c835aa98f22
parentf801efe2ec0080ce1e1677294326f0836455d413 (diff)
Successfully understand how incomplete types are compared
-rw-r--r--gcc/compare-types.c25
-rw-r--r--gcc/compare-types.h1
-rw-r--r--gcc/ipa-hello-world.c3
-rw-r--r--gcc/testsuite/gcc.dg/ipa/type-playground-02.c19
-rw-r--r--gcc/testsuite/gcc.dg/ipa/type-playground-03.c25
-rw-r--r--gcc/testsuite/gcc.dg/ipa/type-playground-04.c25
6 files changed, 97 insertions, 1 deletions
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" } } */