[clang] 69dd89f - [Clang] Fix references to captured variables in dependant context.

Corentin Jabot via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 20 06:35:27 PDT 2022


Author: Corentin Jabot
Date: 2022-04-20T15:35:20+02:00
New Revision: 69dd89fdcbd846375a45e2fe3a88710887236d7a

URL: https://github.com/llvm/llvm-project/commit/69dd89fdcbd846375a45e2fe3a88710887236d7a
DIFF: https://github.com/llvm/llvm-project/commit/69dd89fdcbd846375a45e2fe3a88710887236d7a.diff

LOG: [Clang] Fix references to captured variables in dependant context.

D119136 changed how captures are handled in a lambda call operator
declaration, but did not properly handled dependant context,
which led to crash when refering to init-captures in
a trailing return type.

We fix that bug by making transformations more symetric with parsing,
ie. we first create the call operator, then transform the capture,
then compute the type of the lambda call operaror.

This ensures captures exist and have the right type when
we parse a trailing requires-clause / return type.

Reviewed By: aaron.ballman

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

Added: 
    

Modified: 
    clang/include/clang/Sema/Sema.h
    clang/lib/Sema/SemaLambda.cpp
    clang/lib/Sema/TreeTransform.h
    clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
    clang/test/SemaCXX/lambda-capture-type-deduction.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d5b73686e84a7..6298838d60855 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6828,15 +6828,6 @@ class Sema final {
                                          unsigned LambdaDependencyKind,
                                          LambdaCaptureDefault CaptureDefault);
 
-  /// Start the definition of a lambda expression.
-  CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class,
-                                       SourceRange IntroducerRange,
-                                       TypeSourceInfo *MethodType,
-                                       SourceLocation EndLoc,
-                                       ArrayRef<ParmVarDecl *> Params,
-                                       ConstexprSpecKind ConstexprKind,
-                                       Expr *TrailingRequiresClause);
-
   /// Number lambda for linkage purposes if necessary.
   void handleLambdaNumbering(
       CXXRecordDecl *Class, CXXMethodDecl *Method,
@@ -6849,9 +6840,16 @@ class Sema final {
                         LambdaCaptureDefault CaptureDefault,
                         SourceLocation CaptureDefaultLoc,
                         bool ExplicitParams,
-                        bool ExplicitResultType,
                         bool Mutable);
 
+  CXXMethodDecl *CreateLambdaCallOperator(SourceRange IntroducerRange,
+                                          CXXRecordDecl *Class);
+  void CompleteLambdaCallOperator(
+      CXXMethodDecl *Method, SourceLocation LambdaLoc,
+      SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause,
+      TypeSourceInfo *MethodTyInfo, ConstexprSpecKind ConstexprKind,
+      ArrayRef<ParmVarDecl *> Params, bool HasExplicitResultType);
+
   /// Perform initialization analysis of the init-capture and perform
   /// any implicit conversions such as an lvalue-to-rvalue conversion if
   /// not being used to initialize a reference.

diff  --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index d5918a28d9f06..e1086adcdb73b 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -377,76 +377,6 @@ buildTypeForLambdaCallOperator(Sema &S, clang::CXXRecordDecl *Class,
   return MethodType;
 }
 
-/// Start the definition of a lambda expression.
-/// In this overload, we do not know the type yet
-CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
-                                           SourceRange IntroducerRange,
-                                           TypeSourceInfo *MethodTypeInfo,
-                                           SourceLocation EndLoc,
-                                           ArrayRef<ParmVarDecl *> Params,
-                                           ConstexprSpecKind ConstexprKind,
-                                           Expr *TrailingRequiresClause) {
-
-  LambdaScopeInfo *LSI = getCurLambda();
-
-  TemplateParameterList *TemplateParams =
-      getGenericLambdaTemplateParameterList(LSI, *this);
-
-  // At this point, we may not know the type of the lambda, if we have not
-  // parsed a trailing return type yet
-  QualType MethodType = MethodTypeInfo
-                            ? buildTypeForLambdaCallOperator(
-                                  *this, Class, TemplateParams, MethodTypeInfo)
-                            : QualType();
-
-  // C++11 [expr.prim.lambda]p5:
-  //   The closure type for a lambda-expression has a public inline function
-  //   call operator (13.5.4) whose parameters and return type are described
-  //   by the lambda-expression's parameter-declaration-clause and
-  //   trailing-return-type respectively.
-  DeclarationName MethodName =
-      Context.DeclarationNames.getCXXOperatorName(OO_Call);
-  DeclarationNameLoc MethodNameLoc =
-      DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange);
-  CXXMethodDecl *Method = CXXMethodDecl::Create(
-      Context, Class, EndLoc,
-      DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
-                          MethodNameLoc),
-      MethodType, MethodTypeInfo, SC_None, getCurFPFeatures().isFPConstrained(),
-      /*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause);
-  Method->setAccess(AS_public);
-  if (!TemplateParams)
-    Class->addDecl(Method);
-
-  // Temporarily set the lexical declaration context to the current
-  // context, so that the Scope stack matches the lexical nesting.
-  Method->setLexicalDeclContext(CurContext);
-  // Create a function template if we have a template parameter list
-  FunctionTemplateDecl *const TemplateMethod =
-      TemplateParams
-          ? FunctionTemplateDecl::Create(Context, Class, Method->getLocation(),
-                                         MethodName, TemplateParams, Method)
-          : nullptr;
-  if (TemplateMethod) {
-    TemplateMethod->setAccess(AS_public);
-    Method->setDescribedFunctionTemplate(TemplateMethod);
-    Class->addDecl(TemplateMethod);
-    TemplateMethod->setLexicalDeclContext(CurContext);
-  }
-
-  // Add parameters.
-  if (!Params.empty()) {
-    Method->setParams(Params);
-    CheckParmsForFunctionDef(Params,
-                             /*CheckParameterNames=*/false);
-
-    for (auto P : Method->parameters())
-      P->setOwningFunction(Method);
-  }
-
-  return Method;
-}
-
 void Sema::handleLambdaNumbering(
     CXXRecordDecl *Class, CXXMethodDecl *Method,
     Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) {
@@ -517,12 +447,11 @@ static void buildLambdaScopeReturnType(Sema &S, LambdaScopeInfo *LSI,
   }
 }
 
-static void buildLambdaScopeCaptures(LambdaScopeInfo *LSI,
-                                     CXXMethodDecl *CallOperator,
-                                     SourceRange IntroducerRange,
-                                     LambdaCaptureDefault CaptureDefault,
-                                     SourceLocation CaptureDefaultLoc,
-                                     bool ExplicitParams, bool Mutable) {
+void Sema::buildLambdaScope(LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator,
+                            SourceRange IntroducerRange,
+                            LambdaCaptureDefault CaptureDefault,
+                            SourceLocation CaptureDefaultLoc,
+                            bool ExplicitParams, bool Mutable) {
   LSI->CallOperator = CallOperator;
   CXXRecordDecl *LambdaClass = CallOperator->getParent();
   LSI->Lambda = LambdaClass;
@@ -536,17 +465,6 @@ static void buildLambdaScopeCaptures(LambdaScopeInfo *LSI,
   LSI->Mutable = Mutable;
 }
 
-void Sema::buildLambdaScope(LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator,
-                            SourceRange IntroducerRange,
-                            LambdaCaptureDefault CaptureDefault,
-                            SourceLocation CaptureDefaultLoc,
-                            bool ExplicitParams, bool ExplicitResultType,
-                            bool Mutable) {
-  buildLambdaScopeCaptures(LSI, CallOperator, IntroducerRange, CaptureDefault,
-                           CaptureDefaultLoc, ExplicitParams, Mutable);
-  buildLambdaScopeReturnType(*this, LSI, CallOperator, ExplicitResultType);
-}
-
 void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
   LSI->finishedExplicitCaptures();
 }
@@ -953,28 +871,76 @@ static TypeSourceInfo *getLambdaType(Sema &S, LambdaIntroducer &Intro,
   return MethodTyInfo;
 }
 
-static CXXMethodDecl *CreateMethod(Sema &S, SourceRange IntroducerRange,
-                                   CXXRecordDecl *Class) {
+CXXMethodDecl *Sema::CreateLambdaCallOperator(SourceRange IntroducerRange,
+                                              CXXRecordDecl *Class) {
+
   // C++11 [expr.prim.lambda]p5:
   //   The closure type for a lambda-expression has a public inline function
   //   call operator (13.5.4) whose parameters and return type are described
   //   by the lambda-expression's parameter-declaration-clause and
   //   trailing-return-type respectively.
   DeclarationName MethodName =
-      S.Context.DeclarationNames.getCXXOperatorName(OO_Call);
+      Context.DeclarationNames.getCXXOperatorName(OO_Call);
   DeclarationNameLoc MethodNameLoc =
       DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange.getBegin());
   CXXMethodDecl *Method = CXXMethodDecl::Create(
-      S.Context, Class, SourceLocation(),
+      Context, Class, SourceLocation(),
       DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
                           MethodNameLoc),
-      QualType(), nullptr, SC_None, S.getCurFPFeatures().isFPConstrained(),
+      QualType(), nullptr, SC_None, getCurFPFeatures().isFPConstrained(),
       /*isInline=*/true, ConstexprSpecKind::Unspecified, SourceLocation(),
       nullptr);
   Method->setAccess(AS_public);
   return Method;
 }
 
+void Sema::CompleteLambdaCallOperator(
+    CXXMethodDecl *Method, SourceLocation LambdaLoc,
+    SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause,
+    TypeSourceInfo *MethodTyInfo, ConstexprSpecKind ConstexprKind,
+    ArrayRef<ParmVarDecl *> Params, bool HasExplicitResultType) {
+
+  LambdaScopeInfo *const LSI = getCurrentLambdaScopeUnsafe(*this);
+
+  if (TrailingRequiresClause)
+    Method->setTrailingRequiresClause(TrailingRequiresClause);
+
+  TemplateParameterList *TemplateParams =
+      getGenericLambdaTemplateParameterList(LSI, *this);
+
+  auto DC = Method->getLexicalDeclContext();
+  Method->setLexicalDeclContext(LSI->Lambda);
+  if (TemplateParams) {
+    FunctionTemplateDecl *const TemplateMethod = FunctionTemplateDecl::Create(
+        Context, LSI->Lambda, Method->getLocation(), Method->getDeclName(),
+        TemplateParams, Method);
+    TemplateMethod->setAccess(AS_public);
+    Method->setDescribedFunctionTemplate(TemplateMethod);
+    LSI->Lambda->addDecl(TemplateMethod);
+    TemplateMethod->setLexicalDeclContext(DC);
+  } else {
+    LSI->Lambda->addDecl(Method);
+  }
+  LSI->Lambda->setLambdaIsGeneric(TemplateParams);
+  LSI->Lambda->setLambdaTypeInfo(MethodTyInfo);
+
+  Method->setLexicalDeclContext(DC);
+  Method->setLocation(LambdaLoc);
+  Method->setInnerLocStart(CallOperatorLoc);
+  Method->setTypeSourceInfo(MethodTyInfo);
+  Method->setType(buildTypeForLambdaCallOperator(*this, LSI->Lambda,
+                                                 TemplateParams, MethodTyInfo));
+  Method->setConstexprKind(ConstexprKind);
+  if (!Params.empty()) {
+    CheckParmsForFunctionDef(Params, /*CheckParameterNames=*/false);
+    Method->setParams(Params);
+    for (auto P : Method->parameters())
+      P->setOwningFunction(Method);
+  }
+
+  buildLambdaScopeReturnType(*this, LSI, Method, HasExplicitResultType);
+}
+
 void Sema::ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurrentScope) {
 
   LambdaScopeInfo *const LSI = getCurLambda();
@@ -1016,7 +982,7 @@ void Sema::ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurrentScope) {
   //   by the lambda-expression's parameter-declaration-clause and
   //   trailing-return-type respectively.
 
-  CXXMethodDecl *Method = CreateMethod(*this, Intro.Range, Class);
+  CXXMethodDecl *Method = CreateLambdaCallOperator(Intro.Range, Class);
   LSI->CallOperator = Method;
   Method->setLexicalDeclContext(CurContext);
 
@@ -1297,55 +1263,24 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
   SmallVector<ParmVarDecl *, 8> Params;
   bool ExplicitResultType;
 
-  SourceLocation TypeLoc, LambdaLoc;
+  SourceLocation TypeLoc, CallOperatorLoc;
   if (ParamInfo.getNumTypeObjects() == 0) {
-    LambdaLoc = TypeLoc = Intro.Range.getEnd();
+    CallOperatorLoc = TypeLoc = Intro.Range.getEnd();
   } else {
     unsigned index;
     ParamInfo.isFunctionDeclarator(index);
     const auto &Object = ParamInfo.getTypeObject(index);
     TypeLoc =
         Object.Loc.isValid() ? Object.Loc : ParamInfo.getSourceRange().getEnd();
-    LambdaLoc = ParamInfo.getSourceRange().getEnd();
+    CallOperatorLoc = ParamInfo.getSourceRange().getEnd();
   }
 
   CXXRecordDecl *Class = LSI->Lambda;
   CXXMethodDecl *Method = LSI->CallOperator;
 
-  if (auto *C = ParamInfo.getTrailingRequiresClause())
-    Method->setTrailingRequiresClause(C);
-
-  TemplateParameterList *TemplateParams =
-      getGenericLambdaTemplateParameterList(LSI, *this);
-
-  auto DC = Method->getLexicalDeclContext();
-  Method->setLexicalDeclContext(Class);
-  if (TemplateParams) {
-    FunctionTemplateDecl *const TemplateMethod = FunctionTemplateDecl::Create(
-        Context, Class, Method->getLocation(), Method->getDeclName(),
-        TemplateParams, Method);
-    TemplateMethod->setAccess(AS_public);
-    Method->setDescribedFunctionTemplate(TemplateMethod);
-    Class->addDecl(TemplateMethod);
-    TemplateMethod->setLexicalDeclContext(DC);
-  } else {
-    Class->addDecl(Method);
-  }
-  Method->setLexicalDeclContext(DC);
-  Class->setLambdaIsGeneric(TemplateParams);
-
   TypeSourceInfo *MethodTyInfo = getLambdaType(
       *this, Intro, ParamInfo, getCurScope(), TypeLoc, ExplicitResultType);
 
-  Class->setLambdaTypeInfo(MethodTyInfo);
-  Method->setInnerLocStart(LambdaLoc);
-  Method->setLocation(Intro.Range.getBegin());
-  Method->setTypeSourceInfo(MethodTyInfo);
-  Method->setType(buildTypeForLambdaCallOperator(*this, Class, TemplateParams,
-                                                 MethodTyInfo));
-  Method->setConstexprKind(ParamInfo.getDeclSpec().getConstexprSpecifier());
-  buildLambdaScopeReturnType(*this, LSI, Method, ExplicitResultType);
-
   LSI->ExplicitParams = ParamInfo.getNumTypeObjects() != 0;
 
   if (ParamInfo.isFunctionDeclarator() != 0 &&
@@ -1359,14 +1294,15 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
     }
   }
 
-  ContextRAII ManglingContext(*this, Class->getDeclContext());
+  CompleteLambdaCallOperator(Method, Intro.Range.getBegin(), CallOperatorLoc,
+                             ParamInfo.getTrailingRequiresClause(),
+                             MethodTyInfo,
+                             ParamInfo.getDeclSpec().getConstexprSpecifier(),
+                             Params, ExplicitResultType);
 
-  CheckParmsForFunctionDef(Params, /*CheckParameterNames=*/false);
+  ContextRAII ManglingContext(*this, Class->getDeclContext());
 
-  if (LSI->ExplicitParams) {
-    Method->setParams(Params);
-    CheckCXXDefaultArguments(Method);
-  }
+  CheckCXXDefaultArguments(Method);
 
   // This represents the function body for the lambda function, check if we
   // have to apply optnone due to a pragma.

diff  --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 5460f88228821..653d531b798d0 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -12966,44 +12966,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
   LambdaScopeInfo *LSI = getSema().PushLambdaScope();
   Sema::FunctionScopeRAII FuncScopeCleanup(getSema());
 
-  // Transform the template parameters, and add them to the current
-  // instantiation scope. The null case is handled correctly.
-  auto TPL = getDerived().TransformTemplateParameterList(
-      E->getTemplateParameterList());
-  LSI->GLTemplateParameterList = TPL;
-
-  // Transform the type of the original lambda's call operator.
-  // The transformation MUST be done in the CurrentInstantiationScope since
-  // it introduces a mapping of the original to the newly created
-  // transformed parameters.
-  TypeSourceInfo *NewCallOpTSI = nullptr;
-  {
-    TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
-    FunctionProtoTypeLoc OldCallOpFPTL =
-        OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
-
-    TypeLocBuilder NewCallOpTLBuilder;
-    SmallVector<QualType, 4> ExceptionStorage;
-    TreeTransform *This = this; // Work around gcc.gnu.org/PR56135.
-    QualType NewCallOpType = TransformFunctionProtoType(
-        NewCallOpTLBuilder, OldCallOpFPTL, nullptr, Qualifiers(),
-        [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) {
-          return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI,
-                                              ExceptionStorage, Changed);
-        });
-    if (NewCallOpType.isNull())
-      return ExprError();
-    NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context,
-                                                        NewCallOpType);
-  }
-
-  // Transform the trailing requires clause
-  ExprResult NewTrailingRequiresClause;
-  if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause())
-    // FIXME: Concepts: Substitution into requires clause should only happen
-    //                  when checking satisfaction.
-    NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
-
   // Create the local class that will describe the lambda.
 
   // FIXME: DependencyKind below is wrong when substituting inside a templated
@@ -13019,10 +12981,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
     DependencyKind = CXXRecordDecl::LDK_NeverDependent;
 
   CXXRecordDecl *OldClass = E->getLambdaClass();
-  CXXRecordDecl *Class =
-      getSema().createLambdaClosureType(E->getIntroducerRange(), NewCallOpTSI,
-                                        DependencyKind, E->getCaptureDefault());
-
+  CXXRecordDecl *Class = getSema().createLambdaClosureType(
+      E->getIntroducerRange(), nullptr, DependencyKind, E->getCaptureDefault());
   getDerived().transformedLocalDecl(OldClass, {Class});
 
   Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling;
@@ -13032,35 +12992,19 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
                                OldClass->getDeviceLambdaManglingNumber(),
                                OldClass->getLambdaContextDecl());
 
-  // Build the call operator.
-  CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition(
-      Class, E->getIntroducerRange(), NewCallOpTSI,
-      E->getCallOperator()->getEndLoc(),
-      NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
-      E->getCallOperator()->getConstexprKind(),
-      NewTrailingRequiresClause.get());
-
-  LSI->CallOperator = NewCallOperator;
+  CXXMethodDecl *NewCallOperator =
+      getSema().CreateLambdaCallOperator(E->getIntroducerRange(), Class);
+  NewCallOperator->setLexicalDeclContext(getSema().CurContext);
 
-  getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
-  getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});
-
-  // Number the lambda for linkage purposes if necessary.
-  getSema().handleLambdaNumbering(Class, NewCallOperator, Mangling);
+  // Enter the scope of the lambda.
+  getSema().buildLambdaScope(LSI, NewCallOperator, E->getIntroducerRange(),
+                             E->getCaptureDefault(), E->getCaptureDefaultLoc(),
+                             E->hasExplicitParameters(), E->isMutable());
 
   // Introduce the context of the call operator.
   Sema::ContextRAII SavedContext(getSema(), NewCallOperator,
                                  /*NewThisContext*/false);
 
-  // Enter the scope of the lambda.
-  getSema().buildLambdaScope(LSI, NewCallOperator,
-                             E->getIntroducerRange(),
-                             E->getCaptureDefault(),
-                             E->getCaptureDefaultLoc(),
-                             E->hasExplicitParameters(),
-                             E->hasExplicitResultType(),
-                             E->isMutable());
-
   bool Invalid = false;
 
   // Transform captures.
@@ -13182,6 +13126,60 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
   }
   getSema().finishLambdaExplicitCaptures(LSI);
 
+  // Transform the template parameters, and add them to the current
+  // instantiation scope. The null case is handled correctly.
+  auto TPL = getDerived().TransformTemplateParameterList(
+      E->getTemplateParameterList());
+  LSI->GLTemplateParameterList = TPL;
+
+  // Transform the type of the original lambda's call operator.
+  // The transformation MUST be done in the CurrentInstantiationScope since
+  // it introduces a mapping of the original to the newly created
+  // transformed parameters.
+  TypeSourceInfo *NewCallOpTSI = nullptr;
+  {
+    TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
+    FunctionProtoTypeLoc OldCallOpFPTL =
+        OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+
+    TypeLocBuilder NewCallOpTLBuilder;
+    SmallVector<QualType, 4> ExceptionStorage;
+    TreeTransform *This = this; // Work around gcc.gnu.org/PR56135.
+    QualType NewCallOpType = TransformFunctionProtoType(
+        NewCallOpTLBuilder, OldCallOpFPTL, nullptr, Qualifiers(),
+        [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) {
+          return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI,
+                                              ExceptionStorage, Changed);
+        });
+    if (NewCallOpType.isNull())
+      return ExprError();
+    NewCallOpTSI =
+        NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
+  }
+
+  // Transform the trailing requires clause
+  ExprResult NewTrailingRequiresClause;
+  if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause())
+    // FIXME: Concepts: Substitution into requires clause should only happen
+    //                  when checking satisfaction.
+    NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
+
+  getSema().CompleteLambdaCallOperator(
+      NewCallOperator, E->getCallOperator()->getLocation(),
+      E->getCallOperator()->getInnerLocStart(), NewTrailingRequiresClause.get(),
+      NewCallOpTSI, E->getCallOperator()->getConstexprKind(),
+      NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
+      E->hasExplicitResultType());
+
+  getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
+  getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});
+
+  {
+    // Number the lambda for linkage purposes if necessary.
+    Sema::ContextRAII ManglingContext(getSema(), Class->getDeclContext());
+    getSema().handleLambdaNumbering(Class, NewCallOperator, Mangling);
+  }
+
   // FIXME: Sema's lambda-building mechanism expects us to push an expression
   // evaluation context even if we're not transforming the function body.
   getSema().PushExpressionEvaluationContext(

diff  --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
index 5f7f73d622d82..660f6091bb663 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
@@ -43,10 +43,21 @@ X infer_X_return_type_2(X x) {
   }(5);
 }
 
-struct Incomplete; // expected-note{{forward declaration of 'Incomplete'}}
+struct Incomplete; // expected-note 2{{forward declaration of 'Incomplete'}}
 void test_result_type(int N) {
   auto l1 = [] () -> Incomplete { }; // expected-error{{incomplete result type 'Incomplete' in lambda expression}}
 
   typedef int vla[N];
   auto l2 = [] () -> vla { }; // expected-error{{function cannot return array type 'vla' (aka 'int[N]')}}
 }
+
+template <typename T>
+void test_result_type_tpl(int N) {
+  auto l1 = []() -> T {}; // expected-error{{incomplete result type 'Incomplete' in lambda expression}}
+  typedef int vla[N];
+  auto l2 = []() -> vla {}; // expected-error{{function cannot return array type 'vla' (aka 'int[N]')}}
+}
+
+void test_result_type_call() {
+  test_result_type_tpl<Incomplete>(10); // expected-note {{requested here}}
+}

diff  --git a/clang/test/SemaCXX/lambda-capture-type-deduction.cpp b/clang/test/SemaCXX/lambda-capture-type-deduction.cpp
index f54f2796c73fa..ee5d872071cb7 100644
--- a/clang/test/SemaCXX/lambda-capture-type-deduction.cpp
+++ b/clang/test/SemaCXX/lambda-capture-type-deduction.cpp
@@ -163,6 +163,35 @@ void dependent(U&& u) {
   [&]() requires is_same<decltype(u), T> {}();
 }
 
+template <typename T>
+void dependent_init_capture(T x = 0) {
+  [ y = x + 1, x ]() mutable -> decltype(y + x) requires(is_same<decltype((y)), int &> && is_same<decltype((x)), int &>) {
+    return y;
+  }
+  ();
+  [ y = x + 1, x ]() -> decltype(y + x) requires(is_same<decltype((y)), const int &> && is_same<decltype((x)), const int &>) {
+    return y;
+  }
+  ();
+}
+
+template <typename T, typename...>
+struct extract_type {
+  using type = T;
+};
+
+template <typename... T>
+void dependent_variadic_capture(T... x) {
+  [... y = x, x... ](auto...) mutable -> typename extract_type<decltype(y)...>::type requires((is_same<decltype((y)), int &> && ...) && (is_same<decltype((x)), int &> && ...)) {
+    return 0;
+  }
+  (x...);
+  [... y = x, x... ](auto...) -> typename extract_type<decltype(y)...>::type requires((is_same<decltype((y)), const int &> && ...) && (is_same<decltype((x)), const int &> && ...)) {
+    return 0;
+  }
+  (x...);
+}
+
 void test_dependent() {
   int v   = 0;
   int & r = v;
@@ -170,6 +199,8 @@ void test_dependent() {
   dependent<int&>(v);
   dependent<int&>(r);
   dependent<const int&>(cr);
+  dependent_init_capture(0);
+  dependent_variadic_capture(1, 2, 3, 4);
 }
 
 void test_CWG2569_tpl(auto a) {


        


More information about the cfe-commits mailing list