forked from OSchip/llvm-project
Revert "[clang] Implement Change scope of lambda trailing-return-type"
This reverts commit c729d5be78
.
This change breaks thread safety annotations on lambdas.
This commit is contained in:
parent
a4f47a99aa
commit
836e610d93
|
@ -247,9 +247,6 @@ 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
|
||||
------------------------------
|
||||
|
|
|
@ -1799,20 +1799,6 @@ public:
|
|||
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;
|
||||
|
|
|
@ -7704,8 +7704,6 @@ 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<
|
||||
|
|
|
@ -44,11 +44,11 @@ public:
|
|||
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,12 +140,6 @@ public:
|
|||
/// 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:
|
||||
|
|
|
@ -831,28 +831,6 @@ public:
|
|||
/// 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;
|
||||
|
||||
|
|
|
@ -6852,9 +6852,11 @@ public:
|
|||
///
|
||||
/// 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, DeclContext *DeclCtx);
|
||||
VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc,
|
||||
QualType InitCaptureType,
|
||||
SourceLocation EllipsisLoc,
|
||||
IdentifierInfo *Id,
|
||||
unsigned InitStyle, Expr *Init);
|
||||
|
||||
/// Add an init-capture to a lambda scope.
|
||||
void addInitCapture(sema::LambdaScopeInfo *LSI, VarDecl *Var);
|
||||
|
@ -6863,28 +6865,21 @@ public:
|
|||
/// given lambda.
|
||||
void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
|
||||
|
||||
/// 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
|
||||
/// \brief This is called after parsing the explicit template parameter list
|
||||
/// on a lambda (if it exists) in C++2a.
|
||||
void ActOnLambdaExplicitTemplateParameterList(LambdaIntroducer &Intro,
|
||||
SourceLocation LAngleLoc,
|
||||
void ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
|
||||
ArrayRef<NamedDecl *> TParams,
|
||||
SourceLocation RAngleLoc,
|
||||
ExprResult RequiresClause);
|
||||
|
||||
void ActOnLambdaClosureQualifiers(LambdaIntroducer &Intro,
|
||||
SourceLocation MutableLoc,
|
||||
SourceLocation EndLoc, const DeclSpec &DS);
|
||||
/// 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);
|
||||
|
||||
/// ActOnStartOfLambdaDefinition - This is called just before we start
|
||||
/// parsing the body of a lambda; it analyzes the explicit captures and
|
||||
|
|
|
@ -1250,13 +1250,7 @@ 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);
|
||||
if (getLangOpts().CUDA) {
|
||||
|
@ -1306,7 +1300,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
|
|||
}
|
||||
|
||||
Actions.ActOnLambdaExplicitTemplateParameterList(
|
||||
Intro, LAngleLoc, TemplateParams, RAngleLoc, RequiresClause);
|
||||
LAngleLoc, TemplateParams, RAngleLoc, RequiresClause);
|
||||
++CurTemplateDepthTracker;
|
||||
}
|
||||
}
|
||||
|
@ -1324,31 +1318,28 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
|
|||
|
||||
TypeResult TrailingReturnType;
|
||||
SourceLocation TrailingReturnTypeLoc;
|
||||
SourceLocation LParenLoc, RParenLoc;
|
||||
SourceLocation DeclEndLoc;
|
||||
bool HasParentheses = false;
|
||||
bool HasSpecifiers = false;
|
||||
SourceLocation MutableLoc;
|
||||
|
||||
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.
|
||||
MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr);
|
||||
// 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 =
|
||||
[&](MutableArrayRef<DeclaratorChunk::ParamInfo> ParamInfo,
|
||||
[&](SourceLocation LParenLoc, SourceLocation RParenLoc,
|
||||
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;
|
||||
|
@ -1402,22 +1393,20 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
|
|||
/*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D,
|
||||
TrailingReturnType, TrailingReturnTypeLoc, &DS),
|
||||
std::move(Attr), DeclEndLoc);
|
||||
|
||||
if (HasParentheses && Tok.is(tok::kw_requires))
|
||||
ParseTrailingRequiresClause(D);
|
||||
};
|
||||
|
||||
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)) {
|
||||
ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
|
||||
Scope::FunctionDeclarationScope |
|
||||
Scope::DeclScope);
|
||||
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
T.consumeOpen();
|
||||
LParenLoc = T.getOpenLocation();
|
||||
SourceLocation LParenLoc = T.getOpenLocation();
|
||||
|
||||
// Parse parameter-declaration-clause.
|
||||
SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
|
||||
SourceLocation EllipsisLoc;
|
||||
|
||||
if (Tok.isNot(tok::r_paren)) {
|
||||
Actions.RecordParsingTemplateParameterDepth(
|
||||
|
@ -1435,38 +1424,36 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
|
|||
}
|
||||
|
||||
T.consumeClose();
|
||||
DeclEndLoc = RParenLoc = T.getCloseLocation();
|
||||
HasParentheses = true;
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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)
|
||||
// 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, DS);
|
||||
|
||||
if (HasSpecifiers || HasParentheses)
|
||||
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 |
|
||||
|
@ -1485,7 +1472,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
|
|||
StmtResult Stmt(ParseCompoundStatementBody());
|
||||
BodyScope.Exit();
|
||||
TemplateParamScope.Exit();
|
||||
LambdaScope.Exit();
|
||||
|
||||
if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid())
|
||||
return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope());
|
||||
|
|
|
@ -67,10 +67,8 @@ 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. Lambdas have an extra prototype
|
||||
// scope that doesn't add any depth.
|
||||
if (flags & FunctionPrototypeScope && !(flags & LambdaScope))
|
||||
PrototypeDepth++;
|
||||
// If this is a prototype scope, record that.
|
||||
if (flags & FunctionPrototypeScope) PrototypeDepth++;
|
||||
|
||||
if (flags & DeclScope) {
|
||||
if (flags & FunctionPrototypeScope)
|
||||
|
|
|
@ -2297,8 +2297,7 @@ 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) &&
|
||||
!LSI->BeforeLambdaQualifiersScope) {
|
||||
if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext)) {
|
||||
// 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.
|
||||
|
@ -2324,9 +2323,8 @@ LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) {
|
|||
return nullptr;
|
||||
}
|
||||
auto *CurLSI = dyn_cast<LambdaScopeInfo>(*I);
|
||||
if (CurLSI && CurLSI->Lambda && CurLSI->CallOperator &&
|
||||
!CurLSI->Lambda->Encloses(CurContext) &&
|
||||
!CurLSI->BeforeLambdaQualifiersScope) {
|
||||
if (CurLSI && CurLSI->Lambda &&
|
||||
!CurLSI->Lambda->Encloses(CurContext)) {
|
||||
// We have switched contexts due to template instantiation.
|
||||
assert(!CodeSynthesisContexts.empty());
|
||||
return nullptr;
|
||||
|
|
|
@ -292,11 +292,6 @@ 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()) {
|
||||
|
@ -313,6 +308,9 @@ 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;
|
||||
|
|
|
@ -3383,7 +3383,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 && !isUnevaluatedContext()) {
|
||||
if (BD->getDeclContext() != CurContext) {
|
||||
auto *DD = dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl());
|
||||
if (DD && DD->hasLocalStorage())
|
||||
diagnoseUncapturableValueReference(*this, Loc, BD);
|
||||
|
@ -18398,37 +18398,6 @@ 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,
|
||||
|
@ -18452,6 +18421,11 @@ 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();
|
||||
|
@ -18474,36 +18448,13 @@ 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 =
|
||||
IsInLambdaBeforeQualifiers
|
||||
? DC->getParent()
|
||||
: getParentOfCapturingContextOrNull(DC, Var, ExprLoc,
|
||||
BuildAndDiagnose, *this);
|
||||
DeclContext *ParentDC = 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.
|
||||
|
@ -18518,9 +18469,9 @@ bool Sema::tryCaptureVariable(
|
|||
FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex];
|
||||
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FSI);
|
||||
|
||||
|
||||
// Check whether we've already captured it.
|
||||
if (!IsInLambdaBeforeQualifiers &&
|
||||
isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
|
||||
if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
|
||||
DeclRefType)) {
|
||||
CSI->getCapture(Var).markUsed(BuildAndDiagnose);
|
||||
break;
|
||||
|
@ -18529,8 +18480,7 @@ 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 (!IsInLambdaBeforeQualifiers &&
|
||||
isGenericLambdaCallOperatorSpecialization(DC)) {
|
||||
if (isGenericLambdaCallOperatorSpecialization(DC)) {
|
||||
if (BuildAndDiagnose) {
|
||||
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
|
||||
if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {
|
||||
|
@ -18545,8 +18495,7 @@ bool Sema::tryCaptureVariable(
|
|||
}
|
||||
|
||||
// Try to capture variable-length arrays types.
|
||||
if (!IsInLambdaBeforeQualifiers &&
|
||||
Var->getType()->isVariablyModifiedType()) {
|
||||
if (Var->getType()->isVariablyModifiedType()) {
|
||||
// We're going to walk down into the type and look for VLA
|
||||
// expressions.
|
||||
QualType QTy = Var->getType();
|
||||
|
@ -18555,7 +18504,7 @@ bool Sema::tryCaptureVariable(
|
|||
captureVariablyModifiedType(Context, QTy, CSI);
|
||||
}
|
||||
|
||||
if (!IsInLambdaBeforeQualifiers && getLangOpts().OpenMP) {
|
||||
if (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
|
||||
|
@ -18636,11 +18585,11 @@ bool Sema::tryCaptureVariable(
|
|||
}
|
||||
return true;
|
||||
}
|
||||
Explicit = false;
|
||||
|
||||
FunctionScopesIndex--;
|
||||
if (!IsInLambdaBeforeQualifiers)
|
||||
DC = ParentDC;
|
||||
} while (IsInLambdaBeforeQualifiers || !VarDC->Equals(DC));
|
||||
DC = ParentDC;
|
||||
Explicit = false;
|
||||
} while (!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
|
||||
|
@ -18675,9 +18624,6 @@ 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,
|
||||
|
|
|
@ -1130,7 +1130,7 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda(
|
|||
|
||||
if (C.isCopyCapture()) {
|
||||
ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask);
|
||||
if (!CurLSI->Mutable)
|
||||
if (CurLSI->CallOperator->isConst())
|
||||
ClassType.addConst();
|
||||
return ASTCtx.getPointerType(ClassType);
|
||||
}
|
||||
|
|
|
@ -245,9 +245,8 @@ Sema::createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info,
|
|||
DeclContext *DC = CurContext;
|
||||
while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
|
||||
DC = DC->getParent();
|
||||
|
||||
bool IsGenericLambda =
|
||||
Info && getGenericLambdaTemplateParameterList(getCurLambda(), *this);
|
||||
bool IsGenericLambda = getGenericLambdaTemplateParameterList(getCurLambda(),
|
||||
*this);
|
||||
// Start constructing the lambda class.
|
||||
CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(
|
||||
Context, DC, Info, IntroducerRange.getBegin(), LambdaDependencyKind,
|
||||
|
@ -355,30 +354,6 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
|
|||
llvm_unreachable("unexpected context");
|
||||
}
|
||||
|
||||
static QualType
|
||||
buildTypeForLambdaCallOperator(Sema &S, clang::CXXRecordDecl *Class,
|
||||
TemplateParameterList *TemplateParams,
|
||||
TypeSourceInfo *MethodTypeInfo) {
|
||||
assert(MethodTypeInfo && "expected a non null type");
|
||||
|
||||
QualType MethodType = MethodTypeInfo->getType();
|
||||
// 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.
|
||||
if (Class->isDependentContext() || TemplateParams) {
|
||||
const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>();
|
||||
QualType Result = FPT->getReturnType();
|
||||
if (Result->isUndeducedType()) {
|
||||
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,
|
||||
|
@ -386,26 +361,29 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
|
|||
ArrayRef<ParmVarDecl *> Params,
|
||||
ConstexprSpecKind ConstexprKind,
|
||||
Expr *TrailingRequiresClause) {
|
||||
|
||||
LambdaScopeInfo *LSI = getCurLambda();
|
||||
|
||||
QualType MethodType = MethodTypeInfo->getType();
|
||||
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();
|
||||
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.
|
||||
if (Class->isDependentContext() || TemplateParams) {
|
||||
const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>();
|
||||
QualType Result = FPT->getReturnType();
|
||||
if (Result->isUndeducedType()) {
|
||||
Result = SubstAutoTypeDependent(Result);
|
||||
MethodType = Context.getFunctionType(Result, FPT->getParamTypes(),
|
||||
FPT->getExtProtoInfo());
|
||||
}
|
||||
}
|
||||
|
||||
// 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(
|
||||
|
@ -422,11 +400,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);
|
||||
|
@ -502,27 +480,14 @@ void Sema::handleLambdaNumbering(
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
void Sema::buildLambdaScope(LambdaScopeInfo *LSI,
|
||||
CXXMethodDecl *CallOperator,
|
||||
SourceRange IntroducerRange,
|
||||
LambdaCaptureDefault CaptureDefault,
|
||||
SourceLocation CaptureDefaultLoc,
|
||||
bool ExplicitParams,
|
||||
bool ExplicitResultType,
|
||||
bool Mutable) {
|
||||
LSI->CallOperator = CallOperator;
|
||||
CXXRecordDecl *LambdaClass = CallOperator->getParent();
|
||||
LSI->Lambda = LambdaClass;
|
||||
|
@ -534,27 +499,30 @@ static void buildLambdaScopeCaptures(LambdaScopeInfo *LSI,
|
|||
LSI->IntroducerRange = IntroducerRange;
|
||||
LSI->ExplicitParams = ExplicitParams;
|
||||
LSI->Mutable = Mutable;
|
||||
}
|
||||
|
||||
void Sema::buildLambdaScope(LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator,
|
||||
SourceRange IntroducerRange,
|
||||
LambdaCaptureDefault CaptureDefault,
|
||||
SourceLocation CaptureDefaultLoc,
|
||||
bool ExplicitParams, bool ExplicitResultType,
|
||||
bool Mutable) {
|
||||
buildLambdaScopeCaptures(LSI, CallOperator, IntroducerRange, CaptureDefault,
|
||||
CaptureDefaultLoc, ExplicitParams, Mutable);
|
||||
buildLambdaScopeReturnType(*this, LSI, CallOperator, ExplicitResultType);
|
||||
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::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
|
||||
LSI->finishedExplicitCaptures();
|
||||
}
|
||||
|
||||
void Sema::ActOnLambdaExplicitTemplateParameterList(
|
||||
LambdaIntroducer &Intro, SourceLocation LAngleLoc,
|
||||
ArrayRef<NamedDecl *> TParams, SourceLocation RAngleLoc,
|
||||
ExprResult RequiresClause) {
|
||||
void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
|
||||
ArrayRef<NamedDecl *> TParams,
|
||||
SourceLocation RAngleLoc,
|
||||
ExprResult RequiresClause) {
|
||||
LambdaScopeInfo *LSI = getCurLambda();
|
||||
assert(LSI && "Expected a lambda scope");
|
||||
assert(LSI->NumExplicitTemplateParams == 0 &&
|
||||
|
@ -570,6 +538,35 @@ void Sema::ActOnLambdaExplicitTemplateParameterList(
|
|||
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.
|
||||
///
|
||||
|
@ -856,9 +853,11 @@ QualType Sema::buildLambdaInitCaptureInitialization(
|
|||
return DeducedType;
|
||||
}
|
||||
|
||||
VarDecl *Sema::createLambdaInitCaptureVarDecl(
|
||||
SourceLocation Loc, QualType InitCaptureType, SourceLocation EllipsisLoc,
|
||||
IdentifierInfo *Id, unsigned InitStyle, Expr *Init, DeclContext *DeclCtx) {
|
||||
VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
|
||||
QualType InitCaptureType,
|
||||
SourceLocation EllipsisLoc,
|
||||
IdentifierInfo *Id,
|
||||
unsigned InitStyle, Expr *Init) {
|
||||
// FIXME: Retain the TypeSourceInfo from buildLambdaInitCaptureInitialization
|
||||
// rather than reconstructing it here.
|
||||
TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType, Loc);
|
||||
|
@ -869,8 +868,8 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(
|
|||
// 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, DeclCtx, Loc, Loc, Id,
|
||||
InitCaptureType, TSI, SC_Auto);
|
||||
VarDecl *NewVD = VarDecl::Create(Context, CurContext, Loc,
|
||||
Loc, Id, InitCaptureType, TSI, SC_Auto);
|
||||
NewVD->setInitCapture(true);
|
||||
NewVD->setReferenced(true);
|
||||
// FIXME: Pass in a VarDecl::InitializationStyle.
|
||||
|
@ -889,107 +888,12 @@ void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var) {
|
|||
Var->getType(), /*Invalid*/false);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
||||
Declarator &ParamInfo,
|
||||
Scope *CurScope) {
|
||||
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 =
|
||||
|
@ -1006,37 +910,181 @@ void Sema::ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurrentScope) {
|
|||
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, nullptr, LambdaDependencyKind, Intro.Default);
|
||||
LSI->Lambda = Class;
|
||||
Intro.Range, MethodTyInfo, LambdaDependencyKind, Intro.Default);
|
||||
CXXMethodDecl *Method =
|
||||
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
|
||||
ParamInfo.getDeclSpec().getConstexprSpecifier(),
|
||||
ParamInfo.getTrailingRequiresClause());
|
||||
if (ExplicitParams)
|
||||
CheckCXXDefaultArguments(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.
|
||||
// This represents the function body for the lambda function, check if we
|
||||
// have to apply optnone due to a pragma.
|
||||
AddRangeBasedOptnone(Method);
|
||||
|
||||
CXXMethodDecl *Method = CreateMethod(*this, Intro.Range, Class);
|
||||
LSI->CallOperator = Method;
|
||||
Method->setLexicalDeclContext(CurContext);
|
||||
// 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);
|
||||
|
||||
// Number the lambda for linkage purposes if necessary.
|
||||
handleLambdaNumbering(Class, Method);
|
||||
|
||||
// Introduce the function call operator as the current declaration context.
|
||||
PushDeclContext(CurScope, Method);
|
||||
|
||||
bool ContainsUnexpandedParameterPack = false;
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
|
||||
|
@ -1074,10 +1122,13 @@ void Sema::ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurrentScope) {
|
|||
}
|
||||
Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
|
||||
C->EllipsisLoc, C->Id, InitStyle,
|
||||
C->Init.get(), Method);
|
||||
assert(Var && "createLambdaInitCaptureVarDecl returned a null VarDecl?");
|
||||
CheckShadow(CurrentScope, Var);
|
||||
PushOnScopeChains(Var, CurrentScope, false);
|
||||
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);
|
||||
} else {
|
||||
assert(C->InitKind == LambdaCaptureInitKind::NoInit &&
|
||||
"init capture has valid but null init?");
|
||||
|
@ -1120,25 +1171,13 @@ void Sema::ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurrentScope) {
|
|||
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) {
|
||||
auto It = llvm::find_if(LSI->DelayedCaptures, [&Var](auto &&Pair) {
|
||||
return Pair.second.Var == Var;
|
||||
});
|
||||
if (It != LSI->DelayedCaptures.end()) {
|
||||
if (Var && LSI->isCaptured(Var)) {
|
||||
Diag(C->Loc, diag::err_capture_more_than_once)
|
||||
<< C->Id << SourceRange(It->second.Loc)
|
||||
<< C->Id << SourceRange(LSI->getCapture(Var).getLocation())
|
||||
<< FixItHint::CreateRemoval(
|
||||
SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
|
||||
} else
|
||||
|
@ -1148,6 +1187,15 @@ void Sema::ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurrentScope) {
|
|||
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;
|
||||
|
@ -1175,247 +1223,22 @@ void Sema::ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurrentScope) {
|
|||
ContainsUnexpandedParameterPack = true;
|
||||
}
|
||||
|
||||
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);
|
||||
if (C->Init.isUsable()) {
|
||||
addInitCapture(LSI, Var);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
|
||||
TryCapture_ExplicitByVal;
|
||||
tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
|
||||
}
|
||||
if (!LSI->Captures.empty())
|
||||
LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = C->ExplicitRange;
|
||||
}
|
||||
S.finishLambdaExplicitCaptures(LSI);
|
||||
}
|
||||
finishLambdaExplicitCaptures(LSI);
|
||||
|
||||
void Sema::ActOnLambdaClosureQualifiers(LambdaIntroducer &Intro,
|
||||
SourceLocation MutableLoc,
|
||||
SourceLocation EndLoc,
|
||||
const DeclSpec &DS) {
|
||||
LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
|
||||
|
||||
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);
|
||||
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());
|
||||
Param->setOwningFunction(Method);
|
||||
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) {
|
||||
if (!Param->getIdentifier())
|
||||
return true;
|
||||
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 (auto &&P : Params) {
|
||||
if (!P->getIdentifier())
|
||||
continue;
|
||||
if (CheckRedefinition(P))
|
||||
CheckShadow(CurScope, P);
|
||||
PushOnScopeChains(P, CurScope);
|
||||
}
|
||||
// Add lambda parameters into scope.
|
||||
addLambdaParameters(Intro.Captures, Method, CurScope);
|
||||
|
||||
// Enter a new evaluation context to insulate the lambda from any
|
||||
// cleanups from the enclosing full-expression.
|
||||
|
|
|
@ -13100,8 +13100,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
|||
}
|
||||
VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl(
|
||||
OldVD->getLocation(), InitQualType, NewC.EllipsisLoc,
|
||||
OldVD->getIdentifier(), OldVD->getInitStyle(), Init.get(),
|
||||
getSema().CurContext);
|
||||
OldVD->getIdentifier(), OldVD->getInitStyle(), Init.get());
|
||||
if (!NewVD) {
|
||||
Invalid = true;
|
||||
break;
|
||||
|
|
|
@ -12,16 +12,16 @@ auto with_float_2 = [&f(f)] { // ok, refers to outer f
|
|||
using T = double&;
|
||||
};
|
||||
|
||||
// Within the lambda-expression the identifier in the init-capture
|
||||
// hides any declaration of the same name in scopes enclosing
|
||||
// the lambda-expression.
|
||||
// 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.
|
||||
void hiding() {
|
||||
char c;
|
||||
(void) [c("foo")] {
|
||||
static_assert(sizeof(c) == sizeof(const char*), "");
|
||||
};
|
||||
(void)[c("bar")]()->decltype(c) { // inner c
|
||||
return "baz";
|
||||
(void) [c("bar")] () -> decltype(c) { // outer c, not init-capture
|
||||
return "baz"; // expected-error {{cannot initialize}}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
// 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 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);
|
||||
}
|
|
@ -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 2{{declaration shadows a local variable}}
|
||||
auto l4 = [var = param] (int param) { ; }; // expected-warning {{declaration shadows a local variable}}
|
||||
#endif
|
||||
|
||||
// Make sure that inner lambdas work as well.
|
||||
|
|
|
@ -1356,7 +1356,7 @@ C++20, informally referred to as C++2b.</p>
|
|||
<tr>
|
||||
<td>Change scope of lambda trailing-return-type</td>
|
||||
<td><a href="https://wg21.link/P2036R3">P2036R3</a></td>
|
||||
<td class="unreleased" align="center">Clang 15</td>
|
||||
<td class="none" align="center">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Multidimensional subscript operator</td>
|
||||
|
|
Loading…
Reference in New Issue