aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/alias.c34
-rw-r--r--gcc/testsuite/g++.dg/torture/pr93246.C31
2 files changed, 61 insertions, 4 deletions
diff --git a/gcc/alias.c b/gcc/alias.c
index 336af4e..9629b5a 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -1191,15 +1191,14 @@ record_alias_subset (alias_set_type superset, alias_set_type subset)
}
}
-/* Record that component types of TYPE, if any, are part of that type for
+/* Record that component types of TYPE, if any, are part of SUPERSET for
aliasing purposes. For record types, we only record component types
for fields that are not marked non-addressable. For array types, we
only record the component type if it is not marked non-aliased. */
void
-record_component_aliases (tree type)
+record_component_aliases (tree type, alias_set_type superset)
{
- alias_set_type superset = get_alias_set (type);
tree field;
if (superset == 0)
@@ -1253,7 +1252,21 @@ record_component_aliases (tree type)
== get_alias_set (TREE_TYPE (field)));
}
- record_alias_subset (superset, get_alias_set (t));
+ alias_set_type set = get_alias_set (t);
+ record_alias_subset (superset, set);
+ /* If the field has alias-set zero make sure to still record
+ any componets of it. This makes sure that for
+ struct A {
+ struct B {
+ int i;
+ char c[4];
+ } b;
+ };
+ in C++ even though 'B' has alias-set zero because
+ TYPE_TYPELESS_STORAGE is set, 'A' has the alias-set of
+ 'int' as subset. */
+ if (set == 0)
+ record_component_aliases (t, superset);
}
}
break;
@@ -1270,6 +1283,19 @@ record_component_aliases (tree type)
}
}
+/* Record that component types of TYPE, if any, are part of that type for
+ aliasing purposes. For record types, we only record component types
+ for fields that are not marked non-addressable. For array types, we
+ only record the component type if it is not marked non-aliased. */
+
+void
+record_component_aliases (tree type)
+{
+ alias_set_type superset = get_alias_set (type);
+ record_component_aliases (type, superset);
+}
+
+
/* Allocate an alias set for use in storing and reading from the varargs
spill area. */
diff --git a/gcc/testsuite/g++.dg/torture/pr93246.C b/gcc/testsuite/g++.dg/torture/pr93246.C
new file mode 100644
index 0000000..4c52344
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr93246.C
@@ -0,0 +1,31 @@
+// { dg-do run }
+// { dg-additional-options "-fstrict-aliasing" }
+
+template <typename = void> struct Optional {
+ auto is_present() const { const bool &p = inner.present; return p; }
+ auto set_present() { if (not is_present()) inner.present = true; }
+ struct InnerType {
+ bool present = false;
+ char padding[1] = {0};
+ };
+ using inner_t = InnerType;
+ inner_t inner = {};
+};
+
+template <typename WrappedType> struct Wrapper {
+ auto operator-> () { return value; }
+ WrappedType *value;
+};
+
+void __attribute__((noipa)) foo(Optional<>& x) {}
+
+int main()
+{
+ Optional<> buf{};
+ foo(buf);
+ Wrapper<Optional<>> wo = {&buf};
+ wo->set_present();
+ auto x = wo->is_present();
+ if (!x)
+ __builtin_abort ();
+}