diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 36f9530bb741102f933c5907b02b360c125f3976..b507d6d46d642765811bf2d174ea8c63dbae0738 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2004-12-03  Richard Henderson  <rth@redhat.com>
+
+	* alias.c (component_uses_parent_alias_set): Rename from 
+	can_address_p.  Return bool.  Reverse the sense of the result.
+	Reinstate the check for alias set zero.
+	(get_alias_set): Update to match.
+	* alias.h (component_uses_parent_alias_set): Likewise.
+	* emit-rtl.c (set_mem_attributes_minus_bitpos): Likewise.
+	* expr.c (expand_assignment): Likewise.
+	* expr.h: Remove commented out prototypes that were moved to alias.h.
+
 2004-12-03  Richard Henderson  <rth@redhat.com>
 
 	* doc/tm.texi (TARGET_BUILD_BUILTIN_VA_LIST): New.
diff --git a/gcc/alias.c b/gcc/alias.c
index 3246082af23d7f5149a872af302e33a77e8cd375..e2b7adf156f7e671c6171254ea84f9e43142f72d 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -378,29 +378,36 @@ find_base_decl (tree t)
     }
 }
 
-/* Return 1 if all the nested component references handled by
-   get_inner_reference in T are such that we can address the object in T.  */
+/* Return true if all nested component references handled by
+   get_inner_reference in T are such that we should use the alias set
+   provided by the object at the heart of T.
 
-int
-can_address_p (tree t)
+   This is true for non-addressable components (which don't have their
+   own alias set), as well as components of objects in alias set zero.
+   This later point is a special case wherein we wish to override the
+   alias set used by the component, but we don't have per-FIELD_DECL
+   assignable alias sets.  */
+
+bool
+component_uses_parent_alias_set (tree t)
 {
   while (1)
     {
-      /* If we're at the end, it is vacuously addressable.  */
+      /* If we're at the end, it vacuously uses its own alias set.  */
       if (!handled_component_p (t))
-	return true;
+	return false;
 
       switch (TREE_CODE (t))
 	{
 	case COMPONENT_REF:
 	  if (DECL_NONADDRESSABLE_P (TREE_OPERAND (t, 1)))
-	    return false;
+	    return true;
 	  break;
 
 	case ARRAY_REF:
 	case ARRAY_RANGE_REF:
 	  if (TYPE_NONALIASED_COMPONENT (TREE_TYPE (TREE_OPERAND (t, 0))))
-	    return false;
+	    return true;
 	  break;
 
 	case REALPART_EXPR:
@@ -409,10 +416,12 @@ can_address_p (tree t)
 
 	default:
 	  /* Bitfields and casts are never addressable.  */
-	  return false;
+	  return true;
 	}
 
       t = TREE_OPERAND (t, 0);
+      if (get_alias_set (TREE_TYPE (t)) == 0)
+	return true;
     }
 }
 
@@ -515,7 +524,7 @@ get_alias_set (tree t)
 
       /* Otherwise, pick up the outermost object that we could have a pointer
 	 to, processing conversions as above.  */
-      while (handled_component_p (t) && ! can_address_p (t))
+      while (component_uses_parent_alias_set (t))
 	{
 	  t = TREE_OPERAND (t, 0);
 	  STRIP_NOPS (t);
diff --git a/gcc/alias.h b/gcc/alias.h
index ea78e808a62bb42f42c39535e16e64edd824bed1..58fe0bd17d46af33053010626d37943ba6312f46 100644
--- a/gcc/alias.h
+++ b/gcc/alias.h
@@ -25,6 +25,6 @@ extern HOST_WIDE_INT new_alias_set (void);
 extern HOST_WIDE_INT get_varargs_alias_set (void);
 extern HOST_WIDE_INT get_frame_alias_set (void);
 extern void record_base_value (unsigned int, rtx, int);
-extern int can_address_p (tree);
+extern bool component_uses_parent_alias_set (tree);
 
 #endif /* GCC_ALIAS_H */
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index d722f90ad697ffbf8ba0560d4a1b3aed52edf0be..6858f987ad6ea9251a46d14a9a5b4b963954ddaa 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1546,9 +1546,9 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
 	     || TREE_CODE (t) == SAVE_EXPR)
 	t = TREE_OPERAND (t, 0);
 
-      /* If this expression can't be addressed (e.g., it contains a reference
-	 to a non-addressable field), show we don't change its alias set.  */
-      if (! can_address_p (t))
+      /* If this expression uses it's parent's alias set, mark it such
+	 that we won't change it.  */
+      if (component_uses_parent_alias_set (t))
 	MEM_KEEP_ALIAS_SET_P (ref) = 1;
 
       /* If this is a decl, set the attributes of the MEM from it.  */
diff --git a/gcc/expr.c b/gcc/expr.c
index ec25713c5e91ee1a32f5d9c33e3d578fb2cfbea4..1a43145899143afd2a7409bd29edd9c22eeacd55 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -3810,8 +3810,7 @@ expand_assignment (tree to, tree from)
 		 done for MEM.  Also set MEM_KEEP_ALIAS_SET_P if needed.  */
 	      if (volatilep)
 		MEM_VOLATILE_P (to_rtx) = 1;
-
-	      if (!can_address_p (to))
+	      if (component_uses_parent_alias_set (to))
 		MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
 	    }
 
diff --git a/gcc/expr.h b/gcc/expr.h
index 780ad4dfdd48a6367b996b15074c8597c61b9072..64dccd069bd98add7994f113ea03c6e9b1a76c02 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -530,11 +530,6 @@ extern unsigned int case_values_threshold (void);
 
 /* Functions from alias.c */
 #include "alias.h"
-/* extern HOST_WIDE_INT get_varargs_alias_set (void); */
-/* extern HOST_WIDE_INT get_frame_alias_set (void); */
-/* extern void record_base_value (unsigned int, rtx, int); */
-/* extern HOST_WIDE_INT new_alias_set (void); */
-/* extern int can_address_p (tree); */
 
 
 /* rtl.h and tree.h were included.  */
diff --git a/gcc/testsuite/gcc.dg/attr-may-alias-1.c b/gcc/testsuite/gcc.dg/attr-may-alias-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..30e2bca6f48e9d033287457f4651bc9127ae9bda
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-may-alias-1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler "dont_delete" } } */
+
+typedef struct { int x; } __attribute__((may_alias)) S;
+
+extern void dont_delete (void);
+
+void f(S *s, float *f)
+{
+  s->x = 1;
+  *f = 0;
+  if (s->x != 1)
+    dont_delete ();
+}