5.13.5.1.3. Prepare alias set
However, the entry point for creating alias set is get_alias_set below. Both node of type and node of declaration can claim for alias analysis, but declaration’s alias set is determined by the alias set of underlying type. Condition at line 467 selects out the node of declaration. In C++ front-end, hook get_alias_set at line 475 points to cxx_get_alias_set . However, the function majorly handles node of type definition, we leave the function for the moment.
449 HOST_WIDE_INT
450 get_alias_set (tree t) in alias.c
451 {
452 HOST_WIDE_INT set;
453
454 /* If we're not doing any alias analysis, just assume everything
455 aliases everything else. Also return 0 if this or its type is
456 an error. */
457 if (! flag_strict_aliasing || t == error_mark_node
458 || (! TYPE_P (t)
459 && (TREE_TYPE (t) == 0 || TREE_TYPE (t) == error_mark_node)))
460 return 0;
461
462 /* We can be passed either an expression or a type. This and the
463 language-specific routine may make mutually-recursive calls to each other
464 to figure out what to do. At each juncture, we see if this is a tree
465 that the language may need to handle specially. First handle things that
466 aren't types. */
467 if (! TYPE_P (t))
468 {
469 tree inner = t;
470 tree placeholder_ptr = 0;
471
472 /* Remove any nops, then give the language a chance to do
473 something with this tree before we look at it. */
474 STRIP_NOPS (t);
475 set = (*lang_hooks . get_alias_set ) (t);
476 if (set != -1)
477 return set;
478
479 /* First see if the actual object referenced is an INDIRECT_REF from a
480 restrict-qualified pointer or a "void *". Replace
481 PLACEHOLDER_EXPRs. */
482 while (TREE_CODE (inner) == PLACEHOLDER_EXPR
483 || handled_component_p (inner))
484 {
485 if (TREE_CODE (inner) == PLACEHOLDER_EXPR)
486 inner = find_placeholder (inner, &placeholder_ptr);
487 else
488 inner = TREE_OPERAND (inner, 0);
489
490 STRIP_NOPS (inner);
491 }
492
493 /* Check for accesses through restrict-qualified pointers. */
494 if (TREE_CODE (inner) == INDIRECT_REF)
495 {
496 tree decl = find_base_decl (TREE_OPERAND (inner, 0));
497
498 if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
499 {
500 /* If we haven't computed the actual alias set, do it now. */
501 if (DECL_POINTER_ALIAS_SET (decl) == -2)
502 {
503 tree pointed_to_type = TREE_TYPE (TREE_TYPE (decl));
504
505 /* No two restricted pointers can point at the same thing.
506 However, a restricted pointer can point at the same thing
507 as an unrestricted pointer, if that unrestricted pointer
508 is based on the restricted pointer. So, we make the
509 alias set for the restricted pointer a subset of the
510 alias set for the type pointed to by the type of the
511 decl. */
512 HOST_WIDE_INT pointed_to_alias_set
513 = get_alias_set (pointed_to_type);
514
515 if (pointed_to_alias_set == 0)
516 /* It's not legal to make a subset of alias set zero. */
517 DECL_POINTER_ALIAS_SET (decl) = 0;
518 else if (AGGREGATE_TYPE_P (pointed_to_type))
519 /* For an aggregate, we must treat the restricted
520 pointer the same as an ordinary pointer. If we
521 were to make the type pointed to by the
522 restricted pointer a subset of the pointed-to
523 type, then we would believe that other subsets
524 of the pointed-to type (such as fields of that
525 type) do not conflict with the type pointed to
526 by the restricted pointer. */
527 DECL_POINTER_ALIAS_SET (decl)
528 = pointed_to_alias_set;
529 else
530 {
531 DECL_POINTER_ALIAS_SET (decl) = new_alias_set ();
532 record_alias_subset (pointed_to_alias_set,
533 DECL_POINTER_ALIAS_SET (decl));
534 }
535 }
536
537 /* We use the alias set indicated in the declaration. */
538 return DECL_POINTER_ALIAS_SET (decl);
539 }
540
541 /* If we have an INDIRECT_REF via a void pointer, we don't
542 know anything about what that might alias. */
543 else if (TREE_CODE (TREE_TYPE (inner)) == VOID_TYPE)
544 return 0;
545 }
546
547 /* Otherwise, pick up the outermost object that we could have a pointer
548 to, processing conversion and PLACEHOLDER_EXPR as above. */
549 placeholder_ptr = 0;
550 while (TREE_CODE (t) == PLACEHOLDER_EXPR
551 || (handled_component_p (t) && ! can_address_p (t)))
552 {
553 if (TREE_CODE (t) == PLACEHOLDER_EXPR)
554 t = find_placeholder (t, &placeholder_ptr);
555 else
556 t = TREE_OPERAND (t, 0);
557
558 STRIP_NOPS (t);
559 }
560
561 /* If we've already determined the alias set for a decl, just return
562 it. This is necessary for C++ anonymous unions, whose component
563 variables don't look like union members (boo!). */
564 if (TREE_CODE (t) == VAR_DECL
565 && DECL_RTL_SET_P (t) && GET_CODE (DECL_RTL (t)) == MEM)
566 return MEM_ALIAS_SET (DECL_RTL (t));
567
568 /* Now all we care about is the type. */
569 t = TREE_TYPE (t);
570 }
Above node of INDIRECT_REF in C++ language stands for an expression for a pointer or reference (for example, char *p;), clearly the alias set of the object referred is what we want. Thus find_base_decl finds the DECL on which this expression is based (For example, in `a[i]' this would be `a'). And if there is no such DECL, or a unique DECL cannot be determined, NULL_TREE is returned.
361 static tree
362 find_base_decl (tree t) in alias.c
363 {
364 tree d0, d1, d2;
365
366 if (t == 0 || t == error_mark_node || ! POINTER_TYPE_P (TREE_TYPE (t)))
367 return 0;
368
369 /* If this is a declaration, return it. */
370 if (TREE_CODE_CLASS (TREE_CODE (t)) == 'd')
371 return t;
372
373 /* Handle general expressions. It would be nice to deal with
374 COMPONENT_REFs here. If we could tell that `a' and `b' were the
375 same, then `a->f' and `b->f' are also the same. */
376 switch (TREE_CODE_CLASS (TREE_CODE (t)))
377 {
378 case '1':
379 return find_base_decl (TREE_OPERAND (t, 0));
380
381 case '2':
382 /* Return 0 if found in neither or both are the same. */
383 d0 = find_base_decl (TREE_OPERAND (t, 0));
384 d1 = find_base_decl (TREE_OPERAND (t, 1));
385 if (d0 == d1)
386 return d0;
387 else if (d0 == 0)
388 return d1;
389 else if (d1 == 0)
390 return d0;
391 else
392 return 0;
393
394 case '3':
395 d0 = find_base_decl (TREE_OPERAND (t, 0));
396 d1 = find_base_decl (TREE_OPERAND (t, 1));
397 d2 = find_base_decl (TREE_OPERAND (t, 2));
398
399 /* Set any nonzero values from the last, then from the first. */
400 if (d1 == 0) d1 = d2;
401 if (d0 == 0) d0 = d1;
402 if (d1 == 0) d1 = d0;
403 if (d2 == 0) d2 = d1;
404
405 /* At this point all are nonzero or all are zero. If all three are the
406 same, return it. Otherwise, return zero. */
407 return (d0 == d1 && d1 == d2) ? d0 : 0;
408
409 default :
410 return 0;
411 }
412 }
If we find the based DECL, back get_alias_set at line 498, if DECL_POINTER_ALIAS_SET doesn’t set with -1, DECL_POINTER_ALIAS_SET_KNOWN_P is true (-1 means the alias set for the declaration has not been yet computed). Further if DECL_POINTER_ALIAS_SET returns -2, it indicates that we need to make a unique alias set for this pointer (it is only applied to case of using GNU extension keyword restrict to restrict pointer alias, see c_apply_type_quals_to_decl ). It needs some special treatement.
The restrict pointer qualifier can be applied to a data pointer to indicate that, during the scope of that pointer declaration, all data accessed through it will be accessed only through that pointer but not through any other pointer. The __restrict__ keyword thus enables the compiler to perform certain optimizations based on the premise that a given object cannot be changed through another pointer. For example, declaration “int f ( int * restrict x, int * restrict y)” means changing the content of address pointed by pointer x can only via this pointer. So it is safe to compute alias set as below.
Then at line 503 in get_alias_set , here decl is the based DECL, it must have type of indirect type (pointer or reference), so pointed_to_type holds the type the indirect type refers to. Next get_alias_set invoked at line 512 recursively works out the alias set for the type. So at line 518, if pointed_to_type points to aggregate type, the alias set for this type should have been computed in the invocation at line 512, uses this alias set for the pointer (computing alias set for aggregate type is done by record_component_aliases , we will see it soon).
While if the pointer is not of aggregate type, it enters block at line 529 in get_alias_set , to be conservative but correct, combines all declarations pointed by pointer of this type into the same tree of alias set rooted by the pointer type (but note that the alias set of decl aliases nothing but it self, since it is delcared as “restrict”).
Then if it comes at line 549 in get_alias_set , because either inner is not INDIRECT_REF or its alias set is unknown. For the case, we get the alias set from its type.
Node of WITH_RECORD_EXPR and PLACEHOLDER_EXPR are used in languages that have types where some field in an object of the type contains a value that is used in the computation of another field's offset or size and/or the size of the type. The positions and/or sizes of fields can vary from object to object of the same type or even for one and the same object within its scope. Record types with discriminants in Ada or schema types in Pascal are examples of such types. For C++ front-end, we don’t need worry about these nodes.
get_alias_set (continue)
572 /* Variant qualifiers don't affect the alias set, so get the main
573 variant. If this is a type with a known alias set, return it. */
574 t = TYPE_MAIN_VARIANT (t);
575 if (TYPE_ALIAS_SET_KNOWN_P (t))
576 return TYPE_ALIAS_SET (t);
577
578 /* See if the language has special handling for this type. */
579 set = (*lang_hooks . get_alias_set ) (t);
580 if (set != -1)
581 return set;
582
583 /* There are no objects of FUNCTION_TYPE, so there's no point in
584 using up an alias set for them. (There are, of course, pointers
585 and references to functions, but that's different.) */
586 else if (TREE_CODE (t) == FUNCTION_TYPE)
587 set = 0;
588
589 /* Unless the language specifies otherwise, let vector types alias
590 their components. This avoids some nasty type punning issues in
591 normal usage. And indeed lets vectors be treated more like an
592 array slice. */
593 else if (TREE_CODE (t) == VECTOR_TYPE)
594 set = get_alias_set (TREE_TYPE (t));
595
596 else
597 /* Otherwise make a new alias set for this type. */
598 set = new_alias_set ();
599
600 TYPE_ALIAS_SET (t) = set;
601
602 /* If this is an aggregate type, we must record any component aliasing
603 information. */
604 if (AGGREGATE_TYPE_P (t) || TREE_CODE (t) == COMPLEX_TYPE)
605 record_component_aliases (t);
606
607 return set;
608 }
First, it sees if there is any suggestion from the language. Hook get_alias_set refers to cxx_get_alias_set below for C++.
Recall that for non-POD class, CLASSTYPE_AS_BASE is an RECORD_TYPE node with virtual bases stripped and its TYPE_CONTEXT refers to the RECORD_TYPE of the class, so predicate “CLASSTYPE_AS_BASE (TYPE_CONTEXT (t)) == t” is true if t is the node of CLASSTYPE_AS_BASE of non-POD class (while for POD class, CLASSTYPE_AS_BASE is the RECORD_TYPE of the class, so the mentioned predicate is false).
So condition at line 295 tells that t is enclosed within a class, and it is the base part of enclosing class.
292 static HOST_WIDE_INT
293 cxx_get_alias_set (tree t) in cp-lang.c
294 {
295 if (TREE_CODE (t) == RECORD_TYPE
296 && TYPE_CONTEXT (t) && CLASS_TYPE_P (TYPE_CONTEXT (t))
297 && CLASSTYPE_AS_BASE (TYPE_CONTEXT (t)) == t)
298 /* The base variant of a type must be in the same alias set as the
299 complete type. */
300 return get_alias_set (TYPE_CONTEXT (t));
301
302 if (/* It's not yet safe to use alias sets for some classes in C++. */
303 !ok_to_generate_alias_set_for_type (t)
304 /* Nor is it safe to use alias sets for pointers-to-member
305 functions, due to the fact that there may be more than one
306 RECORD_TYPE type corresponding to the same pointer-to-member
307 type. */
308 || TYPE_PTRMEMFUNC_P (t))
309 return 0;
310
311 return c_common_get_alias_set (t);
312 }
Then for the cases come at line 302, ok_to_generate_alias_set_for_type checks if the type is safe for aliasing.
First, class having virtual base is unsafe for aliasing. For example :
class A { ... };
class B : public virtual A { ... } ;
class C : public virtual A { ... } ;
class D : public B, C { ... } ;
Though D derives from B, in D the base B has different layout than class B even if B is empty class. Remember predicate CLASS_TYPE_P at line 250 is false for CLASSTYPE_AS_BASE of non-POD class.
Similarly, if a class contains a field of another class containing virtual base, it is unsafe to alias this type (both cases considered as may-alias).
239 static bool
240 ok_to_generate_alias_set_for_type (tree t) in cp-lang.c
241 {
242 if (TYPE_PTRMEMFUNC_P (t))
243 return true;
244 if (AGGREGATE_TYPE_P (t))
245 {
246 if ((TREE_CODE (t) == RECORD_TYPE) || (TREE_CODE (t) == UNION_TYPE))
247 {
248 tree fields;
249 /* Backend-created structs are safe. */
250 if (! CLASS_TYPE_P (t))
251 return true;
252 /* PODs are safe. */
253 if (! CLASSTYPE_NON_POD_P(t))
254 return true;
255 /* Classes with virtual baseclasses are not. */
256 if (TYPE_USES_VIRTUAL_BASECLASSES (t))
257 return false;
258 /* Recursively check the base classes. */
259 if (TYPE_BINFO (t) != NULL && TYPE_BINFO_BASETYPES (t) != NULL)
260 {
261 int i;
262 for (i = 0; i < TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (t)); i++)
263 {
264 tree binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i);
265 if (!ok_to_generate_alias_set_for_type (BINFO_TYPE (binfo)))
266 return false;
267 }
268 }
269 /* Check all the fields. */
270 for (fields = TYPE_FIELDS (t); fields; fields = TREE_CHAIN (fields))
271 {
272 if (TREE_CODE (fields) != FIELD_DECL)
273 continue ;
274 if (! ok_to_generate_alias_set_for_type (TREE_TYPE (fields)))
275 return false;
276 }
277 return true;
278 }
279 else if (TREE_CODE (t) == ARRAY_TYPE)
280 return ok_to_generate_alias_set_for_type (TREE_TYPE (t));
281 else
282 /* This should never happen, we dealt with all the aggregate
283 types that can appear in C++ above. */
284 abort ();
285 }
286 else
287 return true;
288 }
Further considering following example:
extern "C" int printf(const char *,...);
class A {
protected : int i ;
public :
void f1 () { printf ("%d/n", i); }
A () : i (0) {}
};
class B : public A {
public :
void f1 () { printf ("%d/n", i); }
B () { i = 2 ; }
};
int main () {
void (A::*pf1) () = &A::f1;
B b;
(b.*pf1)(); // output “2”
A a ;
(a.*pf1)() ; // output “0”
return 0;
}
It prints out “2, 0”, no doubt pf1 accesses different objects in both times. So be careful in treating alias set for member pointer. Here such pointer is regarded as may-alias (line 308 in cxx_get_alias_set ).
Except the treatment of class, C++ front-end shares following routine with C front-end to handle types also available in C. First for direct accessing of union member, it aliases to the other members of the union. The comment of the case says that setting the field via taking address is not permitted in C standard and it has implementation-defined behave, [6] also gives an explaination.
-fstrict-aliasing ² Allows the compiler to assume the strictest aliasing rules applicable to the language being compiled. For C (and C ++ ), this activates optimizations based on the type of expressions. In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same. For example, an unsigned int can alias an int , but not a void* or a double . A character type may alias any other type. Pay special attention to code like this: union a_union { int i; double d; }; int f() { a_union t; t.d = 3.0; return t.i; } The practice of reading from a different union member than the one most recently written to (called “type-punning”) is common. Even with ‘ -fstrict-aliasing ’, type-punning is allowed, provided the memory is accessed through the union type. So, the code above will work as expected. However, this code might not: int f() { a_union t; int* ip; t.d = 3.0; ip = &t.i; return *ip; } Similarly, access by taking the address, casting the resulting pointer and dereferencing the result has undefined behavior, even if the cast uses a union type, e.g.: int f() { double d = 3.0; return ((union a_union *) &d)->i; } The ‘ -fstrict-aliasing ’ option is enabled at levels ‘ -O2 ’, ‘ -O3 ’, ‘ -Os ’. |
Immediately in below, we will see an example of incorrect code generated out of type-punning. And that example can explain well why there may be undefined behavior. However, GCC give NO warning if we behave badly as above. Except this case, t of non-type is kicked off.
2848 HOST_WIDE_INT
2849 c_common_get_alias_set (tree t) n c-common.c
2850 {
2851 tree u;
2852
2853 /* Permit type-punning when accessing a union, provided the access
2854 is directly through the union. For example, this code does not
2855 permit taking the address of a union member and then storing
2856 through it. Even the type-punning allowed here is a GCC
2857 extension, albeit a common and useful one; the C standard says
2858 that such accesses have implementation-defined behavior. */
2859 for (u = t;
2860 TREE_CODE (u) == COMPONENT_REF || TREE_CODE (u) == ARRAY_REF;
2861 u = TREE_OPERAND (u, 0))
2862 if (TREE_CODE (u) == COMPONENT_REF
2863 && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE)
2864 return 0;
2865
2866 /* That's all the expressions we handle specially. */
2867 if (! TYPE_P (t))
2868 return -1;
2869
2870 /* The C standard guarantees that any object may be accessed via an
2871 lvalue that has character type. */
2872 if (t == char_type_node
2873 || t == signed_char_type_node
2874 || t == unsigned_char_type_node)
2875 return 0;
2876
2877 /* If it has the may_alias attribute, it can alias anything. */
2878 if (lookup_attribute ("may_alias", TYPE_ATTRIBUTES (t)))
2879 return 0;
2880
2881 /* The C standard specifically allows aliasing between signed and
2882 unsigned variants of the same type. We treat the signed
2883 variant as canonical. */
2884 if (TREE_CODE (t) == INTEGER_TYPE && TREE_UNSIGNED (t))
2885 {
2886 tree t1 = c_common_signed_type (t);
2887
2888 /* t1 == t can happen for boolean nodes which are always unsigned. */
2889 if (t1 != t)
2890 return get_alias_set (t1);
2891 }
2892 else if (POINTER_TYPE_P (t))
2893 {
2894 tree t1;
2895
2896 /* Unfortunately, there is no canonical form of a pointer type.
2897 I n particular, if we have `typedef int I', then `int *', and
2898 `I *' are different types. So, we have to pick a canonical
2899 representative. We do this below.
2900
2901 Technically, this approach is actually more conservative that
2902 it needs to be. In particular, `const int *' and `int *'
2903 should be in different alias sets, according to the C and C++
2904 standard, since their types are not the same, and so,
2905 technically, an `int **' and `const int **' cannot point at
2906 the same thing.
2907
2908 But, the standard is wrong. In particular, this code is
2909 legal C++:
2910
2911 int *ip;
2912 int **ipp = &ip;
2913 const int* const* cipp = &ipp;
2914
2915 And, it doesn't make sense for that to be legal unless you
2916 can dereference IPP and CIPP. So, we ignore cv-qualifiers on
2917 the pointed-to types. This issue has been reported to the
2918 C++ committee. */
2919 t1 = build_type_no_quals (t);
2920 if (t1 != t)
2921 return get_alias_set (t1);
2922 }
2923
2924 return -1;
2925 }
Above at line 2872, there are two case in fact would be covered. That is declaration like : char c; and char *pc; for the former case, c can’t alias other and no need create alias set (and consider the case of short type, it a group of 2 bytes, thus these two bytes can alias short type and must have alias set within the alias set of short, the front-end must prepare an alias set for this type as we see in the code), while rear one aliases any object that can be accessed via a lvalue. But for rear case, every time it points to specific object, it will get its alias set through block at line 494 in get_alias_set , and mayn’t be zero any more (it returns 0 for c style type cast).
At here, it is clear that declarations other than indirect reference (those pointer type or reference type) will share the alias set of their based type. For example : “short j , k, l; ”, in this statement, variables j, k, and l will have the same alias set of type short. However, the alias set will be ignored as these variables can’t alias each other. Now if we change the statement as : “short j, k, l, *p;”, now j, k, l and pointer p will share the alias set of short. So the front-end can know that p may alias to j, k or l.
Next consider statement “short j, k; char *p;”, j and k share the same alias set of short, but now p hasn’t alias set because get_alias_set (more precisely c_common_get_alias_set ) returns 0 for it. For this statement alone, the front-end won’t alias p to j or k. If we add a statement : “p = &j;”, in C++, it will trigger implicit conversion error. Then if we add instead a statement: “p = (char*)&j;”, alias set of p and j will be checked for intersection by front-end. It will pass since p has a superset of 0 (keep in mind there is no real superset of 0 created), and generate code for the conversion. However, the alias set of p always keeps as 0, which means it may-alias to everything can be accessed via lvalue. This assumption prevents compiler from taking error-prone too aggressive optimization. But it also a point as further improvement to discriminate alias set finer.
And at line 2884 above, integer types with difference signed also shares the same alias set.
Line 2878 mentions an interesting GNU C++ attribution “may_alias”. [6] gives a detail.
may_alias ² Accesses through pointers to types with this attribute are NOT subject to type based alias analysis, but are instead assumed to be able to alias any other type of objects. In the context of 6.5/7 an lvalue expression dereferencing such a pointer is treated like having a character type. See ‘-fstrict-aliasing’ for more information on aliasing issues. This extension exists to support some vector APIs, in which pointers to one vector type are permitted to alias pointers to a different vector type. Note that an object of a type with this attribute does not have any special semantics. Example of use: typedef short __attribute__ ((__may_alias__ )) short_a; int main (void) { int a = 0x12345678; short_a *b = (short_a *) &a; b[1] = 0; if (a == 0x12345678) abort(); exit(0); } If you replaced short_a with short in the variable declaration, the above program would abort when compiled with ‘-fstrict-aliasing’, which is on by default at ‘-O2’ or above in recent GCC versions. |
In above example, in other words, replacing short_a with short generates incorrect code. However you can use –Wstrict-aliasing to find out pointer that may break the alias. For example, here with the option, the compiler gives a warning as : “test2.cpp:4: warning: dereferencing type-punned pointer will break strict-aliasing rules ”.
Then, if cxx_get_alias_set returns value other than -1, either the alias set is found, or the object can alias nothing (i.e, char type). Otherwise, it needs go ahead. See that at line 598 in get_alias_set , the type is assigned with unique alias set and will be shared by declarations of the type. And for aggregate type or type containing more than 1 component, the alias set should contain alias sets of its fields. Below function record_omponent_aliases builds the alias tree in this way. Predicate TYPE_NONALIASED_COMPONENT at line 709 if true, indicates that it is not permitted to take the address of a component of the type.
697 void
698 record_component_aliases (tree type) in alias.c
699 {
700 HOST_WIDE_INT superset = get_alias_set (type);
701 tree field;
702
703 if (superset == 0)
704 return ;
705
706 switch (TREE_CODE (type))
707 {
708 case ARRAY_TYPE:
709 if (! TYPE_NONALIASED_COMPONENT (type))
710 record_alias_subset (superset, get_alias_set (TREE_TYPE (type)));
711 break ;
712
713 case RECORD_TYPE:
714 case UNION_TYPE:
715 case QUAL_UNION_TYPE:
716 /* Recursively record aliases for the base classes, if there are any. */
717 if (TYPE_BINFO (type) != NULL && TYPE_BINFO_BASETYPES (type) != NULL)
718 {
719 int i;
720 for (i = 0; i < TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type)); i++)
721 {
722 tree binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), i);
723 record_alias_subset (superset,
724 get_alias_set (BINFO_TYPE (binfo)));
725 }
726 }
727 for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field))
728 if (TREE_CODE (field) == FIELD_DECL && ! DECL_NONADDRESSABLE_P (field))
729 record_alias_subset (superset, get_alias_set (TREE_TYPE (field)));
730 break ;
731
732 case COMPLEX_TYPE:
733 record_alias_subset (superset, get_alias_set (TREE_TYPE (type)));
734 break ;
735
736 default :
737 break ;
738 }
739 }
Notice that in the aggregate type, for example, field of type of short will use alias set of type short, which means it will share this alias set with other declarations of this type. By this way, if there is a pointer of short type, the compiler can tell that the pointer may alias to this field and other declarations, and prevent too heavy optimization.