2020-04-10  Nathan Sidwell  <nathan@acm.org>

	PR c++/94426 = lambdas with internal linkage are different to no-linkage
	* decl2.c (determine_visibility): A lambda's visibility is
	affected by its extra scope.
	* pt.c (instantiate_decl): Determine var's visibility before
	instantiating its initializer.
	* tree.c (no_linkage_check): Revert code looking at visibility of
	lambda's extra scope.
	gcc/cp/
	* g++.dg/cpp0x/lambda/pr94426-[12].C: New.
	* g++.dg/abi/lambda-vis.C: Drop a warning.
	* g++.dg/cpp0x/lambda/lambda-mangle.C: Lambda visibility on
	variable changes.
	* g++.dg/opt/dump1.C: Drop warnings of no import.

diff --git c/gcc/cp/decl2.c w/gcc/cp/decl2.c
index 6cf72b432e2..293df990435 100644
--- c/gcc/cp/decl2.c
+++ w/gcc/cp/decl2.c
@@ -2527,6 +2527,21 @@ determine_visibility (tree decl)
   else if (DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl))
     template_decl = decl;
 
+  if (TREE_CODE (decl) == TYPE_DECL
+      && LAMBDA_TYPE_P (TREE_TYPE (decl))
+      && CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (decl)) != error_mark_node)
+    if (tree extra = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl)))
+      {
+	/* The lambda's visibility is limited by that of its extra
+	   scope.  */
+	int vis = 0;
+	if (TYPE_P (extra))
+	  vis = type_visibility (extra);
+	else
+	  vis = expr_visibility (extra);
+	constrain_visibility (decl, vis, false);
+      }
+
   /* If DECL is a member of a class, visibility specifiers on the
      class can influence the visibility of the DECL.  */
   tree class_type = NULL_TREE;
diff --git c/gcc/cp/pt.c w/gcc/cp/pt.c
index 050a57b2e2e..0a8ec3198d2 100644
--- c/gcc/cp/pt.c
+++ w/gcc/cp/pt.c
@@ -25541,6 +25541,14 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
       c_inhibit_evaluation_warnings = 0;
     }
 
+  if (VAR_P (d))
+    {
+      /* The variable might be a lambda's extra scope, and that
+	 lambda's visibility depends on D's.  */
+      maybe_commonize_var (d);
+      determine_visibility (d);
+    }
+
   /* Mark D as instantiated so that recursive calls to
      instantiate_decl do not try to instantiate it again.  */
   DECL_TEMPLATE_INSTANTIATED (d) = 1;
diff --git c/gcc/cp/tree.c w/gcc/cp/tree.c
index d1192b7e094..1d311b0fe61 100644
--- c/gcc/cp/tree.c
+++ w/gcc/cp/tree.c
@@ -2780,9 +2780,10 @@ verify_stmt_tree (tree t)
   cp_walk_tree (&t, verify_stmt_tree_r, &statements, NULL);
 }
 
-/* Check if the type T depends on a type with no linkage and if so, return
-   it.  If RELAXED_P then do not consider a class type declared within
-   a vague-linkage function to have no linkage.  */
+/* Check if the type T depends on a type with no linkage and if so,
+   return it.  If RELAXED_P then do not consider a class type declared
+   within a vague-linkage function to have no linkage.  Remember:
+   no-linkage is not the same as internal-linkage*/
 
 tree
 no_linkage_check (tree t, bool relaxed_p)
@@ -2801,17 +2802,6 @@ no_linkage_check (tree t, bool relaxed_p)
       tree extra = LAMBDA_TYPE_EXTRA_SCOPE (t);
       if (!extra)
 	return t;
-
-      /* If the mangling scope is internal-linkage or not repeatable
-	 elsewhere, the lambda effectively has no linkage.  (Sadly
-	 we're not very careful with the linkages of types.)  */
-      if (TREE_CODE (extra) == VAR_DECL
-	  && !(TREE_PUBLIC (extra)
-	       && (processing_template_decl
-		   || (DECL_LANG_SPECIFIC (extra) && DECL_USE_TEMPLATE (extra))
-		   /* DECL_COMDAT is set too late for us to check.  */
-		   || DECL_VAR_DECLARED_INLINE_P (extra))))
-	return t;
     }
 
   /* Otherwise there's no point in checking linkage on template functions; we
diff --git c/gcc/testsuite/g++.dg/abi/lambda-vis.C w/gcc/testsuite/g++.dg/abi/lambda-vis.C
index 89683b2076a..c1033f501a3 100644
--- c/gcc/testsuite/g++.dg/abi/lambda-vis.C
+++ w/gcc/testsuite/g++.dg/abi/lambda-vis.C
@@ -2,7 +2,7 @@
 // { dg-options "-fno-inline" }
 
 template<typename T> int sfoo (T); // { dg-warning "used but never defined" }
-template<typename T> int gfoo (T); // { dg-warning "used but never defined" }
+template<typename T> int gfoo (T); // OK, but not completable
 template<typename T> int ifoo (T); // OK
 template<typename T> struct Wrapper {};
 template<typename T> Wrapper<T> capture (T &&) {return Wrapper<T> ();}
diff --git c/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C w/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C
index 7894ef3051e..ef4bad8698b 100644
--- c/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C
+++ w/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C
@@ -54,9 +54,12 @@ void bar()
   []{}();
 }
 
-// lambdas used in non-template, non-class body initializers are internal.
+// lambdas used in namespace-scope initializers have the linkage of
+// the decl
 // { dg-final { scan-assembler-not "weak\[^\n\r\]*_ZNKUlv" } }
-// { dg-final { scan-assembler-not "weak\[^\n\r\]*variable" } }
+// { dg-final { scan-assembler "weak\[^\n\r\]*variableMUlvE_clEv" { target c++14_down } } }
+// in c++17 and up, this operator() become constexpr, no not emitted
+// { dg-final { scan-assembler-not "weak\[^\n\r\]*variableMUlvE_clEv" { target c++17 } } }
 int variable = []{return 1;}();
 
 // And a template instantiated with such a lambda is also internal.
diff --git c/gcc/testsuite/g++.dg/cpp0x/lambda/pr94426-1.C w/gcc/testsuite/g++.dg/cpp0x/lambda/pr94426-1.C
new file mode 100644
index 00000000000..ae7cbf03091
--- /dev/null
+++ w/gcc/testsuite/g++.dg/cpp0x/lambda/pr94426-1.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++14 } }
+// PR 94426 ICE mangling lambda
+// { dg-options {-flto -O2} }
+
+template <bool> using Void = void;
+
+template <typename U> bool Init (U) {return true;}
+template <typename> bool VAR = Init ([] {});
+
+template <typename T>
+Void<false && VAR<T>> Foo (T)
+{}
+
+void q ()
+{
+  Foo ([] {});
+}
diff --git c/gcc/testsuite/g++.dg/cpp0x/lambda/pr94426-2.C w/gcc/testsuite/g++.dg/cpp0x/lambda/pr94426-2.C
new file mode 100644
index 00000000000..3db864c604b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/cpp0x/lambda/pr94426-2.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++14 } }
+// PR 94426 ICE mangling lambda
+
+template <bool> using Void = void;
+
+template <typename U> bool Init (U) {return true;}
+template <typename> bool VAR = Init ([] {});
+
+template <typename T>
+Void<false && VAR<T>> Foo (T)
+{}
+
+void q ()
+{
+  Foo ([] {});
+}
+
+// The instantiation of VAR becomes local
+// { dg-final { scan-assembler {.local	_Z3VARIZ1qvEUlvE_E} { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler {.comm	_Z3VARIZ1qvEUlvE_E,1,1} { target { i?86-*-* x86_64-*-* } } } }
diff --git c/gcc/testsuite/g++.dg/opt/dump1.C w/gcc/testsuite/g++.dg/opt/dump1.C
index f813044456c..38ed055d5c6 100644
--- c/gcc/testsuite/g++.dg/opt/dump1.C
+++ w/gcc/testsuite/g++.dg/opt/dump1.C
@@ -312,7 +312,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
     typename __add_ref<
                       typename tuple_element<__i, tuple<_Elements...>>::type
                     >::type
-    get(tuple<_Elements...>& __t) noexcept; // { dg-warning "used but never defined" }
+    get(tuple<_Elements...>& __t) noexcept;
   template<std::size_t... _Indexes>
     struct _Index_tuple
     {};
@@ -387,7 +387,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
     };
   template<typename _Callable, typename... _Args>
     typename _Bind_simple_helper<_Callable, _Args...>::__type
-    __bind_simple(_Callable&& __callable, _Args&&... __args)  // { dg-warning "used but never defined" }
+    __bind_simple(_Callable&& __callable, _Args&&... __args) 
   ;
   union _Any_data
   ;
@@ -404,7 +404,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
       {
       protected:
  static _Functor*
- _M_get_pointer(const _Any_data& __source)  // { dg-warning "used but never defined" }
+ _M_get_pointer(const _Any_data& __source)
  ;
       };
   };
@@ -511,7 +511,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
         _S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
  { ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); }
       static pointer
-      allocate(_Alloc& __a, size_type __n)  // { dg-warning "used but never defined" }
+      allocate(_Alloc& __a, size_type __n) 
       ;
       template<typename _Tp, typename... _Args>
  static auto construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
