diff options
-rw-r--r-- | gcc/alias.c | 34 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/torture/pr93246.C | 31 |
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 (); +} |