Skip to content

Commit

Permalink
[Clang] Implement Change scope of lambda trailing-return-type
Browse files Browse the repository at this point in the history
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
  • Loading branch information
cor3ntin committed Jan 31, 2023
1 parent cd173cb commit d708a18
Show file tree
Hide file tree
Showing 20 changed files with 972 additions and 460 deletions.
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ C++20 Feature Support
C++2b Feature Support
^^^^^^^^^^^^^^^^^^^^^

- Implemented `P2036R3: Change scope of lambda trailing-return-type <https://wg21.link/P2036R3>`_
and `P2579R0 Mitigation strategies for P2036 <https://wg21.link/P2579R0>`_.
This proposals modify how variables captured in lambdas can appear in trailing return type

This comment has been minimized.

Copy link
@tbaederr

tbaederr Jan 31, 2023

Contributor

*"These" I guess?

This comment has been minimized.

Copy link
@cor3ntin

cor3ntin Jan 31, 2023

Author Contributor

I'll fix that as NFC, thanks

expressions and how their types are deduced therein, in all C++ language versions.

CUDA/HIP Language Changes in Clang
----------------------------------

Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,11 @@ class CXXRecordDecl : public RecordDecl {

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

const LambdaCapture *getCapture(unsigned I) const {
assert(isLambda() && I < capture_size() && "invalid index for capture");
return captures_begin() + I;
}

using conversion_iterator = UnresolvedSetIterator;

conversion_iterator conversion_begin() const {
Expand Down Expand Up @@ -1826,6 +1831,20 @@ class CXXRecordDecl : public RecordDecl {
return getLambdaData().MethodTyInfo;
}

void setLambdaTypeInfo(TypeSourceInfo *TS) {
assert(DefinitionData && DefinitionData->IsLambda &&
"setting lambda property of non-lambda class");
auto &DL = static_cast<LambdaDefinitionData &>(*DefinitionData);
DL.MethodTyInfo = TS;
}

void setLambdaIsGeneric(bool IsGeneric) {
assert(DefinitionData && DefinitionData->IsLambda &&
"setting lambda property of non-lambda class");
auto &DL = static_cast<LambdaDefinitionData &>(*DefinitionData);
DL.IsGenericLambda = IsGeneric;
}

// Determine whether this type is an Interface Like type for
// __interface inheritance purposes.
bool isInterfaceLike() const;
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Sema/Scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ class Scope {
/// This is a scope of some OpenMP directive with
/// order clause which specifies concurrent
OpenMPOrderClauseScope = 0x4000000,
/// This is the scope for a lambda, after the lambda introducer.
/// Lambdas need two FunctionPrototypeScope scopes (because there is a
/// template scope in between), the outer scope does not increase the
/// depth of recursion.
LambdaScope = 0x8000000,
};

private:
Expand Down
10 changes: 8 additions & 2 deletions clang/include/clang/Sema/ScopeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,11 @@ class LambdaScopeInfo final :
/// The lambda's compiler-generated \c operator().
CXXMethodDecl *CallOperator = nullptr;

/// Indicate that we parsed the parameter list
/// at which point the mutability of the lambda
/// is known.
bool AfterParameterList = true;

/// Source range covering the lambda introducer [...].
SourceRange IntroducerRange;

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

/// Whether this is a mutable lambda.
bool Mutable = false;
/// Whether this is a mutable lambda. Until the mutable keyword is parsed,
/// we assume the lambda is mutable.
bool Mutable = true;

/// Whether the (empty) parameter list is explicit.
bool ExplicitParams = false;
Expand Down
61 changes: 41 additions & 20 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -7103,15 +7103,21 @@ class Sema final {
std::nullopt);

/// Endow the lambda scope info with the relevant properties.
void buildLambdaScope(sema::LambdaScopeInfo *LSI,
CXXMethodDecl *CallOperator,
void buildLambdaScope(sema::LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator,
SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
SourceLocation CaptureDefaultLoc,
bool ExplicitParams,
bool ExplicitResultType,
SourceLocation CaptureDefaultLoc, bool ExplicitParams,
bool Mutable);

CXXMethodDecl *CreateLambdaCallOperator(SourceRange IntroducerRange,
CXXRecordDecl *Class);
void CompleteLambdaCallOperator(
CXXMethodDecl *Method, SourceLocation LambdaLoc,
SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause,
TypeSourceInfo *MethodTyInfo, ConstexprSpecKind ConstexprKind,
StorageClass SC, ArrayRef<ParmVarDecl *> Params,
bool HasExplicitResultType);

/// Perform initialization analysis of the init-capture and perform
/// any implicit conversions such as an lvalue-to-rvalue conversion if
/// not being used to initialize a reference.
Expand All @@ -7132,11 +7138,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,
Expand All @@ -7146,28 +7150,38 @@ 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 ActOnLambdaExpressionAfterIntroducer(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);
void ActOnLambdaClosureQualifiers(LambdaIntroducer &Intro,
SourceLocation MutableLoc);

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

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

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

/// Introduce the instantiated captures of the lambda into the local
/// instantiation scope.
bool addInstantiatedCapturesToScope(
FunctionDecl *Function, const FunctionDecl *PatternDecl,
LocalInstantiationScope &Scope,
const MultiLevelTemplateArgumentList &TemplateArgs);

/// used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in
/// the case of lambdas) set up the LocalInstantiationScope of the current
/// function.
Expand Down
Loading

0 comments on commit d708a18

Please sign in to comment.