diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0e37d4043d0c0ad4c0865afc2865d6a498e6feeb..d450b3d5b78adc9e208fbdacc196b1201247fc7d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7534,6 +7534,7 @@ extern int at_function_scope_p			(void);
 extern bool at_class_scope_p			(void);
 extern bool at_namespace_scope_p		(void);
 extern tree context_for_name_lookup		(tree);
+extern tree type_context_for_name_lookup	(tree);
 extern tree lookup_conversions			(tree);
 extern tree binfo_from_vbase			(tree);
 extern tree binfo_for_vbase			(tree, tree);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index c5a55dae56393831d2a1a2bd3433361e95110ef7..9571d18170ea8070c7fd7a1e3de12c1fd30bd81e 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -597,7 +597,7 @@ maybe_instantiate_nsdmi_init (tree member, tsubst_flags_t complain)
 	  DECL_INSTANTIATING_NSDMI_P (member) = 1;
 
 	  bool pushed = false;
-	  tree ctx = DECL_CONTEXT (member);
+	  tree ctx = type_context_for_name_lookup (member);
 
 	  processing_template_decl_sentinel ptds (/*reset*/false);
 	  if (!currently_open_class (ctx))
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index e8efc32f2c26051ce874d88dd7264e0bf58d9dce..a6341b98af21aabc047e3faf59fe22559b7aed6f 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -26439,11 +26439,12 @@ cp_parser_class_specifier (cp_parser* parser)
       /* Now parse any NSDMIs.  */
       FOR_EACH_VEC_SAFE_ELT (unparsed_nsdmis, ix, decl)
 	{
-	  if (class_type != DECL_CONTEXT (decl))
+	  tree ctx = type_context_for_name_lookup (decl);
+	  if (class_type != ctx)
 	    {
 	      if (pushed_scope)
 		pop_scope (pushed_scope);
-	      class_type = DECL_CONTEXT (decl);
+	      class_type = ctx;
 	      pushed_scope = push_scope (class_type);
 	    }
 	  inject_this_parameter (class_type, TYPE_UNQUALIFIED);
diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc
index e472a97679dce36ec862a3430551e694655a6fe2..3f521b3bd72fc5eb83cc1c1a15ef2863f5a8c323 100644
--- a/gcc/cp/search.cc
+++ b/gcc/cp/search.cc
@@ -485,6 +485,25 @@ context_for_name_lookup (tree decl)
   return context;
 }
 
+/* Like the above, but always return a type, because it's simpler for member
+   handling to refer to the anonymous aggr rather than a function.  */
+
+tree
+type_context_for_name_lookup (tree decl)
+{
+  tree context = DECL_P (decl) ? DECL_CONTEXT (decl) : decl;
+  gcc_checking_assert (CLASS_TYPE_P (context));
+
+  while (context && TYPE_P (context) && ANON_AGGR_TYPE_P (context))
+    {
+      tree next = TYPE_CONTEXT (context);
+      if (!TYPE_P (next))
+	break;
+      context = next;
+    }
+  return context;
+}
+
 /* Returns true iff DECL is declared in TYPE.  */
 
 static bool
@@ -881,6 +900,10 @@ accessible_p (tree type, tree decl, bool consider_local_p)
   else
     otype = type;
 
+  /* Anonymous unions don't have their own access.  */
+  if (ANON_AGGR_TYPE_P (type))
+    type = type_context_for_name_lookup (type);
+
   /* [class.access.base]
 
      A member m is accessible when named in class N if
diff --git a/gcc/testsuite/g++.dg/lookup/anon8.C b/gcc/testsuite/g++.dg/lookup/anon8.C
new file mode 100644
index 0000000000000000000000000000000000000000..80124caba63f89a0227653592dc36721fad313fa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/anon8.C
@@ -0,0 +1,16 @@
+// PR c++/105452
+// { dg-do compile { target c++11 } }
+
+template <typename T>
+struct C {
+  int i = 42;
+  union {
+    T v = i;
+    static_assert(sizeof(v) == sizeof(char), "");
+  };
+};
+
+int main() {
+  C<char> x;
+  return x.v;
+}