Skip to content

Commit d708a18

Browse files
committed
[Clang] Implement Change scope of lambda trailing-return-type
This implements P2036R3 and P2579R0. That is, explicit, int, and implicit capture become visible at the start of the parameter head. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D124351
1 parent cd173cb commit d708a18

20 files changed

+972
-460
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ C++20 Feature Support
110110
C++2b Feature Support
111111
^^^^^^^^^^^^^^^^^^^^^
112112

113+
- Implemented `P2036R3: Change scope of lambda trailing-return-type <https://wg21.link/P2036R3>`_
114+
and `P2579R0 Mitigation strategies for P2036 <https://wg21.link/P2579R0>`_.
115+
This proposals modify how variables captured in lambdas can appear in trailing return type
116+
expressions and how their types are deduced therein, in all C++ language versions.
117+
113118
CUDA/HIP Language Changes in Clang
114119
----------------------------------
115120

clang/include/clang/AST/DeclCXX.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,11 @@ class CXXRecordDecl : public RecordDecl {
10921092

10931093
unsigned capture_size() const { return getLambdaData().NumCaptures; }
10941094

1095+
const LambdaCapture *getCapture(unsigned I) const {
1096+
assert(isLambda() && I < capture_size() && "invalid index for capture");
1097+
return captures_begin() + I;
1098+
}
1099+
10951100
using conversion_iterator = UnresolvedSetIterator;
10961101

10971102
conversion_iterator conversion_begin() const {
@@ -1826,6 +1831,20 @@ class CXXRecordDecl : public RecordDecl {
18261831
return getLambdaData().MethodTyInfo;
18271832
}
18281833

1834+
void setLambdaTypeInfo(TypeSourceInfo *TS) {
1835+
assert(DefinitionData && DefinitionData->IsLambda &&
1836+
"setting lambda property of non-lambda class");
1837+
auto &DL = static_cast<LambdaDefinitionData &>(*DefinitionData);
1838+
DL.MethodTyInfo = TS;
1839+
}
1840+
1841+
void setLambdaIsGeneric(bool IsGeneric) {
1842+
assert(DefinitionData && DefinitionData->IsLambda &&
1843+
"setting lambda property of non-lambda class");
1844+
auto &DL = static_cast<LambdaDefinitionData &>(*DefinitionData);
1845+
DL.IsGenericLambda = IsGeneric;
1846+
}
1847+
18291848
// Determine whether this type is an Interface Like type for
18301849
// __interface inheritance purposes.
18311850
bool isInterfaceLike() const;

clang/include/clang/Sema/Scope.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ class Scope {
145145
/// This is a scope of some OpenMP directive with
146146
/// order clause which specifies concurrent
147147
OpenMPOrderClauseScope = 0x4000000,
148+
/// This is the scope for a lambda, after the lambda introducer.
149+
/// Lambdas need two FunctionPrototypeScope scopes (because there is a
150+
/// template scope in between), the outer scope does not increase the
151+
/// depth of recursion.
152+
LambdaScope = 0x8000000,
148153
};
149154

150155
private:

clang/include/clang/Sema/ScopeInfo.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,11 @@ class LambdaScopeInfo final :
838838
/// The lambda's compiler-generated \c operator().
839839
CXXMethodDecl *CallOperator = nullptr;
840840

841+
/// Indicate that we parsed the parameter list
842+
/// at which point the mutability of the lambda
843+
/// is known.
844+
bool AfterParameterList = true;
845+
841846
/// Source range covering the lambda introducer [...].
842847
SourceRange IntroducerRange;
843848

@@ -849,8 +854,9 @@ class LambdaScopeInfo final :
849854
/// explicit captures.
850855
unsigned NumExplicitCaptures = 0;
851856

852-
/// Whether this is a mutable lambda.
853-
bool Mutable = false;
857+
/// Whether this is a mutable lambda. Until the mutable keyword is parsed,
858+
/// we assume the lambda is mutable.
859+
bool Mutable = true;
854860

855861
/// Whether the (empty) parameter list is explicit.
856862
bool ExplicitParams = false;

clang/include/clang/Sema/Sema.h

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7103,15 +7103,21 @@ class Sema final {
71037103
std::nullopt);
71047104

71057105
/// Endow the lambda scope info with the relevant properties.
7106-
void buildLambdaScope(sema::LambdaScopeInfo *LSI,
7107-
CXXMethodDecl *CallOperator,
7106+
void buildLambdaScope(sema::LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator,
71087107
SourceRange IntroducerRange,
71097108
LambdaCaptureDefault CaptureDefault,
7110-
SourceLocation CaptureDefaultLoc,
7111-
bool ExplicitParams,
7112-
bool ExplicitResultType,
7109+
SourceLocation CaptureDefaultLoc, bool ExplicitParams,
71137110
bool Mutable);
71147111

7112+
CXXMethodDecl *CreateLambdaCallOperator(SourceRange IntroducerRange,
7113+
CXXRecordDecl *Class);
7114+
void CompleteLambdaCallOperator(
7115+
CXXMethodDecl *Method, SourceLocation LambdaLoc,
7116+
SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause,
7117+
TypeSourceInfo *MethodTyInfo, ConstexprSpecKind ConstexprKind,
7118+
StorageClass SC, ArrayRef<ParmVarDecl *> Params,
7119+
bool HasExplicitResultType);
7120+
71157121
/// Perform initialization analysis of the init-capture and perform
71167122
/// any implicit conversions such as an lvalue-to-rvalue conversion if
71177123
/// not being used to initialize a reference.
@@ -7132,11 +7138,9 @@ class Sema final {
71327138
///
71337139
/// CodeGen handles emission of lambda captures, ignoring these dummy
71347140
/// variables appropriately.
7135-
VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc,
7136-
QualType InitCaptureType,
7137-
SourceLocation EllipsisLoc,
7138-
IdentifierInfo *Id,
7139-
unsigned InitStyle, Expr *Init);
7141+
VarDecl *createLambdaInitCaptureVarDecl(
7142+
SourceLocation Loc, QualType InitCaptureType, SourceLocation EllipsisLoc,
7143+
IdentifierInfo *Id, unsigned InitStyle, Expr *Init, DeclContext *DeclCtx);
71407144

71417145
/// Add an init-capture to a lambda scope.
71427146
void addInitCapture(sema::LambdaScopeInfo *LSI, VarDecl *Var,
@@ -7146,28 +7150,38 @@ class Sema final {
71467150
/// given lambda.
71477151
void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
71487152

7149-
/// \brief This is called after parsing the explicit template parameter list
7153+
/// Deduce a block or lambda's return type based on the return
7154+
/// statements present in the body.
7155+
void deduceClosureReturnType(sema::CapturingScopeInfo &CSI);
7156+
7157+
/// Once the Lambdas capture are known, we can start to create the closure,
7158+
/// call operator method, and keep track of the captures.
7159+
/// We do the capture lookup here, but they are not actually captured until
7160+
/// after we know what the qualifiers of the call operator are.
7161+
void ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
7162+
Scope *CurContext);
7163+
7164+
/// This is called after parsing the explicit template parameter list
71507165
/// on a lambda (if it exists) in C++2a.
7151-
void ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
7166+
void ActOnLambdaExplicitTemplateParameterList(LambdaIntroducer &Intro,
7167+
SourceLocation LAngleLoc,
71527168
ArrayRef<NamedDecl *> TParams,
71537169
SourceLocation RAngleLoc,
71547170
ExprResult RequiresClause);
71557171

7156-
/// Introduce the lambda parameters into scope.
7157-
void addLambdaParameters(
7158-
ArrayRef<LambdaIntroducer::LambdaCapture> Captures,
7159-
CXXMethodDecl *CallOperator, Scope *CurScope);
7172+
void ActOnLambdaClosureQualifiers(LambdaIntroducer &Intro,
7173+
SourceLocation MutableLoc);
71607174

7161-
/// Deduce a block or lambda's return type based on the return
7162-
/// statements present in the body.
7163-
void deduceClosureReturnType(sema::CapturingScopeInfo &CSI);
7175+
void ActOnLambdaClosureParameters(
7176+
Scope *LambdaScope,
7177+
MutableArrayRef<DeclaratorChunk::ParamInfo> ParamInfo);
71647178

71657179
/// ActOnStartOfLambdaDefinition - This is called just before we start
71667180
/// parsing the body of a lambda; it analyzes the explicit captures and
71677181
/// arguments, and sets up various data-structures for the body of the
71687182
/// lambda.
71697183
void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
7170-
Declarator &ParamInfo, Scope *CurScope);
7184+
Declarator &ParamInfo, const DeclSpec &DS);
71717185

71727186
/// ActOnLambdaError - If there is an error parsing a lambda, this callback
71737187
/// is invoked to pop the information about the lambda.
@@ -7262,6 +7276,13 @@ class Sema final {
72627276
LocalInstantiationScope &Scope,
72637277
const MultiLevelTemplateArgumentList &TemplateArgs);
72647278

7279+
/// Introduce the instantiated captures of the lambda into the local
7280+
/// instantiation scope.
7281+
bool addInstantiatedCapturesToScope(
7282+
FunctionDecl *Function, const FunctionDecl *PatternDecl,
7283+
LocalInstantiationScope &Scope,
7284+
const MultiLevelTemplateArgumentList &TemplateArgs);
7285+
72657286
/// used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in
72667287
/// the case of lambdas) set up the LocalInstantiationScope of the current
72677288
/// function.

0 commit comments

Comments
 (0)