This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
tahonermann marked an inline comment as done.
Closed by commit rG4409a83c2935: [clang] Correct handling of lambdas in lambda 
default arguments in dependent… (authored by tahonermann).

Changed prior to commit:
  https://reviews.llvm.org/D133500?vs=464489&id=465040#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133500/new/

https://reviews.llvm.org/D133500

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/DeclBase.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
  clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp
  clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp
  clang/test/CodeGenCXX/mangle-lambdas.cpp
  clang/test/SemaCXX/vartemplate-lambda.cpp
  clang/test/SemaTemplate/default-arguments.cpp
  clang/test/SemaTemplate/instantiate-local-class.cpp

Index: clang/test/SemaTemplate/instantiate-local-class.cpp
===================================================================
--- clang/test/SemaTemplate/instantiate-local-class.cpp
+++ clang/test/SemaTemplate/instantiate-local-class.cpp
@@ -401,7 +401,8 @@
 namespace PR21332 {
   template<typename T> void f1() {
     struct S {  // expected-note{{in instantiation of member class 'S' requested here}}
-      void g1(int n = T::error);  // expected-error{{type 'int' cannot be used prior to '::' because it has no members}}
+      void g1(int n = T::error);  // expected-error{{type 'int' cannot be used prior to '::' because it has no members}} \
+                                  // expected-note {{in instantiation of default function argument expression for 'g1<int>' required here}}
     };
   }
   template void f1<int>();  // expected-note{{in instantiation of function template specialization 'PR21332::f1<int>' requested here}}
@@ -438,7 +439,8 @@
     class S {  // expected-note {{in instantiation of member function 'PR21332::f6()::S::get' requested here}}
       void get() {
         class S2 {  // expected-note {{in instantiation of member class 'S2' requested here}}
-          void g1(int n = T::error);  // expected-error {{type 'int' cannot be used prior to '::' because it has no members}}
+          void g1(int n = T::error);  // expected-error {{type 'int' cannot be used prior to '::' because it has no members}} \
+                                      // expected-note  {{in instantiation of default function argument expression for 'g1<int>' required here}}
         };
       }
     };
@@ -460,16 +462,18 @@
 
   template <typename T> void foo() {
     struct Inner { // expected-note {{in instantiation}}
-      void operator()(T a = "") {} // expected-error {{conversion function from 'const char[1]' to 'rdar23721638::A' invokes a deleted function}}
-      // expected-note@-1 {{passing argument to parameter 'a' here}}
+      void operator()(T a = "") {} // expected-error {{conversion function from 'const char[1]' to 'rdar23721638::A' invokes a deleted function}} \
+                                   // expected-note  {{in instantiation of default function argument expression for 'operator()<rdar23721638::A>' required here}} \
+                                   // expected-note  {{passing argument to parameter 'a' here}}
     };
-    Inner()(); // expected-error {{type 'Inner' does not provide a call operator}}
+    Inner()();
   }
-  template void foo<A>(); // expected-note 2 {{in instantiation}}
+  template void foo<A>(); // expected-note {{in instantiation}}
 
   template <typename T> void bar() {
-    auto lambda = [](T a = "") {}; // expected-error {{conversion function from 'const char[1]' to 'rdar23721638::A' invokes a deleted function}}
-      // expected-note@-1 {{passing argument to parameter 'a' here}}
+    auto lambda = [](T a = "") {}; // expected-error {{conversion function from 'const char[1]' to 'rdar23721638::A' invokes a deleted function}} \
+                                   // expected-note  {{in instantiation of default function argument expression for 'operator()<rdar23721638::A>' required here}} \
+                                   // expected-note  {{passing argument to parameter 'a' here}}
     lambda();
   }
   template void bar<A>(); // expected-note {{in instantiation}}
@@ -490,7 +494,8 @@
   template <typename T>
   void f(int x = [](T x = nullptr) -> int { return x; }());
   // expected-error@-1 {{cannot initialize a parameter of type 'int' with an rvalue of type 'std::nullptr_t'}}
-  // expected-note@-2 {{passing argument to parameter 'x' here}}
+  // expected-note@-2  {{in instantiation of default function argument expression for 'operator()<int>' required here}}
+  // expected-note@-3  {{passing argument to parameter 'x' here}}
 
   void g() { f<int>(); }
   // expected-note@-1 {{in instantiation of default function argument expression for 'f<int>' required here}}
Index: clang/test/SemaTemplate/default-arguments.cpp
===================================================================
--- clang/test/SemaTemplate/default-arguments.cpp
+++ clang/test/SemaTemplate/default-arguments.cpp
@@ -169,7 +169,8 @@
 
 namespace NondefDecls {
   template<typename T> void f1() {
-    int g1(int defarg = T::error);  // expected-error{{type 'int' cannot be used prior to '::' because it has no members}}
+    int g1(int defarg = T::error);  // expected-error{{type 'int' cannot be used prior to '::' because it has no members}} \
+                                    // expected-note {{in instantiation of default function argument expression for 'g1<int>' required here}}
   }
   template void f1<int>();  // expected-note{{in instantiation of function template specialization 'NondefDecls::f1<int>' requested here}}
 }
Index: clang/test/SemaCXX/vartemplate-lambda.cpp
===================================================================
--- clang/test/SemaCXX/vartemplate-lambda.cpp
+++ clang/test/SemaCXX/vartemplate-lambda.cpp
@@ -6,7 +6,8 @@
 template<typename T> auto fn1 = [](auto a) { return a + T(1); };
 template<typename T> auto v1 = [](int a = T()) { return a; }();
 // expected-error@-1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}}
-// expected-note@-2{{passing argument to parameter 'a' here}}
+// expected-note@-2{{in instantiation of default function argument expression for 'operator()<int *>' required here}}
+// expected-note@-3{{passing argument to parameter 'a' here}}
 
 struct S {
   template<class T>
Index: clang/test/CodeGenCXX/mangle-lambdas.cpp
===================================================================
--- clang/test/CodeGenCXX/mangle-lambdas.cpp
+++ clang/test/CodeGenCXX/mangle-lambdas.cpp
@@ -210,6 +210,84 @@
 }
 int k = testVarargsLambdaNumbering();
 
+
+template<typename = int>
+void ft1(int = [](int p = [] { return 42; } ()) {
+                 return p;
+               } ());
+void test_ft1() {
+  // CHECK: call noundef i32 @"_ZZZ3ft1IiEviENK3$_4clEiEd_NKUlvE_clEv"
+  // CHECK: call noundef i32 @"_ZZ3ft1IiEviENK3$_4clEi"
+  ft1();
+}
+// CHECK-LABEL: define internal noundef i32 @"_ZZ3ft1IiEviENK3$_4clEi"
+// CHECK-LABEL: define internal noundef i32 @"_ZZZ3ft1IiEviENK3$_4clEiEd_NKUlvE_clEv"
+
+struct c1 {
+  template<typename = int>
+  void mft1(int = [](int p = [] { return 42; } ()) {
+                    return p;
+                  } ());
+};
+void test_c1_mft1() {
+  // CHECK: call noundef i32 @_ZZZN2c14mft1IiEEviEd_NKUliE_clEiEd_NKUlvE_clEv
+  // CHECK: call noundef i32 @_ZZN2c14mft1IiEEviEd_NKUliE_clEi
+  c1{}.mft1();
+}
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZN2c14mft1IiEEviEd_NKUliE_clEi
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZN2c14mft1IiEEviEd_NKUliE_clEiEd_NKUlvE_clEv
+
+template<typename = int>
+struct ct1 {
+  void mf1(int = [](int p = [] { return 42; } ()) {
+                   return p;
+                 } ());
+  friend void ff(ct1, int = [](int p = [] { return 0; }()) { return p; }()) {}
+};
+void test_ct1_mft1() {
+  // CHECK: call noundef i32 @_ZZZN3ct1IiE3mf1EiEd_NKUliE_clEiEd_NKUlvE_clEv
+  // CHECK: call noundef i32 @_ZZN3ct1IiE3mf1EiEd_NKUliE_clEi
+  ct1<>{}.mf1();
+  // CHECK: call noundef i32 @_ZZZ2ff3ct1IiEiEd_NKUliE_clEiEd_NKUlvE_clEv
+  // CHECK: call noundef i32 @_ZZ2ff3ct1IiEiEd_NKUliE_clEi
+  ff(ct1<>{});
+}
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZN3ct1IiE3mf1EiEd_NKUliE_clEi
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZN3ct1IiE3mf1EiEd_NKUliE_clEiEd_NKUlvE_clEv
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ2ff3ct1IiEiEd_NKUliE_clEi
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ2ff3ct1IiEiEd_NKUliE_clEiEd_NKUlvE_clEv
+
+template<typename = int>
+void ft2() {
+  [](int p = [] { return 42; } ()) { return p; } ();
+}
+template void ft2<>();
+// CHECK: call noundef i32 @_ZZZ3ft2IiEvvENKUliE_clEiEd_NKUlvE_clEv
+// CHECK: call noundef i32 @_ZZ3ft2IiEvvENKUliE_clEi
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ3ft2IiEvvENKUliE_clEi
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft2IiEvvENKUliE_clEiEd_NKUlvE_clEv
+
+template<typename>
+void ft3() {
+  void f(int = []{ return 0; }());
+  f();
+}
+template void ft3<int>();
+// CHECK: call noundef i32 @"_ZZ1fiENK3$_5clEv"
+// CHECK-LABEL: define internal noundef i32 @"_ZZ1fiENK3$_5clEv"
+
+template<typename>
+void ft4() {
+  struct lc {
+    void mf(int = []{ return 0; }()) {}
+  };
+  lc().mf();
+}
+template void ft4<int>();
+// CHECK: call noundef i32 @_ZZZ3ft4IiEvvEN2lc2mfEiEd_NKUlvE_clEv
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft4IiEvvEN2lc2mfEiEd_NKUlvE_clEv
+
+
 // Check linkage of the various lambdas.
 // CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ11inline_funciENKUlvE_clEv
 // CHECK: ret i32 1
Index: clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -no-opaque-pointers -std=c++20 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s -w | FileCheck %s
+
+template <typename T>
+auto ft1() {
+  return []<typename U = T>(T p1 = [] { return T{}; } (),
+                            U p2 = [] { return U{}; } ()) { return p1+p2; };
+}
+void test_ft1() {
+  // CHECK: call noundef i32 @_ZZZ3ft1IiEDavENKUlTyiT_E_clIiEEDaiS0_Ed0_NKUlvE_clEv
+  // CHECK: call noundef i32 @_ZZZ3ft1IiEDavENKUlTyiT_E_clIiEEDaiS0_Ed_NKUlvE_clEv
+  // CHECK: call noundef i32 @_ZZ3ft1IiEDavENKUlTyiT_E_clIiEEDaiS0_
+  ft1<int>()();
+}
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ3ft1IiEDavENKUlTyiT_E_clIiEEDaiS0_
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft1IiEDavENKUlTyiT_E_clIiEEDaiS0_Ed0_NKUlvE_clEv
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft1IiEDavENKUlTyiT_E_clIiEEDaiS0_Ed_NKUlvE_clEv
+
+template <typename T>
+auto vt1 = []<typename U = T>(T p1 = [] { return T{}; } (),
+                              U p2 = [] { return U{}; } ()) { return p1+p2; };
+void test_vt1() {
+  // CHECK: call noundef i32 @_ZZNK3vt1IiEMUlTyiT_E_clIiEEDaiS1_Ed0_NKUlvE_clEv
+  // CHECK: call noundef i32 @_ZZNK3vt1IiEMUlTyiT_E_clIiEEDaiS1_Ed_NKUlvE_clEv
+  // CHECK: call noundef i32 @_ZNK3vt1IiEMUlTyiT_E_clIiEEDaiS1_
+  vt1<int>();
+}
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZNK3vt1IiEMUlTyiT_E_clIiEEDaiS1_
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZNK3vt1IiEMUlTyiT_E_clIiEEDaiS1_Ed0_NKUlvE_clEv
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZNK3vt1IiEMUlTyiT_E_clIiEEDaiS1_Ed_NKUlvE_clEv
Index: clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -no-opaque-pointers -std=c++14 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s -w | FileCheck %s
+
+template<typename T = int>
+auto ft1() {
+  return [](int p = [] { return 0; } ()) { return p; };
+}
+void test_ft1() {
+  // CHECK: call noundef i32 @_ZZZ3ft1IiEDavENKUliE_clEiEd_NKUlvE_clEv
+  // CHECK: call noundef i32 @_ZZ3ft1IiEDavENKUliE_clEi
+  ft1<>()();
+}
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ3ft1IiEDavENKUliE_clEi
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft1IiEDavENKUliE_clEiEd_NKUlvE_clEv
+
+template <typename T>
+auto ft2() {
+  struct S {
+    T operator()(T p = []{ return 0; }()) const { return p; }
+  };
+  return S{};
+}
+void test_ft2() {
+  // CHECK: call noundef i32 @_ZZZ3ft2IiEDavENK1SclEiEd_NKUlvE_clEv
+  // CHECK: call noundef i32 @_ZZ3ft2IiEDavENK1SclEi
+  ft2<int>()();
+}
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ3ft2IiEDavENK1SclEi
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft2IiEDavENK1SclEiEd_NKUlvE_clEv
+
+template <typename>
+auto vt1 = [](int p = [] { return 0; } ()) { return p; };
+void test_vt1() {
+  // CHECK: call noundef i32 @_ZZNK3vt1IiEMUliE_clEiEd_NKUlvE_clEv
+  // CHECK: call noundef i32 @_ZNK3vt1IiEMUliE_clEi
+  vt1<int>();
+}
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZNK3vt1IiEMUliE_clEi
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZNK3vt1IiEMUliE_clEiEd_NKUlvE_clEv
Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
===================================================================
--- clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
@@ -34,7 +34,8 @@
 
 template<typename T>
 void defargs_in_template_unused(T t) {
-  auto l1 = [](const T& value = T()) { };  // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}}
+  auto l1 = [](const T& value = T()) { };  // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \
+                                           // expected-note {{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}}
   l1(t);
 }
 
@@ -44,13 +45,8 @@
 template<typename T>
 void defargs_in_template_used() {
   auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \
-                                          // expected-note{{candidate function not viable: requires single argument 'value', but no arguments were provided}}
-#if defined(_WIN32) && !defined(_WIN64)
-                                          // expected-note@46{{conversion candidate of type 'void (*)(const NoDefaultCtor &) __attribute__((thiscall))'}}
-#else
-                                          // expected-note@46{{conversion candidate of type 'void (*)(const NoDefaultCtor &)'}}
-#endif
-  l1(); // expected-error{{no matching function for call to object of type '(lambda at }}
+                                          // expected-note {{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}}
+  l1();
 }
 
 template void defargs_in_template_used<NonPOD>();
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2003,7 +2003,7 @@
 /// Normal class members are of more specific types and therefore
 /// don't make it here.  This function serves three purposes:
 ///   1) instantiating function templates
-///   2) substituting friend declarations
+///   2) substituting friend and local function declarations
 ///   3) substituting deduction guide declarations for nested class templates
 Decl *TemplateDeclInstantiator::VisitFunctionDecl(
     FunctionDecl *D, TemplateParameterList *TemplateParams,
@@ -2133,6 +2133,9 @@
     assert(D->getDeclContext()->isFileContext());
     LexicalDC = D->getDeclContext();
   }
+  else if (D->isLocalExternDecl()) {
+    LexicalDC = SemaRef.CurContext;
+  }
 
   Function->setLexicalDeclContext(LexicalDC);
 
@@ -2275,6 +2278,37 @@
                                  QualifierLoc.hasQualifier());
   }
 
+  // Per [temp.inst], default arguments in function declarations at local scope
+  // are instantiated along with the enclosing declaration. For example:
+  //
+  //   template<typename T>
+  //   void ft() {
+  //     void f(int = []{ return T::value; }());
+  //   }
+  //   template void ft<int>(); // error: type 'int' cannot be used prior
+  //                                      to '::' because it has no members
+  //
+  // The error is issued during instantiation of ft<int>() because substitution
+  // into the default argument fails; the default argument is instantiated even
+  // though it is never used.
+  if (Function->isLocalExternDecl()) {
+    for (ParmVarDecl *PVD : Function->parameters()) {
+      if (!PVD->hasDefaultArg())
+        continue;
+      if (SemaRef.SubstDefaultArgument(D->getInnerLocStart(), PVD, TemplateArgs)) {
+        // If substitution fails, the default argument is set to a
+        // RecoveryExpr that wraps the uninstantiated default argument so
+        // that downstream diagnostics are omitted.
+        Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
+        ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+            UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
+            { UninstExpr }, UninstExpr->getType());
+        if (ErrorResult.isUsable())
+          PVD->setDefaultArg(ErrorResult.get());
+      }
+    }
+  }
+
   SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
                                    IsExplicitSpecialization,
                                    Function->isThisDeclarationADefinition());
@@ -2628,6 +2662,39 @@
       Previous.clear();
   }
 
+  // Per [temp.inst], default arguments in member functions of local classes
+  // are instantiated along with the member function declaration. For example:
+  //
+  //   template<typename T>
+  //   void ft() {
+  //     struct lc {
+  //       int operator()(int p = []{ return T::value; }());
+  //     };
+  //   }
+  //   template void ft<int>(); // error: type 'int' cannot be used prior
+  //                                      to '::'because it has no members
+  //
+  // The error is issued during instantiation of ft<int>()::lc::operator()
+  // because substitution into the default argument fails; the default argument
+  // is instantiated even though it is never used.
+  if (D->isInLocalScopeForInstantiation()) {
+    for (unsigned P = 0; P < Params.size(); ++P) {
+      if (!Params[P]->hasDefaultArg())
+        continue;
+      if (SemaRef.SubstDefaultArgument(StartLoc, Params[P], TemplateArgs)) {
+        // If substitution fails, the default argument is set to a
+        // RecoveryExpr that wraps the uninstantiated default argument so
+        // that downstream diagnostics are omitted.
+        Expr *UninstExpr = Params[P]->getUninstantiatedDefaultArg();
+        ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+            UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
+            { UninstExpr }, UninstExpr->getType());
+        if (ErrorResult.isUsable())
+          Params[P]->setDefaultArg(ErrorResult.get());
+      }
+    }
+  }
+
   SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous,
                                    IsExplicitSpecialization,
                                    Method->isThisDeclarationADefinition());
@@ -4458,10 +4525,6 @@
 bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
                                       ParmVarDecl *Param) {
   assert(Param->hasUninstantiatedDefaultArg());
-  Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
-
-  EnterExpressionEvaluationContext EvalContext(
-      *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
 
   // Instantiate the expression.
   //
@@ -4483,59 +4546,9 @@
   MultiLevelTemplateArgumentList TemplateArgs
     = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true);
 
-  InstantiatingTemplate Inst(*this, CallLoc, Param,
-                             TemplateArgs.getInnermost());
-  if (Inst.isInvalid())
-    return true;
-  if (Inst.isAlreadyInstantiating()) {
-    Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD;
-    Param->setInvalidDecl();
-    return true;
-  }
-
-  ExprResult Result;
-  {
-    // C++ [dcl.fct.default]p5:
-    //   The names in the [default argument] expression are bound, and
-    //   the semantic constraints are checked, at the point where the
-    //   default argument expression appears.
-    ContextRAII SavedContext(*this, FD);
-    LocalInstantiationScope Local(*this);
-
-    FunctionDecl *Pattern = FD->getTemplateInstantiationPattern(
-        /*ForDefinition*/ false);
-    if (addInstantiatedParametersToScope(FD, Pattern, Local, TemplateArgs))
-      return true;
-
-    runWithSufficientStackSpace(CallLoc, [&] {
-      Result = SubstInitializer(UninstExpr, TemplateArgs,
-                                /*DirectInit*/false);
-    });
-  }
-  if (Result.isInvalid())
-    return true;
-
-  // Check the expression as an initializer for the parameter.
-  InitializedEntity Entity
-    = InitializedEntity::InitializeParameter(Context, Param);
-  InitializationKind Kind = InitializationKind::CreateCopy(
-      Param->getLocation(),
-      /*FIXME:EqualLoc*/ UninstExpr->getBeginLoc());
-  Expr *ResultE = Result.getAs<Expr>();
-
-  InitializationSequence InitSeq(*this, Entity, Kind, ResultE);
-  Result = InitSeq.Perform(*this, Entity, Kind, ResultE);
-  if (Result.isInvalid())
-    return true;
-
-  Result =
-      ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart(),
-                          /*DiscardedValue*/ false);
-  if (Result.isInvalid())
+  if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
     return true;
 
-  // Remember the instantiated default argument.
-  Param->setDefaultArg(Result.getAs<Expr>());
   if (ASTMutationListener *L = getASTMutationListener())
     L->DefaultArgumentInstantiated(Param);
 
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -179,11 +179,11 @@
         (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
         "Outer template not instantiated?");
   }
-  // If this is a friend declaration and it declares an entity at
+  // If this is a friend or local declaration and it declares an entity at
   // namespace scope, take arguments from its lexical parent
   // instead of its semantic parent, unless of course the pattern we're
   // instantiating actually comes from the file's context!
-  if (Function->getFriendObjectKind() &&
+  if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) &&
       Function->getNonTransparentDeclContext()->isFileContext() &&
       (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
     return Response::ChangeDecl(Function->getLexicalDeclContext());
@@ -1270,8 +1270,30 @@
     ExprResult TransformLambdaExpr(LambdaExpr *E) {
       LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
       Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
-      ExprResult Res = inherited::TransformLambdaExpr(E);
-      return Res;
+      ExprResult Result = inherited::TransformLambdaExpr(E);
+      if (Result.isInvalid())
+        return Result;
+
+      CXXMethodDecl *MD = Result.getAs<LambdaExpr>()->getCallOperator();
+      for (ParmVarDecl *PVD : MD->parameters()) {
+        if (!PVD->hasDefaultArg())
+          continue;
+        Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
+        // FIXME: Obtain the source location for the '=' token.
+        SourceLocation EqualLoc = UninstExpr->getBeginLoc();
+        if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
+          // If substitution fails, the default argument is set to a
+          // RecoveryExpr that wraps the uninstantiated default argument so
+          // that downstream diagnostics are omitted.
+          ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+              UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
+              { UninstExpr }, UninstExpr->getType());
+          if (ErrorResult.isUsable())
+            PVD->setDefaultArg(ErrorResult.get());
+        }
+      }
+
+      return Result;
     }
 
     ExprResult TransformRequiresExpr(RequiresExpr *E) {
@@ -2595,29 +2617,17 @@
     NewParm->setUnparsedDefaultArg();
     UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm);
   } else if (Expr *Arg = OldParm->getDefaultArg()) {
-    FunctionDecl *OwningFunc = cast<FunctionDecl>(OldParm->getDeclContext());
-    if (OwningFunc->isInLocalScopeForInstantiation()) {
-      // Instantiate default arguments for methods of local classes (DR1484)
-      // and non-defining declarations.
-      Sema::ContextRAII SavedContext(*this, OwningFunc);
-      LocalInstantiationScope Local(*this, true);
-      ExprResult NewArg = SubstExpr(Arg, TemplateArgs);
-      if (NewArg.isUsable()) {
-        // It would be nice if we still had this.
-        SourceLocation EqualLoc = NewArg.get()->getBeginLoc();
-        ExprResult Result =
-            ConvertParamDefaultArgument(NewParm, NewArg.get(), EqualLoc);
-        if (Result.isInvalid())
-          return nullptr;
-
-        SetParamDefaultArgument(NewParm, Result.getAs<Expr>(), EqualLoc);
-      }
-    } else {
-      // FIXME: if we non-lazily instantiated non-dependent default args for
-      // non-dependent parameter types we could remove a bunch of duplicate
-      // conversion warnings for such arguments.
-      NewParm->setUninstantiatedDefaultArg(Arg);
-    }
+    // Default arguments cannot be substituted until the declaration context
+    // for the associated function or lambda capture class is available.
+    // This is necessary for cases like the following where construction of
+    // the lambda capture class for the outer lambda is dependent on the
+    // parameter types but where the default argument is dependent on the
+    // outer lambda's declaration context.
+    //   template <typename T>
+    //   auto f() {
+    //     return [](T = []{ return T{}; }()) { return 0; };
+    //   }
+    NewParm->setUninstantiatedDefaultArg(Arg);
   }
 
   NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
@@ -2662,6 +2672,88 @@
       Loc, Params, nullptr, ExtParamInfos, ParamTypes, OutParams, ParamInfos);
 }
 
+/// Substitute the given template arguments into the default argument.
+bool Sema::SubstDefaultArgument(
+    SourceLocation Loc,
+    ParmVarDecl *Param,
+    const MultiLevelTemplateArgumentList &TemplateArgs,
+    bool ForCallExpr) {
+  FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext());
+  Expr *PatternExpr = Param->getUninstantiatedDefaultArg();
+
+  EnterExpressionEvaluationContext EvalContext(
+      *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
+
+  InstantiatingTemplate Inst(*this, Loc, Param, TemplateArgs.getInnermost());
+  if (Inst.isInvalid())
+    return true;
+  if (Inst.isAlreadyInstantiating()) {
+    Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD;
+    Param->setInvalidDecl();
+    return true;
+  }
+
+  ExprResult Result;
+  {
+    // C++ [dcl.fct.default]p5:
+    //   The names in the [default argument] expression are bound, and
+    //   the semantic constraints are checked, at the point where the
+    //   default argument expression appears.
+    ContextRAII SavedContext(*this, FD);
+    std::unique_ptr<LocalInstantiationScope> LIS;
+
+    if (ForCallExpr) {
+      // When instantiating a default argument due to use in a call expression,
+      // an instantiation scope that includes the parameters of the callee is
+      // required to satisfy references from the default argument. For example:
+      //   template<typename T> void f(T a, int = decltype(a)());
+      //   void g() { f(0); }
+      LIS = std::make_unique<LocalInstantiationScope>(*this);
+      FunctionDecl *PatternFD = FD->getTemplateInstantiationPattern(
+          /*ForDefinition*/ false);
+      if (addInstantiatedParametersToScope(FD, PatternFD, *LIS, TemplateArgs))
+        return true;
+    }
+
+    runWithSufficientStackSpace(Loc, [&] {
+      Result = SubstInitializer(PatternExpr, TemplateArgs,
+                                /*DirectInit*/false);
+    });
+  }
+  if (Result.isInvalid())
+    return true;
+
+  if (ForCallExpr) {
+    // Check the expression as an initializer for the parameter.
+    InitializedEntity Entity
+      = InitializedEntity::InitializeParameter(Context, Param);
+    InitializationKind Kind = InitializationKind::CreateCopy(
+        Param->getLocation(),
+        /*FIXME:EqualLoc*/ PatternExpr->getBeginLoc());
+    Expr *ResultE = Result.getAs<Expr>();
+
+    InitializationSequence InitSeq(*this, Entity, Kind, ResultE);
+    Result = InitSeq.Perform(*this, Entity, Kind, ResultE);
+    if (Result.isInvalid())
+      return true;
+
+    Result =
+        ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart(),
+                            /*DiscardedValue*/ false);
+  } else {
+    // FIXME: Obtain the source location for the '=' token.
+    SourceLocation EqualLoc = PatternExpr->getBeginLoc();
+    Result = ConvertParamDefaultArgument(Param, Result.getAs<Expr>(), EqualLoc);
+  }
+  if (Result.isInvalid())
+      return true;
+
+  // Remember the instantiated default argument.
+  Param->setDefaultArg(Result.getAs<Expr>());
+
+  return false;
+}
+
 /// Perform substitution on the base class specifiers of the
 /// given class template specialization.
 ///
Index: clang/lib/AST/DeclBase.cpp
===================================================================
--- clang/lib/AST/DeclBase.cpp
+++ clang/lib/AST/DeclBase.cpp
@@ -261,12 +261,12 @@
 
 bool Decl::isTemplated() const {
   // A declaration is templated if it is a template or a template pattern, or
-  // is within (lexcially for a friend, semantically otherwise) a dependent
-  // context.
-  // FIXME: Should local extern declarations be treated like friends?
+  // is within (lexcially for a friend or local function declaration,
+  // semantically otherwise) a dependent context.
   if (auto *AsDC = dyn_cast<DeclContext>(this))
     return AsDC->isDependentContext();
-  auto *DC = getFriendObjectKind() ? getLexicalDeclContext() : getDeclContext();
+  auto *DC = getFriendObjectKind() || isLocalExternDecl()
+      ? getLexicalDeclContext() : getDeclContext();
   return DC->isDependentContext() || isTemplateDecl() ||
          getDescribedTemplateParams();
 }
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -9782,6 +9782,9 @@
                       SmallVectorImpl<QualType> &ParamTypes,
                       SmallVectorImpl<ParmVarDecl *> *OutParams,
                       ExtParameterInfoBuilder &ParamInfos);
+  bool SubstDefaultArgument(SourceLocation Loc, ParmVarDecl *Param,
+                            const MultiLevelTemplateArgumentList &TemplateArgs,
+                            bool ForCallExpr = false);
   ExprResult SubstExpr(Expr *E,
                        const MultiLevelTemplateArgumentList &TemplateArgs);
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to