diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d2f1919f24a33..4463f03174543 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -130,11 +130,6 @@ C++20 Feature Support C++2b Feature Support ^^^^^^^^^^^^^^^^^^^^^ -- Implemented `P2036R3: Change scope of lambda trailing-return-type `_ - and `P2579R0 Mitigation strategies for P2036 `_. - These proposals modify 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/HIP Language Changes in Clang ---------------------------------- diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index ff8f8a1bb12d6..11276c77490ce 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1092,11 +1092,6 @@ class CXXRecordDecl : public RecordDecl { unsigned capture_size() const { return getLambdaData().NumCaptures; } - const LambdaCapture *getCapture(unsigned I) const { - assert(isLambda() && I < capture_size() && "invalid index for capture"); - return captures_begin() + I; - } - using conversion_iterator = UnresolvedSetIterator; conversion_iterator conversion_begin() const { @@ -1831,20 +1826,6 @@ class CXXRecordDecl : public RecordDecl { return getLambdaData().MethodTyInfo; } - void setLambdaTypeInfo(TypeSourceInfo *TS) { - assert(DefinitionData && DefinitionData->IsLambda && - "setting lambda property of non-lambda class"); - auto &DL = static_cast(*DefinitionData); - DL.MethodTyInfo = TS; - } - - void setLambdaIsGeneric(bool IsGeneric) { - assert(DefinitionData && DefinitionData->IsLambda && - "setting lambda property of non-lambda class"); - auto &DL = static_cast(*DefinitionData); - DL.IsGenericLambda = IsGeneric; - } - // Determine whether this type is an Interface Like type for // __interface inheritance purposes. bool isInterfaceLike() const; diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h index 9e81706cd2aa1..be5cdb62045b1 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -145,11 +145,6 @@ class Scope { /// This is a scope of some OpenMP directive with /// order clause which specifies concurrent OpenMPOrderClauseScope = 0x4000000, - /// This is the scope for a lambda, after the lambda introducer. - /// Lambdas need two FunctionPrototypeScope scopes (because there is a - /// template scope in between), the outer scope does not increase the - /// depth of recursion. - LambdaScope = 0x8000000, }; private: diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index 5888dee0a883d..65fa18fbb2903 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -838,11 +838,6 @@ class LambdaScopeInfo final : /// The lambda's compiler-generated \c operator(). CXXMethodDecl *CallOperator = nullptr; - /// Indicate that we parsed the parameter list - /// at which point the mutability of the lambda - /// is known. - bool AfterParameterList = true; - /// Source range covering the lambda introducer [...]. SourceRange IntroducerRange; @@ -854,9 +849,8 @@ class LambdaScopeInfo final : /// explicit captures. unsigned NumExplicitCaptures = 0; - /// Whether this is a mutable lambda. Until the mutable keyword is parsed, - /// we assume the lambda is mutable. - bool Mutable = true; + /// Whether this is a mutable lambda. + bool Mutable = false; /// Whether the (empty) parameter list is explicit. bool ExplicitParams = false; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 67d55ab3d8c6d..b8a0727d65103 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7103,21 +7103,15 @@ class Sema final { std::nullopt); /// Endow the lambda scope info with the relevant properties. - void buildLambdaScope(sema::LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator, + void buildLambdaScope(sema::LambdaScopeInfo *LSI, + CXXMethodDecl *CallOperator, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, - SourceLocation CaptureDefaultLoc, bool ExplicitParams, + SourceLocation CaptureDefaultLoc, + bool ExplicitParams, + bool ExplicitResultType, bool Mutable); - CXXMethodDecl *CreateLambdaCallOperator(SourceRange IntroducerRange, - CXXRecordDecl *Class); - void CompleteLambdaCallOperator( - CXXMethodDecl *Method, SourceLocation LambdaLoc, - SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause, - TypeSourceInfo *MethodTyInfo, ConstexprSpecKind ConstexprKind, - StorageClass SC, ArrayRef Params, - bool HasExplicitResultType); - /// Perform initialization analysis of the init-capture and perform /// any implicit conversions such as an lvalue-to-rvalue conversion if /// not being used to initialize a reference. @@ -7138,9 +7132,11 @@ class Sema final { /// /// CodeGen handles emission of lambda captures, ignoring these dummy /// variables appropriately. - VarDecl *createLambdaInitCaptureVarDecl( - SourceLocation Loc, QualType InitCaptureType, SourceLocation EllipsisLoc, - IdentifierInfo *Id, unsigned InitStyle, Expr *Init, 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, @@ -7150,38 +7146,28 @@ class Sema final { /// 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 ActOnLambdaExpressionAfterIntroducer(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 TParams, SourceLocation RAngleLoc, ExprResult RequiresClause); - void ActOnLambdaClosureQualifiers(LambdaIntroducer &Intro, - SourceLocation MutableLoc); + /// Introduce the lambda parameters into scope. + void addLambdaParameters( + ArrayRef Captures, + CXXMethodDecl *CallOperator, Scope *CurScope); - void ActOnLambdaClosureParameters( - Scope *LambdaScope, - MutableArrayRef ParamInfo); + /// 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 /// arguments, and sets up various data-structures for the body of the /// lambda. void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, - Declarator &ParamInfo, const DeclSpec &DS); + Declarator &ParamInfo, Scope *CurScope); /// ActOnLambdaError - If there is an error parsing a lambda, this callback /// is invoked to pop the information about the lambda. @@ -7276,13 +7262,6 @@ class Sema final { LocalInstantiationScope &Scope, const MultiLevelTemplateArgumentList &TemplateArgs); - /// Introduce the instantiated captures of the lambda into the local - /// instantiation scope. - bool addInstantiatedCapturesToScope( - FunctionDecl *Function, const FunctionDecl *PatternDecl, - LocalInstantiationScope &Scope, - const MultiLevelTemplateArgumentList &TemplateArgs); - /// used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in /// the case of lambdas) set up the LocalInstantiationScope of the current /// function. diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 45460db85b878..7f09120574a7a 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1275,19 +1275,18 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc, "lambda expression parsing"); + + + // FIXME: Call into Actions to add any init-capture declarations to the + // scope while parsing the lambda-declarator and compound-statement. + // Parse lambda-declarator[opt]. DeclSpec DS(AttrFactory); Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::LambdaExpr); TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); - - ParseScope LambdaScope(this, Scope::LambdaScope | Scope::DeclScope | - Scope::FunctionDeclarationScope | - Scope::FunctionPrototypeScope); - Actions.PushLambdaScope(); - Actions.ActOnLambdaExpressionAfterIntroducer(Intro, getCurScope()); - ParsedAttributes Attributes(AttrFactory); + ParsedAttributes Attr(AttrFactory); if (getLangOpts().CUDA) { // In CUDA code, GNU attributes are allowed to appear immediately after the // "[...]", even if there is no "(...)" before the lambda body. @@ -1298,22 +1297,22 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( if (Tok.is(tok::kw___noinline__)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - Attributes.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, - 0, ParsedAttr::AS_Keyword); + Attr.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + ParsedAttr::AS_Keyword); } else if (Tok.is(tok::kw___attribute)) - ParseGNUAttributes(Attributes, nullptr, &D); + ParseGNUAttributes(Attr, nullptr, &D); else break; } - D.takeAttributes(Attributes); + D.takeAttributes(Attr); } // Helper to emit a warning if we see a CUDA host/device/global attribute // after '(...)'. nvcc doesn't accept this. auto WarnIfHasCUDATargetAttr = [&] { if (getLangOpts().CUDA) - for (const ParsedAttr &A : Attributes) + for (const ParsedAttr &A : Attr) if (A.getKind() == ParsedAttr::AT_CUDADevice || A.getKind() == ParsedAttr::AT_CUDAHost || A.getKind() == ParsedAttr::AT_CUDAGlobal) @@ -1350,7 +1349,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( } Actions.ActOnLambdaExplicitTemplateParameterList( - Intro, LAngleLoc, TemplateParams, RAngleLoc, RequiresClause); + LAngleLoc, TemplateParams, RAngleLoc, RequiresClause); ++CurTemplateDepthTracker; } } @@ -1368,36 +1367,32 @@ 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, Attributes); - // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update - // the DeclEndLoc. - SourceLocation ConstexprLoc; - SourceLocation ConstevalLoc; - SourceLocation StaticLoc; - - tryConsumeLambdaSpecifierToken(*this, MutableLoc, StaticLoc, ConstexprLoc, - ConstevalLoc, DeclEndLoc); - - DiagnoseStaticSpecifierRestrictions(*this, StaticLoc, MutableLoc, Intro); - - addStaticToLambdaDeclSpecifier(*this, StaticLoc, DS); - addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); - addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS); - }; auto ParseLambdaSpecifiers = - [&](MutableArrayRef ParamInfo, + [&](SourceLocation LParenLoc, SourceLocation RParenLoc, + MutableArrayRef 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 lambda specifiers and update the DeclEndLoc. + SourceLocation MutableLoc; + SourceLocation StaticLoc; + SourceLocation ConstexprLoc; + SourceLocation ConstevalLoc; + tryConsumeLambdaSpecifierToken(*this, MutableLoc, StaticLoc, + ConstexprLoc, ConstevalLoc, DeclEndLoc); + + DiagnoseStaticSpecifierRestrictions(*this, StaticLoc, MutableLoc, + Intro); + + addStaticToLambdaDeclSpecifier(*this, StaticLoc, DS); + addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); + addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS); // Parse exception-specification[opt]. ExceptionSpecificationType ESpecType = EST_None; SourceRange ESpecRange; @@ -1405,7 +1400,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( SmallVector DynamicExceptionRanges; ExprResult NoexceptExpr; CachedTokens *ExceptionSpecTokens; - ESpecType = tryParseExceptionSpecification( /*Delayed=*/false, ESpecRange, DynamicExceptions, DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens); @@ -1414,8 +1408,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DeclEndLoc = ESpecRange.getEnd(); // Parse attribute-specifier[opt]. - if (MaybeParseCXX11Attributes(Attributes)) - DeclEndLoc = Attributes.Range.getEnd(); + if (MaybeParseCXX11Attributes(Attr)) + DeclEndLoc = Attr.Range.getEnd(); // Parse OpenCL addr space attribute. if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local, @@ -1451,32 +1445,27 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( /*ExceptionSpecTokens*/ nullptr, /*DeclsInPrototype=*/std::nullopt, LParenLoc, FunLocalRangeEnd, D, TrailingReturnType, TrailingReturnTypeLoc, &DS), - std::move(Attributes), DeclEndLoc); - - Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc); - - if (HasParentheses && Tok.is(tok::kw_requires)) - ParseTrailingRequiresClause(D); + std::move(Attr), DeclEndLoc); }; - ParseScope Prototype(this, Scope::FunctionPrototypeScope | - Scope::FunctionDeclarationScope | - Scope::DeclScope); - - // Parse parameter-declaration-clause. - SmallVector 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 ParamInfo; + SourceLocation EllipsisLoc; if (Tok.isNot(tok::r_paren)) { Actions.RecordParsingTemplateParameterDepth( CurTemplateDepthTracker.getOriginalDepth()); - ParseParameterDeclarationClause(D, Attributes, ParamInfo, EllipsisLoc); + ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); // For a generic lambda, each 'auto' within the parameter declaration // clause creates a template type parameter, so increment the depth. // If we've parsed any explicit template parameters, then the depth will @@ -1487,47 +1476,44 @@ 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_static, - tok::kw___private, tok::kw___global, tok::kw___local, - tok::kw___constant, tok::kw___generic, tok::kw_groupshared, - 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_static, + tok::kw___private, tok::kw___global, tok::kw___local, + tok::kw___constant, tok::kw___generic, + tok::kw_groupshared, 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(), "() "); - } - if (HasParentheses || HasSpecifiers) - ParseConstexprAndMutableSpecifiers(); - - Actions.ActOnLambdaClosureParameters(getCurScope(), ParamInfo); - - if (!HasParentheses) - Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc); - - if (HasSpecifiers || HasParentheses) - ParseLambdaSpecifiers(ParamInfo, EllipsisLoc); + SourceLocation NoLoc; + // Parse lambda-specifiers. + std::vector EmptyParamInfo; + ParseLambdaSpecifiers(/*LParenLoc=*/NoLoc, /*RParenLoc=*/NoLoc, + EmptyParamInfo, /*EllipsisLoc=*/NoLoc); + } WarnIfHasCUDATargetAttr(); - Prototype.Exit(); - // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using // it. unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope; ParseScope BodyScope(this, ScopeFlags); - Actions.ActOnStartOfLambdaDefinition(Intro, D, DS); + Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope()); // Parse compound-statement. if (!Tok.is(tok::l_brace)) { @@ -1539,7 +1525,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()); diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp index 4570d8c615fe5..c995c7e65f4b7 100644 --- a/clang/lib/Sema/Scope.cpp +++ b/clang/lib/Sema/Scope.cpp @@ -70,10 +70,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) diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 770b8db7e3501..e5566b177affc 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2333,8 +2333,7 @@ FunctionScopeInfo *Sema::getEnclosingFunction() const { LambdaScopeInfo *Sema::getEnclosingLambda() const { for (auto *Scope : llvm::reverse(FunctionScopes)) { if (auto *LSI = dyn_cast(Scope)) { - if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext) && - LSI->AfterParameterList) { + 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. @@ -2360,8 +2359,8 @@ LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) { return nullptr; } auto *CurLSI = dyn_cast(*I); - if (CurLSI && CurLSI->Lambda && CurLSI->CallOperator && - !CurLSI->Lambda->Encloses(CurContext) && CurLSI->AfterParameterList) { + if (CurLSI && CurLSI->Lambda && + !CurLSI->Lambda->Encloses(CurContext)) { // We have switched contexts due to template instantiation. assert(!CodeSynthesisContexts.empty()); return nullptr; diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 1ef83ea52e730..daa61ba45e8e3 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -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; diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 765110d6b230d..a92bbde113fcd 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -519,55 +519,6 @@ bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, .isInvalid(); } -bool Sema::addInstantiatedCapturesToScope( - FunctionDecl *Function, const FunctionDecl *PatternDecl, - LocalInstantiationScope &Scope, - const MultiLevelTemplateArgumentList &TemplateArgs) { - const auto *LambdaClass = cast(Function)->getParent(); - const auto *LambdaPattern = cast(PatternDecl)->getParent(); - - unsigned Instantiated = 0; - for (const LambdaCapture &CapturePattern : LambdaPattern->captures()) { - if (!CapturePattern.capturesVariable()) { - Instantiated++; - continue; - } - const ValueDecl *CapturedPattern = CapturePattern.getCapturedVar(); - if (!CapturedPattern->isParameterPack()) { - ValueDecl *CapturedVar = - LambdaClass->getCapture(Instantiated)->getCapturedVar(); - if (cast(Function)->isConst()) { - QualType T = CapturedVar->getType(); - T.addConst(); - CapturedVar->setType(T); - } - if (CapturedVar->isInitCapture()) - Scope.InstantiatedLocal(CapturedPattern, CapturedVar); - Instantiated++; - } else { - Scope.MakeInstantiatedLocalArgPack(CapturedPattern); - std::optional NumArgumentsInExpansion = - getNumArgumentsInExpansion(CapturedPattern->getType(), TemplateArgs); - if (!NumArgumentsInExpansion) - continue; - for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) { - ValueDecl *CapturedVar = - LambdaClass->getCapture(Instantiated)->getCapturedVar(); - if (cast(Function)->isConst()) { - QualType T = CapturedVar->getType(); - T.addConst(); - CapturedVar->setType(T); - } - if (CapturedVar->isInitCapture()) - Scope.InstantiatedLocalPackArg(CapturedPattern, - cast(CapturedVar)); - Instantiated++; - } - } - } - return false; -} - bool Sema::SetupConstraintScope( FunctionDecl *FD, std::optional> TemplateArgs, MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) { @@ -601,11 +552,6 @@ bool Sema::SetupConstraintScope( if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(), Scope, MLTAL)) return true; - // Make sure the captures are also added to the instantiation scope. - if (isLambdaCallOperator(FD) && - addInstantiatedCapturesToScope(FD, FromMemTempl->getTemplatedDecl(), - Scope, MLTAL)) - return true; } return false; @@ -630,11 +576,6 @@ bool Sema::SetupConstraintScope( // child-function. if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL)) return true; - - // Make sure the captures are also added to the instantiation scope. - if (isLambdaCallOperator(FD) && - addInstantiatedCapturesToScope(FD, InstantiatedFrom, Scope, MLTAL)) - return true; } return false; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 829765c7c4615..6758797a11071 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -19082,6 +19082,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 = !VD->hasLocalStorage(); @@ -19107,34 +19112,12 @@ bool Sema::tryCaptureVariable( bool Explicit = (Kind != TryCapture_Implicit); unsigned FunctionScopesIndex = MaxFunctionScopesIndex; do { - - LambdaScopeInfo *LSI = nullptr; - if (!FunctionScopes.empty()) - LSI = dyn_cast_or_null( - FunctionScopes[FunctionScopesIndex]); - - bool IsInScopeDeclarationContext = - !LSI || LSI->AfterParameterList || CurContext == LSI->CallOperator; - - if (LSI && !LSI->AfterParameterList) { - // This allows capturing parameters from a default value which does not - // seems correct - if (isa(Var) && !Var->getDeclContext()->isFunctionOrMethod()) - return true; - } - // If the variable is declared in the current context, there is no need to - // capture it. - if (IsInScopeDeclarationContext && - FunctionScopesIndex == MaxFunctionScopesIndex && VarDC == DC) - return true; - // Only block literals, captured statements, and lambda expressions can // capture; other scopes don't work. - DeclContext *ParentDC = - !IsInScopeDeclarationContext - ? 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. @@ -19149,6 +19132,7 @@ bool Sema::tryCaptureVariable( FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex]; CapturingScopeInfo *CSI = cast(FSI); + // Check whether we've already captured it. if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType, DeclRefType)) { @@ -19264,10 +19248,10 @@ bool Sema::tryCaptureVariable( } return true; } - Explicit = false; + FunctionScopesIndex--; - if (IsInScopeDeclarationContext) - DC = ParentDC; + DC = ParentDC; + Explicit = false; } while (!VarDC->Equals(DC)); // Walk back down the scope stack, (e.g. from outer lambda to inner lambda) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 17408ef9504ec..ef012770747ca 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1136,7 +1136,7 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda( if (C.isCopyCapture()) { ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask); - if (!CurLSI->Mutable) + if (CurLSI->CallOperator->isConst()) ClassType.addConst(); return ASTCtx.getPointerType(ClassType); } diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 2b2b2e3afd86a..00ab6ba580bfe 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -247,9 +247,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, @@ -365,13 +364,14 @@ 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"); - +CXXMethodDecl *Sema::startLambdaDefinition( + CXXRecordDecl *Class, SourceRange IntroducerRange, + TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc, + ArrayRef Params, ConstexprSpecKind ConstexprKind, + StorageClass SC, Expr *TrailingRequiresClause) { QualType MethodType = MethodTypeInfo->getType(); + TemplateParameterList *TemplateParams = + getGenericLambdaTemplateParameterList(getCurLambda(), *this); // If a lambda appears in a dependent context or is a generic lambda (has // template parameters) and has an 'auto' return type, deduce it to a // dependent type. @@ -379,12 +379,58 @@ buildTypeForLambdaCallOperator(Sema &S, clang::CXXRecordDecl *Class, const FunctionProtoType *FPT = MethodType->castAs(); QualType Result = FPT->getReturnType(); if (Result->isUndeducedType()) { - Result = S.SubstAutoTypeDependent(Result); - MethodType = S.Context.getFunctionType(Result, FPT->getParamTypes(), - FPT->getExtProtoInfo()); + Result = SubstAutoTypeDependent(Result); + MethodType = Context.getFunctionType(Result, FPT->getParamTypes(), + FPT->getExtProtoInfo()); } } - return MethodType; + + // 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 + = Context.DeclarationNames.getCXXOperatorName(OO_Call); + DeclarationNameLoc MethodNameLoc = + DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange); + CXXMethodDecl *Method = CXXMethodDecl::Create( + Context, Class, EndLoc, + DeclarationNameInfo(MethodName, IntroducerRange.getBegin(), + MethodNameLoc), + MethodType, MethodTypeInfo, SC, getCurFPFeatures().isFPConstrained(), + /*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause); + Method->setAccess(AS_public); + if (!TemplateParams) + Class->addDecl(Method); + + // Temporarily set the lexical declaration context to the current + // 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; + if (TemplateMethod) { + TemplateMethod->setAccess(AS_public); + Method->setDescribedFunctionTemplate(TemplateMethod); + Class->addDecl(TemplateMethod); + TemplateMethod->setLexicalDeclContext(CurContext); + } + + // Add parameters. + if (!Params.empty()) { + Method->setParams(Params); + CheckParmsForFunctionDef(Params, + /*CheckParameterNames=*/false); + + for (auto *P : Method->parameters()) + P->setOwningFunction(Method); + } + + return Method; } void Sema::handleLambdaNumbering( @@ -442,25 +488,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; - } -} - -void Sema::buildLambdaScope(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; @@ -472,16 +507,30 @@ void Sema::buildLambdaScope(LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator, LSI->IntroducerRange = IntroducerRange; LSI->ExplicitParams = ExplicitParams; LSI->Mutable = Mutable; + + if (ExplicitResultType) { + LSI->ReturnType = CallOperator->getReturnType(); + + if (!LSI->ReturnType->isDependentType() && + !LSI->ReturnType->isVoidType()) { + if (RequireCompleteType(CallOperator->getBeginLoc(), LSI->ReturnType, + diag::err_lambda_incomplete_result)) { + // Do nothing. + } + } + } else { + LSI->HasImplicitReturnType = true; + } } void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) { LSI->finishedExplicitCaptures(); } -void Sema::ActOnLambdaExplicitTemplateParameterList( - LambdaIntroducer &Intro, SourceLocation LAngleLoc, - ArrayRef TParams, SourceLocation RAngleLoc, - ExprResult RequiresClause) { +void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc, + ArrayRef TParams, + SourceLocation RAngleLoc, + ExprResult RequiresClause) { LambdaScopeInfo *LSI = getCurLambda(); assert(LSI && "Expected a lambda scope"); assert(LSI->NumExplicitTemplateParams == 0 && @@ -497,6 +546,35 @@ void Sema::ActOnLambdaExplicitTemplateParameterList( LSI->RequiresClause = RequiresClause; } +void Sema::addLambdaParameters( + ArrayRef 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. /// @@ -783,9 +861,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); @@ -796,8 +876,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. @@ -817,46 +897,35 @@ 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(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, - std::nullopt, EPI); - return S.Context.getTrivialTypeSourceInfo(MethodTy, Loc); -} +void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, + Declarator &ParamInfo, + Scope *CurScope) { + LambdaScopeInfo *const LSI = getCurLambda(); + assert(LSI && "LambdaScopeInfo should be on stack!"); -static TypeSourceInfo *getLambdaType(Sema &S, LambdaIntroducer &Intro, - Declarator &ParamInfo, Scope *CurScope, - SourceLocation Loc, - bool &ExplicitResultType) { + // 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 = + CXXRecordDecl::LDK_Unknown; + if (LSI->NumExplicitTemplateParams > 0) { + auto *TemplateParamScope = CurScope->getTemplateParamParent(); + assert(TemplateParamScope && + "Lambda with explicit template param list should establish a " + "template param scope"); + assert(TemplateParamScope->getParent()); + if (TemplateParamScope->getParent()->getTemplateParamParent() != nullptr) + LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent; + } else if (CurScope->getTemplateParamParent() != nullptr) { + LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent; + } - ExplicitResultType = false; + // Determine the signature of the call operator. + TypeSourceInfo *MethodTyInfo; + bool ExplicitParams = true; + bool ExplicitResultType = true; + bool ContainsUnexpandedParameterPack = false; + SourceLocation EndLoc; + SmallVector Params; assert( (ParamInfo.getDeclSpec().getStorageClassSpec() == @@ -866,174 +935,146 @@ static TypeSourceInfo *getLambdaType(Sema &S, LambdaIntroducer &Intro, bool IsLambdaStatic = ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static; - TypeSourceInfo *MethodTyInfo; - if (ParamInfo.getNumTypeObjects() == 0) { - MethodTyInfo = getDummyLambdaType(S, Loc); + // 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, + std::nullopt, 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() && !IsLambdaStatic) { + 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 (!FTI.hasMutableQualifier() && !IsLambdaStatic) - FTI.getOrCreateMethodQualifiers().SetTypeQual(DeclSpec::TQ_const, Loc); - if (ExplicitResultType && S.getLangOpts().HLSL) { + if (ExplicitResultType && getLangOpts().HLSL) { QualType RetTy = FTI.getTrailingReturnType().get(); if (!RetTy.isNull()) { // HLSL does not support specifying an address space on a lambda return // type. LangAS AddressSpace = RetTy.getAddressSpace(); if (AddressSpace != LangAS::Default) - S.Diag(FTI.getTrailingReturnTypeLoc(), - diag::err_return_value_with_address_space); + Diag(FTI.getTrailingReturnTypeLoc(), + diag::err_return_value_with_address_space); } } - MethodTyInfo = S.GetTypeForDeclarator(ParamInfo, CurScope); - assert(MethodTyInfo && "no type from lambda-declarator"); + if (FTIHasNonVoidParameters(FTI)) { + Params.reserve(FTI.NumParams); + for (unsigned i = 0, e = FTI.NumParams; i != e; ++i) + Params.push_back(cast(FTI.Params[i].Param)); + } // Check for unexpanded parameter packs in the method type. if (MethodTyInfo->getType()->containsUnexpandedParameterPack()) - S.DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo, - S.UPPC_DeclarationType); - } - return MethodTyInfo; -} - -CXXMethodDecl *Sema::CreateLambdaCallOperator(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 = - Context.DeclarationNames.getCXXOperatorName(OO_Call); - DeclarationNameLoc MethodNameLoc = - DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange.getBegin()); - CXXMethodDecl *Method = CXXMethodDecl::Create( - Context, Class, SourceLocation(), - DeclarationNameInfo(MethodName, IntroducerRange.getBegin(), - MethodNameLoc), - QualType(), nullptr, SC_None, getCurFPFeatures().isFPConstrained(), - /*isInline=*/true, ConstexprSpecKind::Unspecified, SourceLocation(), - nullptr); - Method->setAccess(AS_public); - return Method; -} - -void Sema::CompleteLambdaCallOperator( - CXXMethodDecl *Method, SourceLocation LambdaLoc, - SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause, - TypeSourceInfo *MethodTyInfo, ConstexprSpecKind ConstexprKind, - StorageClass SC, ArrayRef Params, - bool HasExplicitResultType) { - - LambdaScopeInfo *LSI = getCurrentLambdaScopeUnsafe(*this); - - if (TrailingRequiresClause) - Method->setTrailingRequiresClause(TrailingRequiresClause); - - TemplateParameterList *TemplateParams = - getGenericLambdaTemplateParameterList(LSI, *this); - - DeclContext *DC = Method->getLexicalDeclContext(); - Method->setLexicalDeclContext(LSI->Lambda); - if (TemplateParams) { - FunctionTemplateDecl *TemplateMethod = FunctionTemplateDecl::Create( - Context, LSI->Lambda, Method->getLocation(), Method->getDeclName(), - TemplateParams, Method); - TemplateMethod->setAccess(AS_public); - Method->setDescribedFunctionTemplate(TemplateMethod); - LSI->Lambda->addDecl(TemplateMethod); - TemplateMethod->setLexicalDeclContext(DC); - } else { - LSI->Lambda->addDecl(Method); + DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo, + UPPC_DeclarationType); } - LSI->Lambda->setLambdaIsGeneric(TemplateParams); - LSI->Lambda->setLambdaTypeInfo(MethodTyInfo); - - Method->setLexicalDeclContext(DC); - Method->setLocation(LambdaLoc); - Method->setInnerLocStart(CallOperatorLoc); - Method->setTypeSourceInfo(MethodTyInfo); - Method->setType(buildTypeForLambdaCallOperator(*this, LSI->Lambda, - TemplateParams, MethodTyInfo)); - Method->setConstexprKind(ConstexprKind); - Method->setStorageClass(SC); - if (!Params.empty()) { - CheckParmsForFunctionDef(Params, /*CheckParameterNames=*/false); - Method->setParams(Params); - for (auto P : Method->parameters()) - P->setOwningFunction(Method); - } - - buildLambdaScopeReturnType(*this, LSI, Method, HasExplicitResultType); -} -void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro, - Scope *CurrentScope) { - - LambdaScopeInfo *LSI = getCurLambda(); - assert(LSI && "LambdaScopeInfo should be on stack!"); + CXXRecordDecl *Class = createLambdaClosureType( + Intro.Range, MethodTyInfo, LambdaDependencyKind, Intro.Default); + CXXMethodDecl *Method = + startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params, + ParamInfo.getDeclSpec().getConstexprSpecifier(), + IsLambdaStatic ? SC_Static : SC_None, + ParamInfo.getTrailingRequiresClause()); + if (ExplicitParams) + CheckCXXDefaultArguments(Method); - 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->AfterParameterList = false; + // This represents the function body for the lambda function, check if we + // have to apply optnone due to a pragma. + AddRangeBasedOptnone(Method); - assert(LSI->NumExplicitTemplateParams == 0); + // code_seg attribute on lambda apply to the method. + if (Attr *A = getImplicitCodeSegOrSectionAttrForFunction(Method, /*IsDefinition=*/true)) + Method->addAttr(A); - // 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 = - CXXRecordDecl::LDK_Unknown; - if (LSI->NumExplicitTemplateParams > 0) { - Scope *TemplateParamScope = CurScope->getTemplateParamParent(); - assert(TemplateParamScope && - "Lambda with explicit template param list should establish a " - "template param scope"); - assert(TemplateParamScope->getParent()); - if (TemplateParamScope->getParent()->getTemplateParamParent() != nullptr) - LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent; - } else if (CurScope->getTemplateParamParent() != nullptr) { - LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent; - } + // Attributes on the lambda apply to the method. + ProcessDeclAttributes(CurScope, Method, ParamInfo); - CXXRecordDecl *Class = createLambdaClosureType( - Intro.Range, nullptr, LambdaDependencyKind, Intro.Default); - LSI->Lambda = Class; + // CUDA lambdas get implicit host and device attributes. + if (getLangOpts().CUDA) + CUDASetLambdaAttrs(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. + // OpenMP lambdas might get assumumption attributes. + if (LangOpts.OpenMP) + ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Method); - CXXMethodDecl *Method = CreateLambdaCallOperator(Intro.Range, Class); - LSI->CallOperator = Method; - Method->setLexicalDeclContext(CurContext); + // 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::DenseMap CaptureNames; + llvm::SmallSet 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); + ? 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 @@ -1046,7 +1087,7 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro, continue; } - // C++20 [expr.prim.lambda]p8: + // 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 @@ -1112,11 +1153,13 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro, } Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(), C->EllipsisLoc, C->Id, InitStyle, - C->Init.get(), Method); - assert(Var && "createLambdaInitCaptureVarDecl returned a null VarDecl?"); - if (auto *V = dyn_cast(Var)) - CheckShadow(CurrentScope, V); - 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?"); @@ -1162,33 +1205,31 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro, continue; } - // C++11 [expr.prim.lambda]p10: - // [...] each such lookup shall find a variable with automatic storage - // duration declared in the reaching scope of the local lambda expression. - // Note that the 'reaching scope' check happens in tryCaptureVariable(). - if (!Var) { - Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id; - continue; - } - // C++11 [expr.prim.lambda]p8: // An identifier or this shall not appear more than once in a // lambda-capture. - if (auto [It, Inserted] = CaptureNames.insert(std::pair{C->Id, Var}); - !Inserted) { - if (C->InitKind == LambdaCaptureInitKind::NoInit && - !Var->isInitCapture()) { + if (!CaptureNames.insert(C->Id).second) { + if (Var && LSI->isCaptured(Var)) { Diag(C->Loc, diag::err_capture_more_than_once) - << C->Id << It->second->getBeginLoc() + << C->Id << SourceRange(LSI->getCapture(Var).getLocation()) << FixItHint::CreateRemoval( SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc)); } else // Previous capture captured something different (one or both was - // an init-capture): no fixit. + // an init-cpature): no fixit. Diag(C->Loc, diag::err_capture_more_than_once) << C->Id; 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; @@ -1220,167 +1261,20 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro, if (C->Init.isUsable()) { addInitCapture(LSI, cast(Var), C->Kind == LCK_ByRef); - PushOnScopeChains(Var, CurScope, false); } else { - TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef - : TryCapture_ExplicitByVal; + 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; } finishLambdaExplicitCaptures(LSI); - LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack; - PopDeclContext(); -} - -void Sema::ActOnLambdaClosureQualifiers(LambdaIntroducer &Intro, - SourceLocation MutableLoc) { - - LambdaScopeInfo *LSI = getCurrentLambdaScopeUnsafe(*this); - LSI->Mutable = MutableLoc.isValid(); - ContextRAII Context(*this, LSI->CallOperator, /*NewThisContext*/ false); - - // 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); -} - -void Sema::ActOnLambdaClosureParameters( - Scope *LambdaScope, MutableArrayRef Params) { - LambdaScopeInfo *LSI = getCurrentLambdaScopeUnsafe(*this); - PushDeclContext(LambdaScope, LSI->CallOperator); - - for (const DeclaratorChunk::ParamInfo &P : Params) { - auto *Param = cast(P.Param); - Param->setOwningFunction(LSI->CallOperator); - if (Param->getIdentifier()) - PushOnScopeChains(Param, LambdaScope, false); - } - - LSI->AfterParameterList = true; -} - -void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, - Declarator &ParamInfo, - const DeclSpec &DS) { - - LambdaScopeInfo *LSI = getCurrentLambdaScopeUnsafe(*this); - LSI->CallOperator->setConstexprKind(DS.getConstexprSpecifier()); - - SmallVector Params; - bool ExplicitResultType; - - SourceLocation TypeLoc, CallOperatorLoc; - if (ParamInfo.getNumTypeObjects() == 0) { - CallOperatorLoc = 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(); - CallOperatorLoc = ParamInfo.getSourceRange().getEnd(); - } - - CXXRecordDecl *Class = LSI->Lambda; - CXXMethodDecl *Method = LSI->CallOperator; - - TypeSourceInfo *MethodTyInfo = getLambdaType( - *this, Intro, ParamInfo, getCurScope(), TypeLoc, 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(FTI.Params[I].Param); - Param->setScopeInfo(0, Params.size()); - Params.push_back(Param); - } - } - - bool IsLambdaStatic = - ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static; - - CompleteLambdaCallOperator( - Method, Intro.Range.getBegin(), CallOperatorLoc, - ParamInfo.getTrailingRequiresClause(), MethodTyInfo, - ParamInfo.getDeclSpec().getConstexprSpecifier(), - IsLambdaStatic ? SC_Static : SC_None, Params, ExplicitResultType); - - ContextRAII ManglingContext(*this, Class->getDeclContext()); - 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->Captures) { - if (!C.isVariableCapture()) - continue; - ValueDecl *Var = C.getVariable(); - if (Var && Var->isInitCapture()) { - PushOnScopeChains(Var, CurScope, false); - } - } - - auto CheckRedefinition = [&](ParmVarDecl *Param) { - for (const auto &Capture : Intro.Captures) { - if (Capture.Id == Param->getIdentifier()) { - Diag(Param->getLocation(), diag::err_parameter_shadow_capture); - Diag(Capture.Loc, diag::note_var_explicitly_captured_here) - << Capture.Id << true; - return false; - } - } - return true; - }; + LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack; - for (ParmVarDecl *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. diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index da66ffea46f49..2790e78aa53a3 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1231,8 +1231,7 @@ namespace { // We recreated a local declaration, but not by instantiating it. There // may be pending dependent diagnostics to produce. - if (auto *DC = dyn_cast(Old); - DC && DC->isDependentContext() && DC->isFunctionOrMethod()) + if (auto *DC = dyn_cast(Old); DC && DC->isDependentContext()) SemaRef.PerformDependentDiagnostics(DC, TemplateArgs); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 6b33c8f2fb82b..ef56f6219868c 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -13238,6 +13238,37 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { LambdaScopeInfo *LSI = getSema().PushLambdaScope(); Sema::FunctionScopeRAII FuncScopeCleanup(getSema()); + // Transform the template parameters, and add them to the current + // instantiation scope. The null case is handled correctly. + auto TPL = getDerived().TransformTemplateParameterList( + E->getTemplateParameterList()); + LSI->GLTemplateParameterList = TPL; + + // Transform the type of the original lambda's call operator. + // The transformation MUST be done in the CurrentInstantiationScope since + // it introduces a mapping of the original to the newly created + // transformed parameters. + TypeSourceInfo *NewCallOpTSI = nullptr; + { + TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); + FunctionProtoTypeLoc OldCallOpFPTL = + OldCallOpTSI->getTypeLoc().getAs(); + + TypeLocBuilder NewCallOpTLBuilder; + SmallVector ExceptionStorage; + TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. + QualType NewCallOpType = TransformFunctionProtoType( + NewCallOpTLBuilder, OldCallOpFPTL, nullptr, Qualifiers(), + [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { + return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, + ExceptionStorage, Changed); + }); + if (NewCallOpType.isNull()) + return ExprError(); + NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, + NewCallOpType); + } + // Create the local class that will describe the lambda. // FIXME: DependencyKind below is wrong when substituting inside a templated @@ -13254,8 +13285,10 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { DependencyKind = CXXRecordDecl::LDK_NeverDependent; CXXRecordDecl *OldClass = E->getLambdaClass(); - CXXRecordDecl *Class = getSema().createLambdaClosureType( - E->getIntroducerRange(), nullptr, DependencyKind, E->getCaptureDefault()); + CXXRecordDecl *Class = + getSema().createLambdaClosureType(E->getIntroducerRange(), NewCallOpTSI, + DependencyKind, E->getCaptureDefault()); + getDerived().transformedLocalDecl(OldClass, {Class}); std::optional> Mangling; @@ -13265,19 +13298,36 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { OldClass->getDeviceLambdaManglingNumber(), OldClass->getLambdaContextDecl()); - CXXMethodDecl *NewCallOperator = - getSema().CreateLambdaCallOperator(E->getIntroducerRange(), Class); - NewCallOperator->setLexicalDeclContext(getSema().CurContext); + // Build the call operator. + CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition( + Class, E->getIntroducerRange(), NewCallOpTSI, + E->getCallOperator()->getEndLoc(), + NewCallOpTSI->getTypeLoc().castAs().getParams(), + E->getCallOperator()->getConstexprKind(), + E->getCallOperator()->getStorageClass(), + E->getCallOperator()->getTrailingRequiresClause()); - // Enter the scope of the lambda. - getSema().buildLambdaScope(LSI, NewCallOperator, E->getIntroducerRange(), - E->getCaptureDefault(), E->getCaptureDefaultLoc(), - E->hasExplicitParameters(), E->isMutable()); + LSI->CallOperator = NewCallOperator; + + getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); + getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator}); + + // Number the lambda for linkage purposes if necessary. + getSema().handleLambdaNumbering(Class, NewCallOperator, Mangling); // Introduce the context of the call operator. Sema::ContextRAII SavedContext(getSema(), NewCallOperator, /*NewThisContext*/false); + // Enter the scope of the lambda. + getSema().buildLambdaScope(LSI, NewCallOperator, + E->getIntroducerRange(), + E->getCaptureDefault(), + E->getCaptureDefaultLoc(), + E->hasExplicitParameters(), + E->hasExplicitResultType(), + E->isMutable()); + bool Invalid = false; // Transform captures. @@ -13317,8 +13367,7 @@ TreeTransform::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; @@ -13398,55 +13447,6 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { } getSema().finishLambdaExplicitCaptures(LSI); - // Transform the template parameters, and add them to the current - // instantiation scope. The null case is handled correctly. - auto TPL = getDerived().TransformTemplateParameterList( - E->getTemplateParameterList()); - LSI->GLTemplateParameterList = TPL; - - // Transform the type of the original lambda's call operator. - // The transformation MUST be done in the CurrentInstantiationScope since - // it introduces a mapping of the original to the newly created - // transformed parameters. - TypeSourceInfo *NewCallOpTSI = nullptr; - { - TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); - auto OldCallOpFPTL = - OldCallOpTSI->getTypeLoc().getAs(); - - TypeLocBuilder NewCallOpTLBuilder; - SmallVector ExceptionStorage; - TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. - QualType NewCallOpType = TransformFunctionProtoType( - NewCallOpTLBuilder, OldCallOpFPTL, nullptr, Qualifiers(), - [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { - return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, - ExceptionStorage, Changed); - }); - if (NewCallOpType.isNull()) - return ExprError(); - NewCallOpTSI = - NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType); - } - - getSema().CompleteLambdaCallOperator( - NewCallOperator, E->getCallOperator()->getLocation(), - E->getCallOperator()->getInnerLocStart(), - E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI, - E->getCallOperator()->getConstexprKind(), - E->getCallOperator()->getStorageClass(), - NewCallOpTSI->getTypeLoc().castAs().getParams(), - E->hasExplicitResultType()); - - getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); - getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator}); - - { - // Number the lambda for linkage purposes if necessary. - Sema::ContextRAII ManglingContext(getSema(), Class->getDeclContext()); - getSema().handleLambdaNumbering(Class, NewCallOperator, Mangling); - } - // FIXME: Sema's lambda-building mechanism expects us to push an expression // evaluation context even if we're not transforming the function body. getSema().PushExpressionEvaluationContext( diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp index 67953c6a6f901..4a0cf39bc56b3 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp @@ -12,16 +12,16 @@ auto with_float_2 = [&f(f)] { // ok, refers to outer f using T = double&; }; -// Within the lambda-expression 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}} }; } diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp index 660f6091bb663..5f7f73d622d82 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp @@ -43,21 +43,10 @@ X infer_X_return_type_2(X x) { }(5); } -struct Incomplete; // expected-note 2{{forward declaration of 'Incomplete'}} +struct Incomplete; // expected-note{{forward declaration of 'Incomplete'}} void test_result_type(int N) { auto l1 = [] () -> Incomplete { }; // expected-error{{incomplete result type 'Incomplete' in lambda expression}} typedef int vla[N]; auto l2 = [] () -> vla { }; // expected-error{{function cannot return array type 'vla' (aka 'int[N]')}} } - -template -void test_result_type_tpl(int N) { - auto l1 = []() -> T {}; // expected-error{{incomplete result type 'Incomplete' in lambda expression}} - typedef int vla[N]; - auto l2 = []() -> vla {}; // expected-error{{function cannot return array type 'vla' (aka 'int[N]')}} -} - -void test_result_type_call() { - test_result_type_tpl(10); // expected-note {{requested here}} -} diff --git a/clang/test/SemaCXX/lambda-capture-type-deduction.cpp b/clang/test/SemaCXX/lambda-capture-type-deduction.cpp deleted file mode 100644 index e22e3af02c5c0..0000000000000 --- a/clang/test/SemaCXX/lambda-capture-type-deduction.cpp +++ /dev/null @@ -1,243 +0,0 @@ -// RUN: %clang_cc1 -std=c++2b -verify -fsyntax-only %s - -template -constexpr bool is_same = false; - -template -constexpr bool is_same = true; - -void f() { - - int y; - - static_assert(is_same decltype((x)) { return x; }())>); - - static_assert(is_same decltype((x)) { return x; }())>); - - static_assert(is_same decltype((y)) { return y; }())>); - - static_assert(is_same decltype((y)) { return y; }())>); - - static_assert(is_same decltype((y)) { return y; }())>); - - static_assert(is_same 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) {}())); - static_assert(noexcept([x = 1] mutable noexcept(is_same) {}())); - static_assert(noexcept([y] noexcept(is_same) {}())); - static_assert(noexcept([y] mutable noexcept(is_same) {}())); - static_assert(noexcept([=] noexcept(is_same) {}())); - static_assert(noexcept([=] mutable noexcept(is_same) {}())); - static_assert(noexcept([&] noexcept(is_same) {}())); - static_assert(noexcept([&] mutable noexcept(is_same) {}())); -} - -void test_requires() { - - int x; - - [x = 1]() requires is_same {} - (); - [x = 1]() mutable requires is_same {} - (); - [x]() requires is_same {} - (); - [x]() mutable requires is_same {} - (); - [=]() requires is_same {} - (); - [=]() mutable requires is_same {} - (); - [&]() requires is_same {} - (); - [&]() mutable requires is_same {} - (); - [&x]() requires is_same {} - (); - [&x]() mutable requires is_same {} - (); - - [x = 1]() requires is_same {} (); - [x = 1]() mutable requires is_same {} (); -} - -void err() { - int y, z; - (void)[x = 1] - requires(is_same) {}; - - (void)[x = 1]{}; - - (void)[=]{}; - - (void)[z]{}; -} - -void gnu_attributes() { - int y; - (void)[=]() __attribute__((diagnose_if(!is_same, "wrong type", "warning"))){}(); - // expected-warning@-1 {{wrong type}} expected-note@-1{{'diagnose_if' attribute on 'operator()'}} - (void)[=]() __attribute__((diagnose_if(!is_same, "wrong type", "warning"))){}(); - - (void)[=]() __attribute__((diagnose_if(!is_same, "wrong type", "warning"))) mutable {}(); - (void)[=]() __attribute__((diagnose_if(!is_same, "wrong type", "warning"))) mutable {}(); - // expected-warning@-1 {{wrong type}} expected-note@-1{{'diagnose_if' attribute on 'operator()'}} - - - (void)[x=1]() __attribute__((diagnose_if(!is_same, "wrong type", "warning"))){}(); - // expected-warning@-1 {{wrong type}} expected-note@-1{{'diagnose_if' attribute on 'operator()'}} - (void)[x=1]() __attribute__((diagnose_if(!is_same, "wrong type", "warning"))){}(); - - (void)[x=1]() __attribute__((diagnose_if(!is_same, "wrong type", "warning"))) mutable {}(); - (void)[x=1]() __attribute__((diagnose_if(!is_same, "wrong type", "warning"))) mutable {}(); - // expected-warning@-1 {{wrong type}} expected-note@-1{{'diagnose_if' attribute on 'operator()'}} -} - -void nested() { - int x, y, z; - (void)[&]( - decltype([&]( - decltype([=]( - decltype([&]( - decltype([&](decltype(x)) {})) {})) {})) {})){}; - - (void)[&]( - decltype([&]( - decltype([&]( - decltype([&]( - decltype([&](decltype(y)) {})) {})) {})) {})){}; - - (void)[=]( - decltype([=]( - decltype([=]( - decltype([=]( - decltype([&] {})) {})) {})) {})){}; -} - -template -void dependent(U&& u) { - [&]() requires is_same {}(); -} - -template -void dependent_init_capture(T x = 0) { - [ y = x + 1, x ]() mutable -> decltype(y + x) - requires(is_same - && is_same) { - return y; - } - (); - [ y = x + 1, x ]() -> decltype(y + x) - requires(is_same - && is_same) { - return y; - } - (); -} - -template -struct extract_type { - using type = T; -}; - -template -void dependent_variadic_capture(T... x) { - [... y = x, x... ](auto...) mutable -> typename extract_type::type requires((is_same && ...) && (is_same && ...)) { - return 0; - } - (x...); - [... y = x, x... ](auto...) -> typename extract_type::type requires((is_same && ...) && (is_same && ...)) { - return 0; - } - (x...); -} - -void test_dependent() { - int v = 0; - int & r = v; - const int & cr = v; - dependent(v); - dependent(r); - dependent(cr); - dependent_init_capture(0); - dependent_variadic_capture(1, 2, 3, 4); -} - -void check_params() { - int i = 0; - int &j = i; - (void)[=](decltype((j)) jp, decltype((i)) ip) { - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - }; - - (void)[=](decltype((j)) jp, decltype((i)) ip) mutable { - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - }; - - (void)[a = 0](decltype((a)) ap) mutable { - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - }; - (void)[a = 0](decltype((a)) ap) { - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - }; -} - -template -void check_params_tpl() { - T i = 0; - T &j = i; - (void)[=](decltype((j)) jp, decltype((i)) ip) { - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - }; - - (void)[=](decltype((j)) jp, decltype((i)) ip) mutable { - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - }; - - (void)[a = 0](decltype((a)) ap) mutable { - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - }; - (void)[a = 0](decltype((a)) ap) { - static_assert(is_same); - static_assert(is_same); - static_assert(is_same); - }; -} diff --git a/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp b/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp index 9dddbf8b5f3b7..a772af049ab41 100644 --- a/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp +++ b/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp @@ -95,7 +95,7 @@ void foo(int param) { // expected-note 1+ {{previous declaration is here}} #ifdef AVOID auto l4 = [var = param] (int param) { ; }; // no warning #else - auto l4 = [var = param](int param) { ; }; // expected-warning 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. diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index b64c2cf20da00..c9df1ed37350b 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -1358,7 +1358,7 @@

C++2b implementation status

Change scope of lambda trailing-return-type P2036R3 - Clang 17 + No P2579R0