[clang] Correct handling of lambdas in lambda default arguments in dependent contexts.
authorTom Honermann <tom.honermann@intel.com>
Fri, 6 May 2022 20:55:05 +0000 (13:55 -0700)
committerTom Honermann <tom.honermann@intel.com>
Tue, 4 Oct 2022 16:04:54 +0000 (09:04 -0700)
Previously, a lambda expression in a dependent context with a default argument
containing an immediately invoked lambda expression would produce a closure
class object that, if invoked such that the default argument was used, resulted
in a compiler crash or one of the following assertion failures during code
generation. The failures occurred regardless of whether the lambda expressions
were dependent.

  clang/lib/CodeGen/CGCall.cpp:
  Assertion `(isGenericMethod || Ty->isVariablyModifiedType() || Ty.getNonReferenceType()->isObjCRetainableType() || getContext() .getCanonicalType(Ty.getNonReferenceType()) .getTypePtr() == getContext().getCanonicalType((*Arg)->getType()).getTypePtr()) && "type mismatch in call argument!"' failed.

  clang/lib/AST/Decl.cpp:
  Assertion `!Init->isValueDependent()' failed.

Default arguments in declarations in local context are instantiated along with
their enclosing function or variable template (since such declarations can't
be explicitly specialized). Previously, such instantiations were performed at
the same time that their associated parameters were instantiated. However, that
approach fails in cases like the following in which the context for the inner
lambda is the outer lambda, but construction of the outer lambda is dependent
on the parameters of the inner lambda. This change resolves this dependency by
delyaing instantiation of default arguments in local contexts until after
construction of the enclosing context.
  template <typename T>
  auto f() {
    return [](T = []{ return T{}; }()) { return 0; };
  }

Refactoring included with this change results in the same code now being used
to instantiate default arguments that appear in local context and those that
are only instantiated when used at a call site; previously, such code was
duplicated and out of sync.

Fixes https://github.com/llvm/llvm-project/issues/49178

Reviewed By: erichkeane

Differential Revision: https://reviews.llvm.org/D133500

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 [new file with mode: 0644]
clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp [new file with mode: 0644]
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 74735fb..ce6f67a 100644 (file)
@@ -9782,6 +9782,9 @@ public:
                       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);
 
index a9ac441..763fc1d 100644 (file)
@@ -261,12 +261,12 @@ const TemplateParameterList *Decl::getDescribedTemplateParams() const {
 
 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 c6eb034..21b141f 100644 (file)
@@ -179,11 +179,11 @@ Response HandleFunction(const FunctionDecl *Function,
         (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 @@ namespace {
     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 @@ Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
     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 @@ bool Sema::SubstParmTypes(
       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 9fcc165..b50ed64 100644 (file)
@@ -2003,7 +2003,7 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
 /// 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 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
     assert(D->getDeclContext()->isFileContext());
     LexicalDC = D->getDeclContext();
   }
+  else if (D->isLocalExternDecl()) {
+    LexicalDC = SemaRef.CurContext;
+  }
 
   Function->setLexicalDeclContext(LexicalDC);
 
@@ -2275,6 +2278,37 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
                                  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 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
       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::addInstantiatedParametersToScope(
 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 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
   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 3e28288..72265d7 100644 (file)
@@ -34,7 +34,8 @@ struct NoDefaultCtor {
 
 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 void defargs_in_template_unused(NoDefaultCtor);  // expected-note{{in i
 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>();
diff --git a/clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp b/clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp
new file mode 100644 (file)
index 0000000..5049356
--- /dev/null
@@ -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
diff --git a/clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp b/clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp
new file mode 100644 (file)
index 0000000..0e080e7
--- /dev/null
@@ -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 ab6c90a..063b989 100644 (file)
@@ -210,6 +210,84 @@ inline int testVarargsLambdaNumbering() {
 }
 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 3546193..8b232ab 100644 (file)
@@ -6,7 +6,8 @@ template <typename> void foo0() { fn0<char>(); }
 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 882b279..a850d27 100644 (file)
@@ -169,7 +169,8 @@ namespace DR1635 {
 
 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 e51c711..f0f3d2b 100644 (file)
@@ -401,7 +401,8 @@ void g() { f<void>(); }
 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 @@ namespace PR21332 {
     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 @@ namespace rdar23721638 {
 
   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 {{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 @@ namespace PR45000 {
   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}}