[clang] 04000c2 - [clang] Implement Change scope of lambda trailing-return-type

Corentin Jabot via cfe-commits cfe-commits at lists.llvm.org
Fri Apr 15 07:50:58 PDT 2022


Author: Corentin Jabot
Date: 2022-04-15T16:50:52+02:00
New Revision: 04000c2f928a7adc32138a664d167f01b642bef3

URL: https://github.com/llvm/llvm-project/commit/04000c2f928a7adc32138a664d167f01b642bef3
DIFF: https://github.com/llvm/llvm-project/commit/04000c2f928a7adc32138a664d167f01b642bef3.diff

LOG: [clang] Implement Change scope of lambda trailing-return-type

Implement P2036R3.

Captured variables by copy (explicitely or not), are deduced
correctly at the point we know whether the lambda is mutable,
and ill-formed before that.

Up until now, the entire lambda declaration up to the start of the body would be parsed in the parent scope, such that capture would not be available to look up.

The scoping is changed to have an outer lambda scope, followed by the lambda prototype and body.

The lambda scope is necessary because there may be a template scope between the start of the lambda (to which we want to attach the captured variable) and the prototype scope.

We also need to introduce a declaration context to attach the captured variable to (and several parts of clang assume captures are handled from the call operator context), before we know the type of the call operator.

The order of operations is as follow:

* Parse the init capture in the lambda's parent scope

* Introduce a lambda scope

* Create the lambda class and call operator

* Add the init captures to the call operator context and the lambda scope. But the variables are not capured yet (because we don't know their type).
Instead, explicit  captures are stored in a temporary map that conserves the order of capture (for the purpose of having a stable order in the ast dumps).

* A flag is set on LambdaScopeInfo to indicate that we have not yet injected the captures.

* The parameters are parsed (in the parent context, as lambda mangling recurses in the parent context, we couldn't mangle a lambda that is attached to the context of a lambda whose type is not yet known).

* The lambda qualifiers are parsed, at this point We can switch (for the second time) inside the lambda context, unset the flag indicating that we have not parsed the lambda qualifiers,
record the lambda is mutable and capture the explicit variables.

* We can parse the rest of the lambda type, transform the lambda and call operator's types and also transform the call operator to a template function decl where necessary.

At this point, both captures and parameters can be injected in the body's scope. When trying to capture an implicit variable, if we are before the qualifiers of a lambda, we need to remember that the variables are still in the parent's context (rather than in the call operator's).

Reviewed By: aaron.ballman, #clang-language-wg, ChuanqiXu

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

Added: 
    clang/test/SemaCXX/lambda-capture-type-deduction.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/AST/DeclCXX.h
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Parse/Parser.h
    clang/include/clang/Sema/Scope.h
    clang/include/clang/Sema/ScopeInfo.h
    clang/include/clang/Sema/Sema.h
    clang/lib/Parse/ParseExprCXX.cpp
    clang/lib/Sema/Scope.cpp
    clang/lib/Sema/Sema.cpp
    clang/lib/Sema/SemaCXXScopeSpec.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/lib/Sema/SemaExprCXX.cpp
    clang/lib/Sema/SemaLambda.cpp
    clang/lib/Sema/TreeTransform.h
    clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
    clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
    clang/www/cxx_status.html

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2497280dfdd6d..c72028c718586 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -255,6 +255,9 @@ C++2b Feature Support
 - Implemented `P2128R6: Multidimensional subscript operator <https://wg21.link/P2128R6>`_.
 - Implemented `P0849R8: auto(x): decay-copy in the language <https://wg21.link/P0849R8>`_.
 - Implemented `P2242R3: Non-literal variables (and labels and gotos) in constexpr functions	<https://wg21.link/P2242R3>`_.
+- Implemented `P2036R3: Change scope of lambda trailing-return-type <https://wg21.link/P2036R3>`_.
+  This proposal modifies how variables captured in lambdas can appear in trailing return type
+  expressions and how their types are deduced therein, in all C++ language versions.
 
 CUDA Language Changes in Clang
 ------------------------------

diff  --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 04a9daa14e05e..c640f7f7ba63f 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1799,6 +1799,20 @@ class CXXRecordDecl : public RecordDecl {
     return getLambdaData().MethodTyInfo;
   }
 
+  void setLambdaTypeInfo(TypeSourceInfo *TS) {
+    auto *DD = DefinitionData;
+    assert(DD && DD->IsLambda && "setting lambda property of non-lambda class");
+    auto &DL = static_cast<LambdaDefinitionData &>(*DD);
+    DL.MethodTyInfo = TS;
+  }
+
+  void setLambdaIsGeneric(bool IsGeneric) {
+    auto *DD = DefinitionData;
+    assert(DD && DD->IsLambda && "setting lambda property of non-lambda class");
+    auto &DL = static_cast<LambdaDefinitionData &>(*DD);
+    DL.IsGenericLambda = IsGeneric;
+  }
+
   // Determine whether this type is an Interface Like type for
   // __interface inheritance purposes.
   bool isInterfaceLike() const;

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6547002b378f2..a14194d271a71 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7710,6 +7710,8 @@ let CategoryName = "Lambda Issue" in {
   def err_lambda_impcap : Error<
     "variable %0 cannot be implicitly captured in a lambda with no "
     "capture-default specified">;
+  def err_lambda_used_before_capture: Error<
+    "captured variable %0 cannot appear here">;
   def note_lambda_variable_capture_fixit : Note<
     "capture %0 by %select{value|reference}1">;
   def note_lambda_default_capture_fixit : Note<

diff  --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 8f28eb30ad1dc..3046962dddec4 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1901,6 +1901,8 @@ class Parser : public CodeCompletionHandler {
   ParseLambdaIntroducer(LambdaIntroducer &Intro,
                         LambdaIntroducerTentativeParse *Tentative = nullptr);
   ExprResult ParseLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro);
+  void ParseLambdaLexedGNUAttributeArgs(LateParsedAttribute &LA,
+                                        ParsedAttributes &Attrs, Declarator &D);
 
   //===--------------------------------------------------------------------===//
   // C++ 5.2p1: C++ Casts

diff  --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h
index 872951a0829b4..5a2d51b63d909 100644
--- a/clang/include/clang/Sema/Scope.h
+++ b/clang/include/clang/Sema/Scope.h
@@ -44,11 +44,11 @@ class Scope {
   enum ScopeFlags {
     /// This indicates that the scope corresponds to a function, which
     /// means that labels are set here.
-    FnScope       = 0x01,
+    FnScope = 0x01,
 
     /// This is a while, do, switch, for, etc that can have break
     /// statements embedded into it.
-    BreakScope    = 0x02,
+    BreakScope = 0x02,
 
     /// This is a while, do, for, which can have continue statements
     /// embedded into it.
@@ -140,6 +140,12 @@ class Scope {
     /// parsed. If such a scope is a ContinueScope, it's invalid to jump to the
     /// continue block from here.
     ConditionVarScope = 0x2000000,
+
+    /// This is the scope for a lambda, after the lambda introducer.
+    /// Lambdas need 2 FunctionPrototypeScope scopes (because there is a
+    /// template scope in between), the outer scope does not increase the
+    /// depth of recursion.
+    LambdaScope = 0x4000000,
   };
 
 private:

diff  --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index 08bf53d22f8a4..11a9fdc513da9 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -831,6 +831,28 @@ class LambdaScopeInfo final :
   /// The lambda's compiler-generated \c operator().
   CXXMethodDecl *CallOperator = nullptr;
 
+  struct DelayedCapture {
+    VarDecl *Var;
+    SourceLocation Loc;
+    LambdaCaptureKind Kind;
+  };
+
+  /// Holds the captures until we parsed the qualifiers, as the cv qualified
+  /// type of captures can only be computed at that point, and the captures
+  /// should not be visible before.
+  /// The index represents the position in the original capture list.
+  /// We use a map as not all index represents captures (defaults), or are
+  /// captured (some captures are invalid).
+  llvm::DenseMap<unsigned, DelayedCapture> DelayedCaptures;
+
+  /// Whether the current scope when parsing the lambda
+  /// is after the call operator qualifiers,
+  /// which is the point at which the captures are usable
+  /// per [expr.prim.id.unqual]/p3.2 and [expr.prim.lambda.capture]/6.
+  /// This is set to false by default as the lambda can be reconstructed during
+  /// instantiation
+  bool BeforeLambdaQualifiersScope = false;
+
   /// Source range covering the lambda introducer [...].
   SourceRange IntroducerRange;
 

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index fae0ca1fa1e09..95ce074fdccd3 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6852,11 +6852,9 @@ class Sema final {
   ///
   ///  CodeGen handles emission of lambda captures, ignoring these dummy
   ///  variables appropriately.
-  VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc,
-                                          QualType InitCaptureType,
-                                          SourceLocation EllipsisLoc,
-                                          IdentifierInfo *Id,
-                                          unsigned InitStyle, Expr *Init);
+  VarDecl *createLambdaInitCaptureVarDecl(
+      SourceLocation Loc, QualType InitCaptureType, SourceLocation EllipsisLoc,
+      IdentifierInfo *Id, unsigned InitStyle, Expr *Init, DeclContext *DeclCtx);
 
   /// Add an init-capture to a lambda scope.
   void addInitCapture(sema::LambdaScopeInfo *LSI, VarDecl *Var);
@@ -6865,21 +6863,29 @@ class Sema final {
   /// given lambda.
   void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
 
-  /// \brief This is called after parsing the explicit template parameter list
+  /// Deduce a block or lambda's return type based on the return
+  /// statements present in the body.
+  void deduceClosureReturnType(sema::CapturingScopeInfo &CSI);
+
+  /// Once the Lambdas capture are known, we can
+  /// start to create the closure, call operator method,
+  /// and keep track of the captures.
+  /// We do the capture lookup here, but they are not actually captured
+  /// until after we know what the qualifiers of the call operator are.
+  void ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurContext);
+
+  /// This is called after parsing the explicit template parameter list
   /// on a lambda (if it exists) in C++2a.
-  void ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
+  void ActOnLambdaExplicitTemplateParameterList(LambdaIntroducer &Intro,
+                                                SourceLocation LAngleLoc,
                                                 ArrayRef<NamedDecl *> TParams,
                                                 SourceLocation RAngleLoc,
                                                 ExprResult RequiresClause);
 
-  /// Introduce the lambda parameters into scope.
-  void addLambdaParameters(
-      ArrayRef<LambdaIntroducer::LambdaCapture> Captures,
-      CXXMethodDecl *CallOperator, Scope *CurScope);
-
-  /// Deduce a block or lambda's return type based on the return
-  /// statements present in the body.
-  void deduceClosureReturnType(sema::CapturingScopeInfo &CSI);
+  void ActOnLambdaClosureQualifiers(
+      LambdaIntroducer &Intro, SourceLocation MutableLoc, SourceLocation EndLoc,
+      MutableArrayRef<DeclaratorChunk::ParamInfo> ParamInfo,
+      const DeclSpec &DS);
 
   /// ActOnStartOfLambdaDefinition - This is called just before we start
   /// parsing the body of a lambda; it analyzes the explicit captures and

diff  --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 7b66f6c46339a..b03d4e3a90acb 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1231,6 +1231,36 @@ static void addConstevalToLambdaDeclSpecifier(Parser &P,
   }
 }
 
+void Parser::ParseLambdaLexedGNUAttributeArgs(LateParsedAttribute &LA,
+                                              ParsedAttributes &Attrs,
+                                              Declarator &D) {
+  // Create a fake EOF so that attribute parsing won't go off the end of the
+  // attribute.
+  Token AttrEnd;
+  AttrEnd.startToken();
+  AttrEnd.setKind(tok::eof);
+  AttrEnd.setLocation(Tok.getLocation());
+  AttrEnd.setEofData(LA.Toks.data());
+  LA.Toks.push_back(AttrEnd);
+  // Append the current token at the end of the new token stream so that it
+  // doesn't get lost.
+  LA.Toks.push_back(Tok);
+  PP.EnterTokenStream(LA.Toks, true, /*IsReinject=*/true);
+  // Consume the previously pushed token.
+  ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+
+  ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, nullptr, nullptr,
+                        SourceLocation(), ParsedAttr::AS_GNU, &D);
+  // After parsing attribute arguments, we've either reached the EOF token
+  // (signaling that parsing was successful) or we have tokens we need to
+  // consume until we reach the EOF.
+  while (Tok.isNot(tok::eof))
+    ConsumeAnyToken();
+
+  assert(Tok.is(tok::eof));
+  ConsumeAnyToken();
+}
+
 /// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda
 /// expression.
 ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
@@ -1250,9 +1280,15 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
   DeclSpec DS(AttrFactory);
   Declarator D(DS, DeclaratorContext::LambdaExpr);
   TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+
+  ParseScope LambdaScope(this, Scope::LambdaScope | Scope::DeclScope |
+                                   Scope::FunctionDeclarationScope |
+                                   Scope::FunctionPrototypeScope);
+
   Actions.PushLambdaScope();
+  Actions.ActOnLambdaIntroducer(Intro, getCurScope());
 
-  ParsedAttributes Attr(AttrFactory);
+  ParsedAttributes Attributes(AttrFactory);
   if (getLangOpts().CUDA) {
     // In CUDA code, GNU attributes are allowed to appear immediately after the
     // "[...]", even if there is no "(...)" before the lambda body.
@@ -1263,7 +1299,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
   // after '(...)'. nvcc doesn't accept this.
   auto WarnIfHasCUDATargetAttr = [&] {
     if (getLangOpts().CUDA)
-      for (const ParsedAttr &A : Attr)
+      for (const ParsedAttr &A : Attributes)
         if (A.getKind() == ParsedAttr::AT_CUDADevice ||
             A.getKind() == ParsedAttr::AT_CUDAHost ||
             A.getKind() == ParsedAttr::AT_CUDAGlobal)
@@ -1300,7 +1336,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
       }
 
       Actions.ActOnLambdaExplicitTemplateParameterList(
-          LAngleLoc, TemplateParams, RAngleLoc, RequiresClause);
+          Intro, LAngleLoc, TemplateParams, RAngleLoc, RequiresClause);
       ++CurTemplateDepthTracker;
     }
   }
@@ -1318,28 +1354,39 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
 
   TypeResult TrailingReturnType;
   SourceLocation TrailingReturnTypeLoc;
+  SourceLocation LParenLoc, RParenLoc;
+  SourceLocation DeclEndLoc;
+  bool HasParentheses = false;
+  bool HasSpecifiers = false;
+  SourceLocation MutableLoc;
+  LateParsedAttrList LateParsedAttrs(true);
+
+  auto ParseConstexprAndMutableSpecifiers = [&] {
+    // GNU-style attributes must be parsed before the mutable specifier to
+    // be compatible with GCC. MSVC-style attributes must be parsed before
+    // the mutable specifier to be compatible with MSVC.
+    // However, because GNU attributes could refer to captured variables,
+    // which only become visible after the mutable keyword is parsed
+    // we delay the parsing of gnu attributes - by reusing the mechanism used
+    // for C++ late method parsing. Note, __declspec attributes do not make
+    // use of late parsing (expressions cannot appear in __declspec arguments),
+    // so only GNU style attributes are affected here.
+    MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attributes,
+                         &LateParsedAttrs);
+    // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update
+    // the DeclEndLoc.
+    SourceLocation ConstexprLoc;
+    SourceLocation ConstevalLoc;
+    tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
+                                   ConstevalLoc, DeclEndLoc);
+
+    addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
+    addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
+  };
 
   auto ParseLambdaSpecifiers =
-      [&](SourceLocation LParenLoc, SourceLocation RParenLoc,
-          MutableArrayRef<DeclaratorChunk::ParamInfo> ParamInfo,
+      [&](MutableArrayRef<DeclaratorChunk::ParamInfo> ParamInfo,
           SourceLocation EllipsisLoc) {
-        SourceLocation DeclEndLoc = RParenLoc;
-
-        // GNU-style attributes must be parsed before the mutable specifier to
-        // be compatible with GCC. MSVC-style attributes must be parsed before
-        // the mutable specifier to be compatible with MSVC.
-        MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr);
-
-        // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update
-        // the DeclEndLoc.
-        SourceLocation MutableLoc;
-        SourceLocation ConstexprLoc;
-        SourceLocation ConstevalLoc;
-        tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
-                                       ConstevalLoc, DeclEndLoc);
-
-        addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
-        addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
         // Parse exception-specification[opt].
         ExceptionSpecificationType ESpecType = EST_None;
         SourceRange ESpecRange;
@@ -1347,6 +1394,15 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
         SmallVector<SourceRange, 2> DynamicExceptionRanges;
         ExprResult NoexceptExpr;
         CachedTokens *ExceptionSpecTokens;
+
+        // At this point we know whether the lambda is mutable so we can
+        // complete the parsing of gnu attributes.
+        for (LateParsedAttribute *Attr : LateParsedAttrs) {
+          ParseLambdaLexedGNUAttributeArgs(*Attr, Attributes, D);
+          delete Attr;
+        }
+        LateParsedAttrs.clear();
+
         ESpecType = tryParseExceptionSpecification(
             /*Delayed=*/false, ESpecRange, DynamicExceptions,
             DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens);
@@ -1355,8 +1411,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
           DeclEndLoc = ESpecRange.getEnd();
 
         // Parse attribute-specifier[opt].
-        if (MaybeParseCXX11Attributes(Attr))
-          DeclEndLoc = Attr.Range.getEnd();
+        if (MaybeParseCXX11Attributes(Attributes))
+          DeclEndLoc = Attributes.Range.getEnd();
 
         // Parse OpenCL addr space attribute.
         if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local,
@@ -1392,27 +1448,29 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
                 /*ExceptionSpecTokens*/ nullptr,
                 /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D,
                 TrailingReturnType, TrailingReturnTypeLoc, &DS),
-            std::move(Attr), DeclEndLoc);
+            std::move(Attributes), DeclEndLoc);
+
+        if (HasParentheses && Tok.is(tok::kw_requires))
+          ParseTrailingRequiresClause(D);
       };
 
-  if (Tok.is(tok::l_paren)) {
-    ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
-                                        Scope::FunctionDeclarationScope |
-                                        Scope::DeclScope);
+  ParseScope Prototype(this, Scope::FunctionPrototypeScope |
+                                 Scope::FunctionDeclarationScope |
+                                 Scope::DeclScope);
 
+  // Parse parameter-declaration-clause.
+  SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+  SourceLocation EllipsisLoc;
+  if (Tok.is(tok::l_paren)) {
     BalancedDelimiterTracker T(*this, tok::l_paren);
     T.consumeOpen();
-    SourceLocation LParenLoc = T.getOpenLocation();
-
-    // Parse parameter-declaration-clause.
-    SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
-    SourceLocation EllipsisLoc;
+    LParenLoc = T.getOpenLocation();
 
     if (Tok.isNot(tok::r_paren)) {
       Actions.RecordParsingTemplateParameterDepth(
           CurTemplateDepthTracker.getOriginalDepth());
 
-      ParseParameterDeclarationClause(D.getContext(), Attr, ParamInfo,
+      ParseParameterDeclarationClause(D.getContext(), Attributes, ParamInfo,
                                       EllipsisLoc);
       // For a generic lambda, each 'auto' within the parameter declaration
       // clause creates a template type parameter, so increment the depth.
@@ -1424,36 +1482,40 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
     }
 
     T.consumeClose();
+    DeclEndLoc = RParenLoc = T.getCloseLocation();
+    HasParentheses = true;
+  }
 
-    // Parse lambda-specifiers.
-    ParseLambdaSpecifiers(LParenLoc, /*DeclEndLoc=*/T.getCloseLocation(),
-                          ParamInfo, EllipsisLoc);
-
-    // Parse requires-clause[opt].
-    if (Tok.is(tok::kw_requires))
-      ParseTrailingRequiresClause(D);
-  } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute,
-                         tok::kw_constexpr, tok::kw_consteval,
-                         tok::kw___private, tok::kw___global, tok::kw___local,
-                         tok::kw___constant, tok::kw___generic,
-                         tok::kw_requires, tok::kw_noexcept) ||
-             (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
-    if (!getLangOpts().CPlusPlus2b)
+  // MSVC doesn't support [] __declspec(...) {}, so we do not check for it here.
+  if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute,
+                  tok::kw_constexpr, tok::kw_consteval, tok::kw___private,
+                  tok::kw___global, tok::kw___local, tok::kw___constant,
+                  tok::kw___generic, tok::kw_requires, tok::kw_noexcept) ||
+      (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
+    HasSpecifiers = true;
+    if (!HasParentheses && !getLangOpts().CPlusPlus2b) {
       // It's common to forget that one needs '()' before 'mutable', an
       // attribute specifier, the result type, or the requires clause. Deal with
       // this.
       Diag(Tok, diag::ext_lambda_missing_parens)
           << FixItHint::CreateInsertion(Tok.getLocation(), "() ");
+    }
+  }
 
-    SourceLocation NoLoc;
-    // Parse lambda-specifiers.
-    std::vector<DeclaratorChunk::ParamInfo> EmptyParamInfo;
-    ParseLambdaSpecifiers(/*LParenLoc=*/NoLoc, /*RParenLoc=*/NoLoc,
-                          EmptyParamInfo, /*EllipsisLoc=*/NoLoc);
+  if (HasParentheses || HasSpecifiers) {
+    ParseConstexprAndMutableSpecifiers();
   }
 
+  Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc, DeclEndLoc, ParamInfo,
+                                       DS);
+
+  if (HasSpecifiers || HasParentheses || !LateParsedAttrs.empty())
+    ParseLambdaSpecifiers(ParamInfo, EllipsisLoc);
+
   WarnIfHasCUDATargetAttr();
 
+  Prototype.Exit();
+
   // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
   // it.
   unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope |
@@ -1472,6 +1534,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
   StmtResult Stmt(ParseCompoundStatementBody());
   BodyScope.Exit();
   TemplateParamScope.Exit();
+  LambdaScope.Exit();
 
   if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid())
     return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope());

diff  --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index 499279a2659dd..00519c132a6a4 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -67,8 +67,10 @@ void Scope::setFlags(Scope *parent, unsigned flags) {
   if (flags & BlockScope)         BlockParent = this;
   if (flags & TemplateParamScope) TemplateParamParent = this;
 
-  // If this is a prototype scope, record that.
-  if (flags & FunctionPrototypeScope) PrototypeDepth++;
+  // If this is a prototype scope, record that. Lambdas have an extra prototype
+  // scope that doesn't add any depth.
+  if (flags & FunctionPrototypeScope && !(flags & LambdaScope))
+    PrototypeDepth++;
 
   if (flags & DeclScope) {
     if (flags & FunctionPrototypeScope)

diff  --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index ce104f377730c..4f86a06e820ae 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -2297,7 +2297,8 @@ FunctionScopeInfo *Sema::getEnclosingFunction() const {
 LambdaScopeInfo *Sema::getEnclosingLambda() const {
   for (auto *Scope : llvm::reverse(FunctionScopes)) {
     if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Scope)) {
-      if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext)) {
+      if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext) &&
+          !LSI->BeforeLambdaQualifiersScope) {
         // We have switched contexts due to template instantiation.
         // FIXME: We should swap out the FunctionScopes during code synthesis
         // so that we don't need to check for this.
@@ -2323,8 +2324,9 @@ LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) {
       return nullptr;
   }
   auto *CurLSI = dyn_cast<LambdaScopeInfo>(*I);
-  if (CurLSI && CurLSI->Lambda &&
-      !CurLSI->Lambda->Encloses(CurContext)) {
+  if (CurLSI && CurLSI->Lambda && CurLSI->CallOperator &&
+      !CurLSI->Lambda->Encloses(CurContext) &&
+      !CurLSI->BeforeLambdaQualifiersScope) {
     // We have switched contexts due to template instantiation.
     assert(!CodeSynthesisContexts.empty());
     return nullptr;

diff  --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 4781d71080c98..f7e8ebd6e203f 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -292,6 +292,11 @@ bool Sema::ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc,
 bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc,
                                     SourceLocation ColonColonLoc,
                                     CXXScopeSpec &SS) {
+  if (getCurLambda()) {
+    Diag(SuperLoc, diag::err_super_in_lambda_unsupported);
+    return true;
+  }
+
   CXXRecordDecl *RD = nullptr;
   for (Scope *S = getCurScope(); S; S = S->getParent()) {
     if (S->isFunctionScope()) {
@@ -308,9 +313,6 @@ bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc,
   if (!RD) {
     Diag(SuperLoc, diag::err_invalid_super_scope);
     return true;
-  } else if (RD->isLambda()) {
-    Diag(SuperLoc, diag::err_super_in_lambda_unsupported);
-    return true;
   } else if (RD->getNumBases() == 0) {
     Diag(SuperLoc, diag::err_no_base_classes) << RD->getName();
     return true;

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 37e54a8603f15..334ece62c2bea 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3385,7 +3385,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
     // FIXME: Support lambda-capture of BindingDecls, once CWG actually
     // decides how that's supposed to work.
     auto *BD = cast<BindingDecl>(VD);
-    if (BD->getDeclContext() != CurContext) {
+    if (BD->getDeclContext() != CurContext && !isUnevaluatedContext()) {
       auto *DD = dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl());
       if (DD && DD->hasLocalStorage())
         diagnoseUncapturableValueReference(*this, Loc, BD);
@@ -18542,6 +18542,37 @@ static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI,
   }
 }
 
+static bool CheckCaptureUseBeforeLambdaQualifiers(Sema &S, VarDecl *Var,
+                                                  SourceLocation ExprLoc,
+                                                  LambdaScopeInfo *LSI) {
+  if (Var->isInvalidDecl())
+    return false;
+
+  bool ByCopy = LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByval;
+  SourceLocation Loc = LSI->IntroducerRange.getBegin();
+  bool Explicitly = false;
+  for (auto &&C : LSI->DelayedCaptures) {
+    VarDecl *CV = C.second.Var;
+    if (Var != CV)
+      continue;
+    ByCopy = C.second.Kind == LambdaCaptureKind::LCK_ByCopy;
+    Loc = C.second.Loc;
+    Explicitly = true;
+    break;
+  }
+  if (ByCopy && LSI->BeforeLambdaQualifiersScope) {
+    // This can only occur in a non-ODR context, so we need to diagnose eagerly,
+    // even when BuildAndDiagnose is false
+    S.Diag(ExprLoc, diag::err_lambda_used_before_capture) << Var;
+    S.Diag(Loc, diag::note_var_explicitly_captured_here) << Var << Explicitly;
+    if (!Var->isInitCapture())
+      S.Diag(Var->getBeginLoc(), diag::note_entity_declared_at) << Var;
+    Var->setInvalidDecl();
+    return false;
+  }
+  return true;
+}
+
 bool Sema::tryCaptureVariable(
     VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
     SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType,
@@ -18565,11 +18596,6 @@ bool Sema::tryCaptureVariable(
     }
   }
 
-
-  // If the variable is declared in the current context, there is no need to
-  // capture it.
-  if (VarDC == DC) return true;
-
   // Capture global variables if it is required to use private copy of this
   // variable.
   bool IsGlobal = !Var->hasLocalStorage();
@@ -18592,13 +18618,36 @@ bool Sema::tryCaptureVariable(
   bool Nested = false;
   bool Explicit = (Kind != TryCapture_Implicit);
   unsigned FunctionScopesIndex = MaxFunctionScopesIndex;
+  bool IsInLambdaBeforeQualifiers;
   do {
+    IsInLambdaBeforeQualifiers = false;
+
+    LambdaScopeInfo *LSI = nullptr;
+    if (!FunctionScopes.empty())
+      LSI = dyn_cast_or_null<LambdaScopeInfo>(
+          FunctionScopes[FunctionScopesIndex]);
+    if (LSI && LSI->BeforeLambdaQualifiersScope) {
+      if (isa<ParmVarDecl>(Var))
+        return true;
+      IsInLambdaBeforeQualifiers = true;
+      if (!CheckCaptureUseBeforeLambdaQualifiers(*this, Var, ExprLoc, LSI)) {
+        break;
+      }
+    }
+
+    // If the variable is declared in the current context, there is no need to
+    // capture it.
+    if (!IsInLambdaBeforeQualifiers &&
+        FunctionScopesIndex == MaxFunctionScopesIndex && VarDC == DC)
+      return true;
+
     // Only block literals, captured statements, and lambda expressions can
     // capture; other scopes don't work.
-    DeclContext *ParentDC = getParentOfCapturingContextOrNull(DC, Var,
-                                                              ExprLoc,
-                                                              BuildAndDiagnose,
-                                                              *this);
+    DeclContext *ParentDC =
+        IsInLambdaBeforeQualifiers
+            ? DC->getParent()
+            : getParentOfCapturingContextOrNull(DC, Var, ExprLoc,
+                                                BuildAndDiagnose, *this);
     // We need to check for the parent *first* because, if we *have*
     // private-captured a global variable, we need to recursively capture it in
     // intermediate blocks, lambdas, etc.
@@ -18613,9 +18662,9 @@ bool Sema::tryCaptureVariable(
     FunctionScopeInfo  *FSI = FunctionScopes[FunctionScopesIndex];
     CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FSI);
 
-
     // Check whether we've already captured it.
-    if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
+    if (!IsInLambdaBeforeQualifiers &&
+        isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
                                              DeclRefType)) {
       CSI->getCapture(Var).markUsed(BuildAndDiagnose);
       break;
@@ -18624,7 +18673,8 @@ bool Sema::tryCaptureVariable(
     // we do not want to capture new variables.  What was captured
     // during either a lambdas transformation or initial parsing
     // should be used.
-    if (isGenericLambdaCallOperatorSpecialization(DC)) {
+    if (!IsInLambdaBeforeQualifiers &&
+        isGenericLambdaCallOperatorSpecialization(DC)) {
       if (BuildAndDiagnose) {
         LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
         if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {
@@ -18639,7 +18689,8 @@ bool Sema::tryCaptureVariable(
     }
 
     // Try to capture variable-length arrays types.
-    if (Var->getType()->isVariablyModifiedType()) {
+    if (!IsInLambdaBeforeQualifiers &&
+        Var->getType()->isVariablyModifiedType()) {
       // We're going to walk down into the type and look for VLA
       // expressions.
       QualType QTy = Var->getType();
@@ -18648,7 +18699,7 @@ bool Sema::tryCaptureVariable(
       captureVariablyModifiedType(Context, QTy, CSI);
     }
 
-    if (getLangOpts().OpenMP) {
+    if (!IsInLambdaBeforeQualifiers && getLangOpts().OpenMP) {
       if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
         // OpenMP private variables should not be captured in outer scope, so
         // just break here. Similarly, global variables that are captured in a
@@ -18729,11 +18780,11 @@ bool Sema::tryCaptureVariable(
       }
       return true;
     }
-
-    FunctionScopesIndex--;
-    DC = ParentDC;
     Explicit = false;
-  } while (!VarDC->Equals(DC));
+    FunctionScopesIndex--;
+    if (!IsInLambdaBeforeQualifiers)
+      DC = ParentDC;
+  } while (IsInLambdaBeforeQualifiers || !VarDC->Equals(DC));
 
   // Walk back down the scope stack, (e.g. from outer lambda to inner lambda)
   // computing the type of the capture at each step, checking type-specific
@@ -18768,6 +18819,9 @@ bool Sema::tryCaptureVariable(
       Nested = true;
     } else {
       LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
+      if (!CheckCaptureUseBeforeLambdaQualifiers(*this, Var, ExprLoc, LSI)) {
+        return true;
+      }
       Invalid =
           !captureInLambda(LSI, Var, ExprLoc, BuildAndDiagnose, CaptureType,
                            DeclRefType, Nested, Kind, EllipsisLoc,

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f360dc6e1a236..aad9574e9e694 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1130,7 +1130,7 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda(
 
     if (C.isCopyCapture()) {
       ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask);
-      if (CurLSI->CallOperator->isConst())
+      if (!CurLSI->Mutable)
         ClassType.addConst();
       return ASTCtx.getPointerType(ClassType);
     }

diff  --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index c0b2fad530c5c..d5918a28d9f06 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -245,8 +245,9 @@ Sema::createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info,
   DeclContext *DC = CurContext;
   while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
     DC = DC->getParent();
-  bool IsGenericLambda = getGenericLambdaTemplateParameterList(getCurLambda(),
-                                                               *this);
+
+  bool IsGenericLambda =
+      Info && getGenericLambdaTemplateParameterList(getCurLambda(), *this);
   // Start constructing the lambda class.
   CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(
       Context, DC, Info, IntroducerRange.getBegin(), LambdaDependencyKind,
@@ -354,16 +355,13 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
   llvm_unreachable("unexpected context");
 }
 
-CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
-                                           SourceRange IntroducerRange,
-                                           TypeSourceInfo *MethodTypeInfo,
-                                           SourceLocation EndLoc,
-                                           ArrayRef<ParmVarDecl *> Params,
-                                           ConstexprSpecKind ConstexprKind,
-                                           Expr *TrailingRequiresClause) {
+static QualType
+buildTypeForLambdaCallOperator(Sema &S, clang::CXXRecordDecl *Class,
+                               TemplateParameterList *TemplateParams,
+                               TypeSourceInfo *MethodTypeInfo) {
+  assert(MethodTypeInfo && "expected a non null type");
+
   QualType MethodType = MethodTypeInfo->getType();
-  TemplateParameterList *TemplateParams =
-      getGenericLambdaTemplateParameterList(getCurLambda(), *this);
   // If a lambda appears in a dependent context or is a generic lambda (has
   // template parameters) and has an 'auto' return type, deduce it to a
   // dependent type.
@@ -371,19 +369,43 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
     const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>();
     QualType Result = FPT->getReturnType();
     if (Result->isUndeducedType()) {
-      Result = SubstAutoTypeDependent(Result);
-      MethodType = Context.getFunctionType(Result, FPT->getParamTypes(),
-                                           FPT->getExtProtoInfo());
+      Result = S.SubstAutoTypeDependent(Result);
+      MethodType = S.Context.getFunctionType(Result, FPT->getParamTypes(),
+                                             FPT->getExtProtoInfo());
     }
   }
+  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
+  //   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);
+  DeclarationName MethodName =
+      Context.DeclarationNames.getCXXOperatorName(OO_Call);
   DeclarationNameLoc MethodNameLoc =
       DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange);
   CXXMethodDecl *Method = CXXMethodDecl::Create(
@@ -400,11 +422,11 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
   // 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;
+  FunctionTemplateDecl *const TemplateMethod =
+      TemplateParams
+          ? FunctionTemplateDecl::Create(Context, Class, Method->getLocation(),
+                                         MethodName, TemplateParams, Method)
+          : nullptr;
   if (TemplateMethod) {
     TemplateMethod->setAccess(AS_public);
     Method->setDescribedFunctionTemplate(TemplateMethod);
@@ -480,14 +502,27 @@ void Sema::handleLambdaNumbering(
   }
 }
 
-void Sema::buildLambdaScope(LambdaScopeInfo *LSI,
-                                        CXXMethodDecl *CallOperator,
-                                        SourceRange IntroducerRange,
-                                        LambdaCaptureDefault CaptureDefault,
-                                        SourceLocation CaptureDefaultLoc,
-                                        bool ExplicitParams,
-                                        bool ExplicitResultType,
-                                        bool Mutable) {
+static void buildLambdaScopeReturnType(Sema &S, LambdaScopeInfo *LSI,
+                                       CXXMethodDecl *CallOperator,
+                                       bool ExplicitResultType) {
+  if (ExplicitResultType) {
+    LSI->HasImplicitReturnType = false;
+    LSI->ReturnType = CallOperator->getReturnType();
+    if (!LSI->ReturnType->isDependentType() && !LSI->ReturnType->isVoidType()) {
+      S.RequireCompleteType(CallOperator->getBeginLoc(), LSI->ReturnType,
+                            diag::err_lambda_incomplete_result);
+    }
+  } else {
+    LSI->HasImplicitReturnType = true;
+  }
+}
+
+static void buildLambdaScopeCaptures(LambdaScopeInfo *LSI,
+                                     CXXMethodDecl *CallOperator,
+                                     SourceRange IntroducerRange,
+                                     LambdaCaptureDefault CaptureDefault,
+                                     SourceLocation CaptureDefaultLoc,
+                                     bool ExplicitParams, bool Mutable) {
   LSI->CallOperator = CallOperator;
   CXXRecordDecl *LambdaClass = CallOperator->getParent();
   LSI->Lambda = LambdaClass;
@@ -499,30 +534,27 @@ void Sema::buildLambdaScope(LambdaScopeInfo *LSI,
   LSI->IntroducerRange = IntroducerRange;
   LSI->ExplicitParams = ExplicitParams;
   LSI->Mutable = Mutable;
+}
 
-  if (ExplicitResultType) {
-    LSI->ReturnType = CallOperator->getReturnType();
-
-    if (!LSI->ReturnType->isDependentType() &&
-        !LSI->ReturnType->isVoidType()) {
-      if (RequireCompleteType(CallOperator->getBeginLoc(), LSI->ReturnType,
-                              diag::err_lambda_incomplete_result)) {
-        // Do nothing.
-      }
-    }
-  } else {
-    LSI->HasImplicitReturnType = true;
-  }
+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();
 }
 
-void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
-                                                    ArrayRef<NamedDecl *> TParams,
-                                                    SourceLocation RAngleLoc,
-                                                    ExprResult RequiresClause) {
+void Sema::ActOnLambdaExplicitTemplateParameterList(
+    LambdaIntroducer &Intro, SourceLocation LAngleLoc,
+    ArrayRef<NamedDecl *> TParams, SourceLocation RAngleLoc,
+    ExprResult RequiresClause) {
   LambdaScopeInfo *LSI = getCurLambda();
   assert(LSI && "Expected a lambda scope");
   assert(LSI->NumExplicitTemplateParams == 0 &&
@@ -538,35 +570,6 @@ void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
   LSI->RequiresClause = RequiresClause;
 }
 
-void Sema::addLambdaParameters(
-    ArrayRef<LambdaIntroducer::LambdaCapture> Captures,
-    CXXMethodDecl *CallOperator, Scope *CurScope) {
-  // Introduce our parameters into the function scope
-  for (unsigned p = 0, NumParams = CallOperator->getNumParams();
-       p < NumParams; ++p) {
-    ParmVarDecl *Param = CallOperator->getParamDecl(p);
-
-    // If this has an identifier, add it to the scope stack.
-    if (CurScope && Param->getIdentifier()) {
-      bool Error = false;
-      // Resolution of CWG 2211 in C++17 renders shadowing ill-formed, but we
-      // retroactively apply it.
-      for (const auto &Capture : Captures) {
-        if (Capture.Id == Param->getIdentifier()) {
-          Error = true;
-          Diag(Param->getLocation(), diag::err_parameter_shadow_capture);
-          Diag(Capture.Loc, diag::note_var_explicitly_captured_here)
-              << Capture.Id << true;
-        }
-      }
-      if (!Error)
-        CheckShadow(CurScope, Param);
-
-      PushOnScopeChains(Param, CurScope);
-    }
-  }
-}
-
 /// If this expression is an enumerator-like expression of some type
 /// T, return the type T; otherwise, return null.
 ///
@@ -853,11 +856,9 @@ QualType Sema::buildLambdaInitCaptureInitialization(
   return DeducedType;
 }
 
-VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
-                                              QualType InitCaptureType,
-                                              SourceLocation EllipsisLoc,
-                                              IdentifierInfo *Id,
-                                              unsigned InitStyle, Expr *Init) {
+VarDecl *Sema::createLambdaInitCaptureVarDecl(
+    SourceLocation Loc, QualType InitCaptureType, SourceLocation EllipsisLoc,
+    IdentifierInfo *Id, unsigned InitStyle, Expr *Init, DeclContext *DeclCtx) {
   // FIXME: Retain the TypeSourceInfo from buildLambdaInitCaptureInitialization
   // rather than reconstructing it here.
   TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType, Loc);
@@ -868,8 +869,8 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
   // used as a variable, and only exists as a way to name and refer to the
   // init-capture.
   // FIXME: Pass in separate source locations for '&' and identifier.
-  VarDecl *NewVD = VarDecl::Create(Context, CurContext, Loc,
-                                   Loc, Id, InitCaptureType, TSI, SC_Auto);
+  VarDecl *NewVD = VarDecl::Create(Context, DeclCtx, Loc, Loc, Id,
+                                   InitCaptureType, TSI, SC_Auto);
   NewVD->setInitCapture(true);
   NewVD->setReferenced(true);
   // FIXME: Pass in a VarDecl::InitializationStyle.
@@ -888,12 +889,107 @@ void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var) {
                   Var->getType(), /*Invalid*/false);
 }
 
-void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
-                                        Declarator &ParamInfo,
-                                        Scope *CurScope) {
+// Unlike getCurLambda, getCurrentLambdaScopeUnsafe doesn't
+// check that the current lambda is in a consistent or fully constructed state.
+static LambdaScopeInfo *getCurrentLambdaScopeUnsafe(Sema &S) {
+  assert(!S.FunctionScopes.empty());
+  return cast<LambdaScopeInfo>(S.FunctionScopes[S.FunctionScopes.size() - 1]);
+}
+
+static TypeSourceInfo *
+getDummyLambdaType(Sema &S, SourceLocation Loc = SourceLocation()) {
+  // C++11 [expr.prim.lambda]p4:
+  //   If a lambda-expression does not include a lambda-declarator, it is as
+  //   if the lambda-declarator were ().
+  FunctionProtoType::ExtProtoInfo EPI(S.Context.getDefaultCallingConvention(
+      /*IsVariadic=*/false, /*IsCXXMethod=*/true));
+  EPI.HasTrailingReturn = true;
+  EPI.TypeQuals.addConst();
+  LangAS AS = S.getDefaultCXXMethodAddrSpace();
+  if (AS != LangAS::Default)
+    EPI.TypeQuals.addAddressSpace(AS);
+
+  // C++1y [expr.prim.lambda]:
+  //   The lambda return type is 'auto', which is replaced by the
+  //   trailing-return type if provided and/or deduced from 'return'
+  //   statements
+  // We don't do this before C++1y, because we don't support deduced return
+  // types there.
+  QualType DefaultTypeForNoTrailingReturn = S.getLangOpts().CPlusPlus14
+                                                ? S.Context.getAutoDeductType()
+                                                : S.Context.DependentTy;
+  QualType MethodTy =
+      S.Context.getFunctionType(DefaultTypeForNoTrailingReturn, None, EPI);
+  return S.Context.getTrivialTypeSourceInfo(MethodTy, Loc);
+}
+
+static TypeSourceInfo *getLambdaType(Sema &S, LambdaIntroducer &Intro,
+                                     Declarator &ParamInfo, Scope *CurScope,
+                                     SourceLocation Loc,
+                                     bool &ExplicitResultType) {
+
+  ExplicitResultType = false;
+
+  TypeSourceInfo *MethodTyInfo;
+
+  if (ParamInfo.getNumTypeObjects() == 0) {
+    MethodTyInfo = getDummyLambdaType(S, Loc);
+  } else {
+    DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo();
+    ExplicitResultType = FTI.hasTrailingReturnType();
+    if (!FTI.hasMutableQualifier()) {
+      FTI.getOrCreateMethodQualifiers().SetTypeQual(DeclSpec::TQ_const, Loc);
+    }
+
+    MethodTyInfo = S.GetTypeForDeclarator(ParamInfo, CurScope);
+
+    assert(MethodTyInfo && "no type from lambda-declarator");
+
+    // Check for unexpanded parameter packs in the method type.
+    if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
+      S.DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo,
+                                        S.UPPC_DeclarationType);
+  }
+  return MethodTyInfo;
+}
+
+static CXXMethodDecl *CreateMethod(Sema &S, 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);
+  DeclarationNameLoc MethodNameLoc =
+      DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange.getBegin());
+  CXXMethodDecl *Method = CXXMethodDecl::Create(
+      S.Context, Class, SourceLocation(),
+      DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
+                          MethodNameLoc),
+      QualType(), nullptr, SC_None, S.getCurFPFeatures().isFPConstrained(),
+      /*isInline=*/true, ConstexprSpecKind::Unspecified, SourceLocation(),
+      nullptr);
+  Method->setAccess(AS_public);
+  return Method;
+}
+
+void Sema::ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurrentScope) {
+
   LambdaScopeInfo *const LSI = getCurLambda();
   assert(LSI && "LambdaScopeInfo should be on stack!");
 
+  if (Intro.Default == LCD_ByCopy)
+    LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
+  else if (Intro.Default == LCD_ByRef)
+    LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref;
+  LSI->CaptureDefaultLoc = Intro.DefaultLoc;
+  LSI->IntroducerRange = Intro.Range;
+  LSI->BeforeLambdaQualifiersScope = true;
+
+  assert(LSI->NumExplicitTemplateParams == 0);
+
   // Determine if we're within a context where we know that the lambda will
   // be dependent, because there are template parameters in scope.
   CXXRecordDecl::LambdaDependencyKind LambdaDependencyKind =
@@ -910,181 +1006,37 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
     LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
   }
 
-  // Determine the signature of the call operator.
-  TypeSourceInfo *MethodTyInfo;
-  bool ExplicitParams = true;
-  bool ExplicitResultType = true;
-  bool ContainsUnexpandedParameterPack = false;
-  SourceLocation EndLoc;
-  SmallVector<ParmVarDecl *, 8> Params;
-  if (ParamInfo.getNumTypeObjects() == 0) {
-    // C++11 [expr.prim.lambda]p4:
-    //   If a lambda-expression does not include a lambda-declarator, it is as
-    //   if the lambda-declarator were ().
-    FunctionProtoType::ExtProtoInfo EPI(Context.getDefaultCallingConvention(
-        /*IsVariadic=*/false, /*IsCXXMethod=*/true));
-    EPI.HasTrailingReturn = true;
-    EPI.TypeQuals.addConst();
-    LangAS AS = getDefaultCXXMethodAddrSpace();
-    if (AS != LangAS::Default)
-      EPI.TypeQuals.addAddressSpace(AS);
-
-    // C++1y [expr.prim.lambda]:
-    //   The lambda return type is 'auto', which is replaced by the
-    //   trailing-return type if provided and/or deduced from 'return'
-    //   statements
-    // We don't do this before C++1y, because we don't support deduced return
-    // types there.
-    QualType DefaultTypeForNoTrailingReturn =
-        getLangOpts().CPlusPlus14 ? Context.getAutoDeductType()
-                                  : Context.DependentTy;
-    QualType MethodTy =
-        Context.getFunctionType(DefaultTypeForNoTrailingReturn, None, EPI);
-    MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
-    ExplicitParams = false;
-    ExplicitResultType = false;
-    EndLoc = Intro.Range.getEnd();
-  } else {
-    assert(ParamInfo.isFunctionDeclarator() &&
-           "lambda-declarator is a function");
-    DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo();
-
-    // C++11 [expr.prim.lambda]p5:
-    //   This function call operator is declared const (9.3.1) if and only if
-    //   the lambda-expression's parameter-declaration-clause is not followed
-    //   by mutable. It is neither virtual nor declared volatile. [...]
-    if (!FTI.hasMutableQualifier()) {
-      FTI.getOrCreateMethodQualifiers().SetTypeQual(DeclSpec::TQ_const,
-                                                    SourceLocation());
-    }
-
-    MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
-    assert(MethodTyInfo && "no type from lambda-declarator");
-    EndLoc = ParamInfo.getSourceRange().getEnd();
-
-    ExplicitResultType = FTI.hasTrailingReturnType();
-
-    if (FTIHasNonVoidParameters(FTI)) {
-      Params.reserve(FTI.NumParams);
-      for (unsigned i = 0, e = FTI.NumParams; i != e; ++i)
-        Params.push_back(cast<ParmVarDecl>(FTI.Params[i].Param));
-    }
-
-    // Check for unexpanded parameter packs in the method type.
-    if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
-      DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo,
-                                      UPPC_DeclarationType);
-  }
-
   CXXRecordDecl *Class = createLambdaClosureType(
-      Intro.Range, MethodTyInfo, LambdaDependencyKind, Intro.Default);
-  CXXMethodDecl *Method =
-      startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
-                            ParamInfo.getDeclSpec().getConstexprSpecifier(),
-                            ParamInfo.getTrailingRequiresClause());
-  if (ExplicitParams)
-    CheckCXXDefaultArguments(Method);
-
-  // This represents the function body for the lambda function, check if we
-  // have to apply optnone due to a pragma.
-  AddRangeBasedOptnone(Method);
-
-  // code_seg attribute on lambda apply to the method.
-  if (Attr *A = getImplicitCodeSegOrSectionAttrForFunction(Method, /*IsDefinition=*/true))
-    Method->addAttr(A);
-
-  // Attributes on the lambda apply to the method.
-  ProcessDeclAttributes(CurScope, Method, ParamInfo);
-
-  // CUDA lambdas get implicit host and device attributes.
-  if (getLangOpts().CUDA)
-    CUDASetLambdaAttrs(Method);
+      Intro.Range, nullptr, LambdaDependencyKind, Intro.Default);
+  LSI->Lambda = Class;
 
-  // OpenMP lambdas might get assumumption attributes.
-  if (LangOpts.OpenMP)
-    ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Method);
+  // 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.
 
-  // Number the lambda for linkage purposes if necessary.
-  handleLambdaNumbering(Class, Method);
+  CXXMethodDecl *Method = CreateMethod(*this, Intro.Range, Class);
+  LSI->CallOperator = Method;
+  Method->setLexicalDeclContext(CurContext);
 
-  // Introduce the function call operator as the current declaration context.
   PushDeclContext(CurScope, Method);
 
-  // Build the lambda scope.
-  buildLambdaScope(LSI, Method, Intro.Range, Intro.Default, Intro.DefaultLoc,
-                   ExplicitParams, ExplicitResultType, !Method->isConst());
-
-  // C++11 [expr.prim.lambda]p9:
-  //   A lambda-expression whose smallest enclosing scope is a block scope is a
-  //   local lambda expression; any other lambda expression shall not have a
-  //   capture-default or simple-capture in its lambda-introducer.
-  //
-  // For simple-captures, this is covered by the check below that any named
-  // entity is a variable that can be captured.
-  //
-  // For DR1632, we also allow a capture-default in any context where we can
-  // odr-use 'this' (in particular, in a default initializer for a non-static
-  // data member).
-  if (Intro.Default != LCD_None && !Class->getParent()->isFunctionOrMethod() &&
-      (getCurrentThisType().isNull() ||
-       CheckCXXThisCapture(SourceLocation(), /*Explicit*/true,
-                           /*BuildAndDiagnose*/false)))
-    Diag(Intro.DefaultLoc, diag::err_capture_default_non_local);
+  bool ContainsUnexpandedParameterPack = false;
 
   // Distinct capture names, for diagnostics.
-  llvm::SmallSet<IdentifierInfo*, 8> CaptureNames;
+  llvm::SmallSet<IdentifierInfo *, 8> CaptureNames;
 
   // Handle explicit captures.
-  SourceLocation PrevCaptureLoc
-    = Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc;
+  SourceLocation PrevCaptureLoc =
+      Intro.Default == LCD_None ? Intro.Range.getBegin() : Intro.DefaultLoc;
   for (auto C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E;
        PrevCaptureLoc = C->Loc, ++C) {
     if (C->Kind == LCK_This || C->Kind == LCK_StarThis) {
-      if (C->Kind == LCK_StarThis)
-        Diag(C->Loc, !getLangOpts().CPlusPlus17
-                             ? diag::ext_star_this_lambda_capture_cxx17
-                             : diag::warn_cxx14_compat_star_this_lambda_capture);
-
-      // C++11 [expr.prim.lambda]p8:
-      //   An identifier or this shall not appear more than once in a
-      //   lambda-capture.
-      if (LSI->isCXXThisCaptured()) {
-        Diag(C->Loc, diag::err_capture_more_than_once)
-            << "'this'" << SourceRange(LSI->getCXXThisCapture().getLocation())
-            << FixItHint::CreateRemoval(
-                   SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
-        continue;
-      }
-
-      // C++2a [expr.prim.lambda]p8:
-      //  If a lambda-capture includes a capture-default that is =,
-      //  each simple-capture of that lambda-capture shall be of the form
-      //  "&identifier", "this", or "* this". [ Note: The form [&,this] is
-      //  redundant but accepted for compatibility with ISO C++14. --end note ]
-      if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis)
-        Diag(C->Loc, !getLangOpts().CPlusPlus20
-                         ? diag::ext_equals_this_lambda_capture_cxx20
-                         : diag::warn_cxx17_compat_equals_this_lambda_capture);
-
-      // C++11 [expr.prim.lambda]p12:
-      //   If this is captured by a local lambda expression, its nearest
-      //   enclosing function shall be a non-static member function.
-      QualType ThisCaptureType = getCurrentThisType();
-      if (ThisCaptureType.isNull()) {
-        Diag(C->Loc, diag::err_this_capture) << true;
         continue;
-      }
-
-      CheckCXXThisCapture(C->Loc, /*Explicit=*/true, /*BuildAndDiagnose*/ true,
-                          /*FunctionScopeIndexToStopAtPtr*/ nullptr,
-                          C->Kind == LCK_StarThis);
-      if (!LSI->Captures.empty())
-        LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = C->ExplicitRange;
-      continue;
     }
 
     assert(C->Id && "missing identifier for capture");
-
     if (C->Init.isInvalid())
       continue;
 
@@ -1122,13 +1074,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
       }
       Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
                                            C->EllipsisLoc, C->Id, InitStyle,
-                                           C->Init.get());
-      // C++1y [expr.prim.lambda]p11:
-      //   An init-capture behaves as if it declares and explicitly
-      //   captures a variable [...] whose declarative region is the
-      //   lambda-expression's compound-statement
-      if (Var)
-        PushOnScopeChains(Var, CurScope, false);
+                                           C->Init.get(), Method);
+      assert(Var && "createLambdaInitCaptureVarDecl returned a null VarDecl?");
+      CheckShadow(CurrentScope, Var);
+      PushOnScopeChains(Var, CurrentScope, false);
     } else {
       assert(C->InitKind == LambdaCaptureInitKind::NoInit &&
              "init capture has valid but null init?");
@@ -1171,13 +1120,25 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
         continue;
     }
 
+    // C++11 [expr.prim.lambda]p10:
+    //   [...] each such lookup shall find a variable with automatic storage
+    //   duration declared in the reaching scope of the local lambda expression.
+    // Note that the 'reaching scope' check happens in tryCaptureVariable().
+    if (!Var) {
+      Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
+      continue;
+    }
+
     // C++11 [expr.prim.lambda]p8:
     //   An identifier or this shall not appear more than once in a
     //   lambda-capture.
     if (!CaptureNames.insert(C->Id).second) {
-      if (Var && LSI->isCaptured(Var)) {
+      auto It = llvm::find_if(LSI->DelayedCaptures, [&Var](auto &&Pair) {
+        return Pair.second.Var == Var;
+      });
+      if (It != LSI->DelayedCaptures.end()) {
         Diag(C->Loc, diag::err_capture_more_than_once)
-            << C->Id << SourceRange(LSI->getCapture(Var).getLocation())
+            << C->Id << SourceRange(It->second.Loc)
             << FixItHint::CreateRemoval(
                    SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
       } else
@@ -1187,15 +1148,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
       continue;
     }
 
-    // C++11 [expr.prim.lambda]p10:
-    //   [...] each such lookup shall find a variable with automatic storage
-    //   duration declared in the reaching scope of the local lambda expression.
-    // Note that the 'reaching scope' check happens in tryCaptureVariable().
-    if (!Var) {
-      Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
-      continue;
-    }
-
     // Ignore invalid decls; they'll just confuse the code later.
     if (Var->isInvalidDecl())
       continue;
@@ -1223,22 +1175,250 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
       ContainsUnexpandedParameterPack = true;
     }
 
-    if (C->Init.isUsable()) {
-      addInitCapture(LSI, Var);
+    if (Var)
+      LSI->DelayedCaptures[std::distance(Intro.Captures.begin(), C)] =
+          LambdaScopeInfo::DelayedCapture{Var, C->ExplicitRange.getBegin(),
+                                          C->Kind};
+  }
+
+  LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
+  PopDeclContext();
+}
+
+static void AddExplicitCapturesToContext(Sema &S, LambdaScopeInfo *LSI,
+                                         LambdaIntroducer &Intro) {
+  SourceLocation PrevCaptureLoc;
+  for (auto C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E;
+       PrevCaptureLoc = C->Loc, ++C) {
+    if (C->Kind == LCK_This || C->Kind == LCK_StarThis) {
+      if (C->Kind == LCK_StarThis)
+        S.Diag(C->Loc, !S.getLangOpts().CPlusPlus17
+                           ? diag::ext_star_this_lambda_capture_cxx17
+                           : diag::warn_cxx14_compat_star_this_lambda_capture);
+
+      // C++11 [expr.prim.lambda]p8:
+      //   An identifier or this shall not appear more than once in a
+      //   lambda-capture.
+      if (LSI->isCXXThisCaptured()) {
+        S.Diag(C->Loc, diag::err_capture_more_than_once)
+            << "'this'" << SourceRange(LSI->getCXXThisCapture().getLocation())
+            << FixItHint::CreateRemoval(
+                   SourceRange(S.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+        continue;
+      }
+
+      // C++20 [expr.prim.lambda]p8:
+      //  If a lambda-capture includes a capture-default that is =,
+      //  each simple-capture of that lambda-capture shall be of the form
+      //  "&identifier", "this", or "* this". [ Note: The form [&,this] is
+      //  redundant but accepted for compatibility with ISO C++14. --end note ]
+      if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis)
+        S.Diag(C->Loc,
+               !S.getLangOpts().CPlusPlus20
+                   ? diag::ext_equals_this_lambda_capture_cxx20
+                   : diag::warn_cxx17_compat_equals_this_lambda_capture);
+
+      // C++11 [expr.prim.lambda]p12:
+      //   If this is captured by a local lambda expression, its nearest
+      //   enclosing function shall be a non-static member function.
+      QualType ThisCaptureType = S.getCurrentThisType();
+      if (ThisCaptureType.isNull()) {
+        S.Diag(C->Loc, diag::err_this_capture) << true;
+        continue;
+      }
+      S.CheckCXXThisCapture(C->Loc, true, true, nullptr,
+                            C->Kind == LCK_StarThis);
     } else {
-      TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
-                                                   TryCapture_ExplicitByVal;
-      tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
+      VarDecl *Var =
+          LSI->DelayedCaptures[std::distance(Intro.Captures.begin(), C)].Var;
+      if (!Var)
+        continue;
+      if (Var->isInitCapture() && C->Init.isUsable()) {
+        S.addInitCapture(LSI, Var);
+        S.PushOnScopeChains(Var, S.getCurScope(), false);
+      } else {
+        Sema::TryCaptureKind Kind = C->Kind == LCK_ByRef
+                                        ? Sema::TryCapture_ExplicitByRef
+                                        : Sema::TryCapture_ExplicitByVal;
+        S.tryCaptureVariable(Var, C->Loc, Kind, C->EllipsisLoc);
+      }
     }
     if (!LSI->Captures.empty())
       LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = C->ExplicitRange;
   }
-  finishLambdaExplicitCaptures(LSI);
+  S.finishLambdaExplicitCaptures(LSI);
+}
 
-  LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
+void Sema::ActOnLambdaClosureQualifiers(
+    LambdaIntroducer &Intro, SourceLocation MutableLoc, SourceLocation EndLoc,
+    MutableArrayRef<DeclaratorChunk::ParamInfo> Params, const DeclSpec &DS) {
 
-  // Add lambda parameters into scope.
-  addLambdaParameters(Intro.Captures, Method, CurScope);
+  LambdaScopeInfo *const LSI = getCurrentLambdaScopeUnsafe(*this);
+  LSI->Mutable = MutableLoc.isValid();
+  LSI->BeforeLambdaQualifiersScope = false;
+  LSI->CallOperator->setConstexprKind(DS.getConstexprSpecifier());
+
+  // C++11 [expr.prim.lambda]p9:
+  //   A lambda-expression whose smallest enclosing scope is a block scope is a
+  //   local lambda expression; any other lambda expression shall not have a
+  //   capture-default or simple-capture in its lambda-introducer.
+  //
+  // For simple-captures, this is covered by the check below that any named
+  // entity is a variable that can be captured.
+  //
+  // For DR1632, we also allow a capture-default in any context where we can
+  // odr-use 'this' (in particular, in a default initializer for a non-static
+  // data member).
+  if (Intro.Default != LCD_None &&
+      !LSI->Lambda->getParent()->isFunctionOrMethod() &&
+      (getCurrentThisType().isNull() ||
+       CheckCXXThisCapture(SourceLocation(), /*Explicit*/ true,
+                           /*BuildAndDiagnose*/ false)))
+    Diag(Intro.DefaultLoc, diag::err_capture_default_non_local);
+
+  PushDeclContext(CurScope, LSI->CallOperator);
+
+  for (const DeclaratorChunk::ParamInfo &P : Params) {
+    auto *Param = cast<ParmVarDecl>(P.Param);
+    Param->setOwningFunction(LSI->CallOperator);
+    if (Param->getIdentifier())
+      PushOnScopeChains(Param, CurScope, false);
+  }
+
+  AddExplicitCapturesToContext(*this, LSI, Intro);
+}
+
+void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
+                                        Declarator &ParamInfo,
+                                        Scope *CurScope) {
+
+  LambdaScopeInfo *const LSI = getCurrentLambdaScopeUnsafe(*this);
+
+  SmallVector<ParmVarDecl *, 8> Params;
+  bool ExplicitResultType;
+
+  SourceLocation TypeLoc, LambdaLoc;
+  if (ParamInfo.getNumTypeObjects() == 0) {
+    LambdaLoc = 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();
+  }
+
+  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 &&
+      !FTIHasSingleVoidParameter(ParamInfo.getFunctionTypeInfo())) {
+    const auto &FTI = ParamInfo.getFunctionTypeInfo();
+    Params.reserve(Params.size());
+    for (unsigned I = 0; I < FTI.NumParams; ++I) {
+      auto *Param = cast<ParmVarDecl>(FTI.Params[I].Param);
+      Param->setScopeInfo(0, Params.size());
+      Params.push_back(Param);
+    }
+  }
+
+  ContextRAII ManglingContext(*this, Class->getDeclContext());
+
+  CheckParmsForFunctionDef(Params, /*CheckParameterNames=*/false);
+
+  if (LSI->ExplicitParams) {
+    Method->setParams(Params);
+    CheckCXXDefaultArguments(Method);
+  }
+
+  // This represents the function body for the lambda function, check if we
+  // have to apply optnone due to a pragma.
+  AddRangeBasedOptnone(Method);
+
+  // code_seg attribute on lambda apply to the method.
+  if (Attr *A = getImplicitCodeSegOrSectionAttrForFunction(
+          Method, /*IsDefinition=*/true))
+    Method->addAttr(A);
+
+  // Attributes on the lambda apply to the method.
+  ProcessDeclAttributes(CurScope, Method, ParamInfo);
+
+  // CUDA lambdas get implicit host and device attributes.
+  if (getLangOpts().CUDA)
+    CUDASetLambdaAttrs(Method);
+
+  // OpenMP lambdas might get assumumption attributes.
+  if (LangOpts.OpenMP)
+    ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Method);
+
+  handleLambdaNumbering(Class, Method);
+
+  ManglingContext.pop();
+
+  for (auto &&C : LSI->DelayedCaptures) {
+    VarDecl *Var = C.second.Var;
+    if (Var && Var->isInitCapture()) {
+      PushOnScopeChains(Var, CurScope, false);
+    }
+  }
+
+  LSI->DelayedCaptures.clear();
+
+  auto CheckRedefinition = [&](ParmVarDecl *Param) {
+    for (const auto &Capture : Intro.Captures) {
+      if (Capture.Id == Param->getIdentifier()) {
+        Diag(Param->getLocation(), diag::err_parameter_shadow_capture);
+        Diag(Capture.Loc, diag::note_var_explicitly_captured_here)
+            << Capture.Id << true;
+        return false;
+      }
+    }
+    return true;
+  };
+  for (ParmVarDecl *P : Params) {
+    if (!P->getIdentifier())
+      continue;
+    if (CheckRedefinition(P))
+      CheckShadow(CurScope, P);
+    PushOnScopeChains(P, CurScope);
+  }
 
   // Enter a new evaluation context to insulate the lambda from any
   // cleanups from the enclosing full-expression.

diff  --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 5eff7cfd7a253..5460f88228821 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13100,7 +13100,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
         }
         VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl(
             OldVD->getLocation(), InitQualType, NewC.EllipsisLoc,
-            OldVD->getIdentifier(), OldVD->getInitStyle(), Init.get());
+            OldVD->getIdentifier(), OldVD->getInitStyle(), Init.get(),
+            getSema().CurContext);
         if (!NewVD) {
           Invalid = true;
           break;

diff  --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
index 4a0cf39bc56b3..67953c6a6f901 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
@@ -12,16 +12,16 @@ auto with_float_2 = [&f(f)] { // ok, refers to outer f
   using T = double&;
 };
 
-// Within the lambda-expression's compound-statement,
-// the identifier in the init-capture hides any declaration
-// of the same name in scopes enclosing the lambda-expression.
+// Within the lambda-expression the identifier in the init-capture
+// hides any declaration of the same name in scopes enclosing
+// the lambda-expression.
 void hiding() {
   char c;
   (void) [c("foo")] {
     static_assert(sizeof(c) == sizeof(const char*), "");
   };
-  (void) [c("bar")] () -> decltype(c) { // outer c, not init-capture
-    return "baz"; // expected-error {{cannot initialize}}
+  (void)[c("bar")]()->decltype(c) { // inner c
+    return "baz";
   };
 }
 

diff  --git a/clang/test/SemaCXX/lambda-capture-type-deduction.cpp b/clang/test/SemaCXX/lambda-capture-type-deduction.cpp
new file mode 100644
index 0000000000000..88976571dca32
--- /dev/null
+++ b/clang/test/SemaCXX/lambda-capture-type-deduction.cpp
@@ -0,0 +1,173 @@
+// RUN: %clang_cc1 -std=c++2b -verify -fsyntax-only %s
+
+template <typename T, typename U>
+constexpr bool is_same = false;
+
+template <typename T>
+constexpr bool is_same<T, T> = true;
+
+void f() {
+
+  int y;
+
+  static_assert(is_same<const int &,
+                        decltype([x = 1] -> decltype((x)) { return x; }())>);
+
+  static_assert(is_same<int &,
+                        decltype([x = 1] mutable -> decltype((x)) { return x; }())>);
+
+  static_assert(is_same<const int &,
+                        decltype([=] -> decltype((y)) { return y; }())>);
+
+  static_assert(is_same<int &,
+                        decltype([=] mutable -> decltype((y)) { return y; }())>);
+
+  static_assert(is_same<const int &,
+                        decltype([=] -> decltype((y)) { return y; }())>);
+
+  static_assert(is_same<int &,
+                        decltype([=] mutable -> decltype((y)) { return y; }())>);
+
+  auto ref = [&x = y](
+                 decltype([&](decltype(x)) { return 0; }) y) {
+    return x;
+  };
+}
+
+void test_noexcept() {
+
+  int y;
+
+  static_assert(noexcept([x = 1] noexcept(is_same<const int &, decltype((x))>) {}()));
+  static_assert(noexcept([x = 1] mutable noexcept(is_same<int &, decltype((x))>) {}()));
+  static_assert(noexcept([y] noexcept(is_same<const int &, decltype((y))>) {}()));
+  static_assert(noexcept([y] mutable noexcept(is_same<int &, decltype((y))>) {}()));
+  static_assert(noexcept([=] noexcept(is_same<const int &, decltype((y))>) {}()));
+  static_assert(noexcept([=] mutable noexcept(is_same<int &, decltype((y))>) {}()));
+  static_assert(noexcept([&] noexcept(is_same<int &, decltype((y))>) {}()));
+  static_assert(noexcept([&] mutable noexcept(is_same<int &, decltype((y))>) {}()));
+
+  static_assert(noexcept([&] mutable noexcept(!is_same<int &, decltype((y))>) {}())); // expected-error {{static_assert failed due}}
+}
+
+void test_requires() {
+
+  int x;
+
+  [x = 1]() requires is_same<const int &, decltype((x))> {}
+  ();
+  [x = 1]() mutable requires is_same<int &, decltype((x))> {}
+  ();
+  [x]() requires is_same<const int &, decltype((x))> {}
+  ();
+  [x]() mutable requires is_same<int &, decltype((x))> {}
+  ();
+  [=]() requires is_same<const int &, decltype((x))> {}
+  ();
+  [=]() mutable requires is_same<int &, decltype((x))> {}
+  ();
+  [&]() requires is_same<int &, decltype((x))> {}
+  ();
+  [&]() mutable requires is_same<int &, decltype((x))> {}
+  ();
+  [&x]() requires is_same<int &, decltype((x))> {}
+  ();
+  [&x]() mutable requires is_same<int &, decltype((x))> {}
+  ();
+
+  [x = 1]() requires is_same<int &, decltype((x))> {} (); //expected-error {{no matching function for call to object of type}} \
+                                                           // expected-note {{candidate function not viable}} \
+                                                           // expected-note {{'is_same<int &, decltype((x))>' evaluated to false}}
+  [x = 1]() mutable requires is_same<const int &, decltype((x))> {} (); // expected-error {{no matching function for call to object of type}} \
+                                                                     // expected-note {{candidate function not viable}} \
+                                                                     // expected-note {{'is_same<const int &, decltype((x))>' evaluated to false}}
+}
+
+void err() {
+  int y, z;                // expected-note 2{{declared here}}
+  auto implicit_tpl = [=]( // expected-note {{variable 'y' is captured here}}
+                          decltype(
+                              [&]<decltype(y)> { return 0; }) y) { //expected-error{{captured variable 'y' cannot appear here}}
+    return y;
+  };
+
+  auto init_tpl = [x = 1](                                          // expected-note{{explicitly captured here}}
+                      decltype([&]<decltype(x)> { return 0; }) y) { // expected-error {{captured variable 'x' cannot appear here}}
+    return x;
+  };
+
+  auto implicit = [=]( // expected-note {{variable 'z' is captured here}}
+                      decltype(
+                          [&](decltype(z)) { return 0; }) z) { //expected-error{{captured variable 'z' cannot appear here}}
+    return z;
+  };
+
+  auto init = [x = 1](                                          // expected-note{{explicitly captured here}}
+                  decltype([&](decltype(x)) { return 0; }) y) { // expected-error {{captured variable 'x' cannot appear here}}
+    return x;
+  };
+
+  auto use_before_params = [x = 1]<typename T>  // expected-note {{variable 'x' is explicitly captured here}}
+  requires(is_same<const int &, decltype((x))>) // expected-error {{captured variable 'x' cannot appear here}}
+  {};
+
+  auto use_before_params2 = [x = 1]<typename T =  decltype((x))>  // expected-note {{variable 'x' is explicitly captured here}} \
+                                                                 // expected-error {{captured variable 'x' cannot appear here}}
+  {};
+}
+
+void gnu_attributes() {
+  int y;
+  (void)[=]() __attribute__((diagnose_if(!is_same<decltype((y)), const int &>, "wrong type", "warning"))){}();
+  (void)[=]() __attribute__((diagnose_if(!is_same<decltype((y)), int &>, "wrong type", "warning"))){}();
+  // expected-warning at -1 {{wrong type}} expected-note at -1{{'diagnose_if' attribute on 'operator()'}}
+
+  (void)[=]() __attribute__((diagnose_if(!is_same<decltype((y)), int &>, "wrong type", "warning"))) mutable {}();
+  (void)[=]() __attribute__((diagnose_if(!is_same<decltype((y)), const int &>, "wrong type", "warning"))) mutable {}();
+  // expected-warning at -1 {{wrong type}} expected-note at -1{{'diagnose_if' attribute on 'operator()'}}
+
+  (void)[x=1]() __attribute__((diagnose_if(!is_same<decltype((x)), const int &>, "wrong type", "warning"))){}();
+  (void)[x=1]() __attribute__((diagnose_if(!is_same<decltype((x)), int &>, "wrong type", "warning"))){}();
+  // expected-warning at -1 {{wrong type}} expected-note at -1{{'diagnose_if' attribute on 'operator()'}}
+
+  (void)[x=1]() __attribute__((diagnose_if(!is_same<decltype((x)), int &>, "wrong type", "warning"))) mutable {}();
+  (void)[x=1]() __attribute__((diagnose_if(!is_same<decltype((x)), const int &>, "wrong type", "warning"))) mutable {}();
+  // expected-warning at -1 {{wrong type}} expected-note at -1{{'diagnose_if' attribute on 'operator()'}}
+}
+
+void nested() {
+  int x, y, z; // expected-note {{'x' declared here}} expected-note {{'z' declared here}}
+  (void)[&](
+      decltype([&](
+                   decltype([=]( // expected-note {{variable 'x' is captured here}}
+                                decltype([&](
+                                             decltype([&](decltype(x)) {}) // expected-error{{captured variable 'x' cannot appear here}}
+                                         ) {})) {})) {})){};
+
+  (void)[&](
+      decltype([&](
+                   decltype([&](
+                                decltype([&](
+                                             decltype([&](decltype(y)) {})) {})) {})) {})){};
+
+  (void)[=](
+      decltype([=](
+                   decltype([=](
+                                decltype([=](                              // expected-note {{variable 'z' is captured here}}
+                                             decltype([&]<decltype(z)> {}) // expected-error{{captured variable 'z' cannot appear here}}
+                                         ) {})) {})) {})){};
+}
+
+template <typename T, typename U>
+void dependent(U&& u) {
+  [&]() requires is_same<decltype(u), T> {}();
+}
+
+void test_dependent() {
+  int v   = 0;
+  int & r = v;
+  const int & cr = v;
+  dependent<int&>(v);
+  dependent<int&>(r);
+  dependent<const int&>(cr);
+}

diff  --git a/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp b/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
index a772af049ab41..9dddbf8b5f3b7 100644
--- a/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
+++ b/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
@@ -95,7 +95,7 @@ void foo(int param) { // expected-note 1+ {{previous declaration is here}}
 #ifdef AVOID
   auto l4 = [var = param] (int param) { ; }; // no warning
 #else
-  auto l4 = [var = param] (int param) { ; }; // expected-warning {{declaration shadows a local variable}}
+  auto l4 = [var = param](int param) { ; }; // expected-warning 2{{declaration shadows a local variable}}
 #endif
 
   // Make sure that inner lambdas work as well.

diff  --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 5501d07f0e1ba..44dfcbe98e2c1 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1356,7 +1356,7 @@ <h2 id="cxx23">C++2b implementation status</h2>
     <tr>
       <td>Change scope of lambda trailing-return-type</td>
       <td><a href="https://wg21.link/P2036R3">P2036R3</a></td>
-      <td class="none" align="center">No</td>
+      <td class="unreleased" align="center">Clang 15</td>
     </tr>
     <tr>
       <td>Multidimensional subscript operator</td>


        


More information about the cfe-commits mailing list