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:
Richard Smith 2022-04-13 21:34:08 -07:00
parent a4f47a99aa
commit 836e610d93
18 changed files with 376 additions and 836 deletions

View File

@ -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
------------------------------

View File

@ -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;

View File

@ -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<

View File

@ -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:

View File

@ -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;

View File

@ -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

View File

@ -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());

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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);
}

View File

@ -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.

View File

@ -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;

View File

@ -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}}
};
}

View File

@ -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);
}

View File

@ -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.

View File

@ -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>