aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaLambda.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaLambda.cpp')
-rw-r--r--clang/lib/Sema/SemaLambda.cpp222
1 files changed, 132 insertions, 90 deletions
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index afc2f3ef4d76..00ab6ba580bf 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -21,6 +21,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
#include "llvm/ADT/STLExtras.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -54,17 +55,17 @@ using namespace sema;
/// is at the top of the stack and has the highest index.
/// \param VarToCapture - the variable to capture. If NULL, capture 'this'.
///
-/// \returns An Optional<unsigned> Index that if evaluates to 'true' contains
-/// the index (into Sema's FunctionScopeInfo stack) of the innermost lambda
-/// which is capture-ready. If the return value evaluates to 'false' then
-/// no lambda is capture-ready for \p VarToCapture.
+/// \returns An std::optional<unsigned> Index that if evaluates to 'true'
+/// contains the index (into Sema's FunctionScopeInfo stack) of the innermost
+/// lambda which is capture-ready. If the return value evaluates to 'false'
+/// then no lambda is capture-ready for \p VarToCapture.
-static inline Optional<unsigned>
+static inline std::optional<unsigned>
getStackIndexOfNearestEnclosingCaptureReadyLambda(
ArrayRef<const clang::sema::FunctionScopeInfo *> FunctionScopes,
- VarDecl *VarToCapture) {
+ ValueDecl *VarToCapture) {
// Label failure to capture.
- const Optional<unsigned> NoLambdaIsCaptureReady;
+ const std::optional<unsigned> NoLambdaIsCaptureReady;
// Ignore all inner captured regions.
unsigned CurScopeIndex = FunctionScopes.size() - 1;
@@ -165,18 +166,19 @@ getStackIndexOfNearestEnclosingCaptureReadyLambda(
/// \param VarToCapture - the variable to capture. If NULL, capture 'this'.
///
///
-/// \returns An Optional<unsigned> Index that if evaluates to 'true' contains
-/// the index (into Sema's FunctionScopeInfo stack) of the innermost lambda
-/// which is capture-capable. If the return value evaluates to 'false' then
-/// no lambda is capture-capable for \p VarToCapture.
+/// \returns An std::optional<unsigned> Index that if evaluates to 'true'
+/// contains the index (into Sema's FunctionScopeInfo stack) of the innermost
+/// lambda which is capture-capable. If the return value evaluates to 'false'
+/// then no lambda is capture-capable for \p VarToCapture.
-Optional<unsigned> clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
+std::optional<unsigned>
+clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
ArrayRef<const sema::FunctionScopeInfo *> FunctionScopes,
- VarDecl *VarToCapture, Sema &S) {
+ ValueDecl *VarToCapture, Sema &S) {
- const Optional<unsigned> NoLambdaIsCaptureCapable;
+ const std::optional<unsigned> NoLambdaIsCaptureCapable;
- const Optional<unsigned> OptionalStackIndex =
+ const std::optional<unsigned> OptionalStackIndex =
getStackIndexOfNearestEnclosingCaptureReadyLambda(FunctionScopes,
VarToCapture);
if (!OptionalStackIndex)
@@ -282,7 +284,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
DataMember,
StaticDataMember,
InlineVariable,
- VariableTemplate
+ VariableTemplate,
+ Concept
} Kind = Normal;
// Default arguments of member function parameters that appear in a class
@@ -307,6 +310,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
}
} else if (isa<FieldDecl>(ManglingContextDecl)) {
Kind = DataMember;
+ } else if (isa<ImplicitConceptSpecializationDecl>(ManglingContextDecl)) {
+ Kind = Concept;
}
}
@@ -330,12 +335,17 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
return std::make_tuple(nullptr, nullptr);
}
+ case Concept:
+ // Concept definitions aren't code generated and thus aren't mangled,
+ // however the ManglingContextDecl is important for the purposes of
+ // re-forming the template argument list of the lambda for constraint
+ // evaluation.
case StaticDataMember:
// -- the initializers of nonspecialized static members of template classes
if (!IsInNonspecializedTemplate)
return std::make_tuple(nullptr, ManglingContextDecl);
// Fall through to get the current context.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DataMember:
// -- the in-class initializers of class members
@@ -354,13 +364,11 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
llvm_unreachable("unexpected context");
}
-CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
- SourceRange IntroducerRange,
- TypeSourceInfo *MethodTypeInfo,
- SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params,
- ConstexprSpecKind ConstexprKind,
- Expr *TrailingRequiresClause) {
+CXXMethodDecl *Sema::startLambdaDefinition(
+ CXXRecordDecl *Class, SourceRange IntroducerRange,
+ TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc,
+ ArrayRef<ParmVarDecl *> Params, ConstexprSpecKind ConstexprKind,
+ StorageClass SC, Expr *TrailingRequiresClause) {
QualType MethodType = MethodTypeInfo->getType();
TemplateParameterList *TemplateParams =
getGenericLambdaTemplateParameterList(getCurLambda(), *this);
@@ -390,7 +398,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
Context, Class, EndLoc,
DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
MethodNameLoc),
- MethodType, MethodTypeInfo, SC_None, getCurFPFeatures().isFPConstrained(),
+ MethodType, MethodTypeInfo, SC, getCurFPFeatures().isFPConstrained(),
/*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause);
Method->setAccess(AS_public);
if (!TemplateParams)
@@ -418,7 +426,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
CheckParmsForFunctionDef(Params,
/*CheckParameterNames=*/false);
- for (auto P : Method->parameters())
+ for (auto *P : Method->parameters())
P->setOwningFunction(Method);
}
@@ -427,7 +435,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
void Sema::handleLambdaNumbering(
CXXRecordDecl *Class, CXXMethodDecl *Method,
- Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) {
+ std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) {
if (Mangling) {
bool HasKnownInternalLinkage;
unsigned ManglingNumber, DeviceManglingNumber;
@@ -769,8 +777,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
if (Context.getCanonicalFunctionResultType(ReturnType) ==
Context.getCanonicalFunctionResultType(CSI.ReturnType)) {
// Use the return type with the strictest possible nullability annotation.
- auto RetTyNullability = ReturnType->getNullability(Ctx);
- auto BlockNullability = CSI.ReturnType->getNullability(Ctx);
+ auto RetTyNullability = ReturnType->getNullability();
+ auto BlockNullability = CSI.ReturnType->getNullability();
if (BlockNullability &&
(!RetTyNullability ||
hasWeakerNullability(*RetTyNullability, *BlockNullability)))
@@ -789,8 +797,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
QualType Sema::buildLambdaInitCaptureInitialization(
SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions, IdentifierInfo *Id, bool IsDirectInit,
- Expr *&Init) {
+ std::optional<unsigned> NumExpansions, IdentifierInfo *Id,
+ bool IsDirectInit, Expr *&Init) {
// Create an 'auto' or 'auto&' TypeSourceInfo that we can use to
// deduce against.
QualType DeductType = Context.getAutoDeductType();
@@ -881,11 +889,12 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
return NewVD;
}
-void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var) {
+void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var,
+ bool isReferenceType) {
assert(Var->isInitCapture() && "init capture flag should be set");
- LSI->addCapture(Var, /*isBlock*/false, Var->getType()->isReferenceType(),
- /*isNested*/false, Var->getLocation(), SourceLocation(),
- Var->getType(), /*Invalid*/false);
+ LSI->addCapture(Var, /*isBlock*/ false, isReferenceType,
+ /*isNested*/ false, Var->getLocation(), SourceLocation(),
+ Var->getType(), /*Invalid*/ false);
}
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
@@ -917,6 +926,15 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
bool ContainsUnexpandedParameterPack = false;
SourceLocation EndLoc;
SmallVector<ParmVarDecl *, 8> Params;
+
+ assert(
+ (ParamInfo.getDeclSpec().getStorageClassSpec() ==
+ DeclSpec::SCS_unspecified ||
+ ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) &&
+ "Unexpected storage specifier");
+ bool IsLambdaStatic =
+ ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static;
+
if (ParamInfo.getNumTypeObjects() == 0) {
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a lambda-declarator, it is as
@@ -938,8 +956,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
QualType DefaultTypeForNoTrailingReturn =
getLangOpts().CPlusPlus14 ? Context.getAutoDeductType()
: Context.DependentTy;
- QualType MethodTy =
- Context.getFunctionType(DefaultTypeForNoTrailingReturn, None, EPI);
+ QualType MethodTy = Context.getFunctionType(DefaultTypeForNoTrailingReturn,
+ std::nullopt, EPI);
MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
ExplicitParams = false;
ExplicitResultType = false;
@@ -953,7 +971,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// 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()) {
+ if (!FTI.hasMutableQualifier() && !IsLambdaStatic) {
FTI.getOrCreateMethodQualifiers().SetTypeQual(DeclSpec::TQ_const,
SourceLocation());
}
@@ -964,6 +982,18 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
ExplicitResultType = FTI.hasTrailingReturnType();
+ 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)
+ Diag(FTI.getTrailingReturnTypeLoc(),
+ diag::err_return_value_with_address_space);
+ }
+ }
+
if (FTIHasNonVoidParameters(FTI)) {
Params.reserve(FTI.NumParams);
for (unsigned i = 0, e = FTI.NumParams; i != e; ++i)
@@ -981,6 +1011,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
ParamInfo.getDeclSpec().getConstexprSpecifier(),
+ IsLambdaStatic ? SC_Static : SC_None,
ParamInfo.getTrailingRequiresClause());
if (ExplicitParams)
CheckCXXDefaultArguments(Method);
@@ -1088,7 +1119,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (C->Init.isInvalid())
continue;
- VarDecl *Var = nullptr;
+ ValueDecl *Var = nullptr;
if (C->Init.isUsable()) {
Diag(C->Loc, getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_init_capture
@@ -1166,7 +1197,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
continue;
}
- Var = R.getAsSingle<VarDecl>();
+ if (auto *BD = R.getAsSingle<BindingDecl>())
+ Var = BD;
+ else
+ Var = R.getAsSingle<VarDecl>();
if (Var && DiagnoseUseOfDecl(Var, C->Loc))
continue;
}
@@ -1200,7 +1234,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (Var->isInvalidDecl())
continue;
- if (!Var->hasLocalStorage()) {
+ VarDecl *Underlying = Var->getPotentiallyDecomposedVarDecl();
+
+ if (!Underlying->hasLocalStorage()) {
Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
Diag(Var->getLocation(), diag::note_previous_decl) << C->Id;
continue;
@@ -1224,7 +1260,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
if (C->Init.isUsable()) {
- addInitCapture(LSI, Var);
+ addInitCapture(LSI, cast<VarDecl>(Var), C->Kind == LCK_ByRef);
} else {
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
TryCapture_ExplicitByVal;
@@ -1374,7 +1410,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
ConvExtInfo.TypeQuals.addConst();
ConvExtInfo.ExceptionSpec.Type = EST_BasicNoexcept;
QualType ConvTy =
- S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo);
+ S.Context.getFunctionType(PtrToFunctionTy, std::nullopt, ConvExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName ConversionName
@@ -1470,45 +1506,50 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
Class->addDecl(ConversionTemplate);
} else
Class->addDecl(Conversion);
- // Add a non-static member function that will be the result of
- // the conversion with a certain unique ID.
- DeclarationName InvokerName = &S.Context.Idents.get(
- getLambdaStaticInvokerName());
- // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
- // we should get a prebuilt TrivialTypeSourceInfo from Context
- // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
- // then rewire the parameters accordingly, by hoisting up the InvokeParams
- // loop below and then use its Params to set Invoke->setParams(...) below.
- // This would avoid the 'const' qualifier of the calloperator from
- // contaminating the type of the invoker, which is currently adjusted
- // in SemaTemplateDeduction.cpp:DeduceTemplateArguments. Fixing the
- // trailing return type of the invoker would require a visitor to rebuild
- // the trailing return type and adjusting all back DeclRefExpr's to refer
- // to the new static invoker parameters - not the call operator's.
- CXXMethodDecl *Invoke = CXXMethodDecl::Create(
- S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc),
- InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static,
- S.getCurFPFeatures().isFPConstrained(),
- /*isInline=*/true, ConstexprSpecKind::Unspecified,
- CallOperator->getBody()->getEndLoc());
- for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
- InvokerParams[I]->setOwningFunction(Invoke);
- Invoke->setParams(InvokerParams);
- Invoke->setAccess(AS_private);
- Invoke->setImplicit(true);
- if (Class->isGenericLambda()) {
- FunctionTemplateDecl *TemplateCallOperator =
- CallOperator->getDescribedFunctionTemplate();
- FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create(
- S.Context, Class, Loc, InvokerName,
- TemplateCallOperator->getTemplateParameters(),
- Invoke);
- StaticInvokerTemplate->setAccess(AS_private);
- StaticInvokerTemplate->setImplicit(true);
- Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);
- Class->addDecl(StaticInvokerTemplate);
- } else
- Class->addDecl(Invoke);
+
+ // If the lambda is not static, we need to add a static member
+ // function that will be the result of the conversion with a
+ // certain unique ID.
+ // When it is static we just return the static call operator instead.
+ if (CallOperator->isInstance()) {
+ DeclarationName InvokerName =
+ &S.Context.Idents.get(getLambdaStaticInvokerName());
+ // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
+ // we should get a prebuilt TrivialTypeSourceInfo from Context
+ // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
+ // then rewire the parameters accordingly, by hoisting up the InvokeParams
+ // loop below and then use its Params to set Invoke->setParams(...) below.
+ // This would avoid the 'const' qualifier of the calloperator from
+ // contaminating the type of the invoker, which is currently adjusted
+ // in SemaTemplateDeduction.cpp:DeduceTemplateArguments. Fixing the
+ // trailing return type of the invoker would require a visitor to rebuild
+ // the trailing return type and adjusting all back DeclRefExpr's to refer
+ // to the new static invoker parameters - not the call operator's.
+ CXXMethodDecl *Invoke = CXXMethodDecl::Create(
+ S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc),
+ InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static,
+ S.getCurFPFeatures().isFPConstrained(),
+ /*isInline=*/true, ConstexprSpecKind::Unspecified,
+ CallOperator->getBody()->getEndLoc());
+ for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
+ InvokerParams[I]->setOwningFunction(Invoke);
+ Invoke->setParams(InvokerParams);
+ Invoke->setAccess(AS_private);
+ Invoke->setImplicit(true);
+ if (Class->isGenericLambda()) {
+ FunctionTemplateDecl *TemplateCallOperator =
+ CallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *StaticInvokerTemplate =
+ FunctionTemplateDecl::Create(
+ S.Context, Class, Loc, InvokerName,
+ TemplateCallOperator->getTemplateParameters(), Invoke);
+ StaticInvokerTemplate->setAccess(AS_private);
+ StaticInvokerTemplate->setImplicit(true);
+ Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);
+ Class->addDecl(StaticInvokerTemplate);
+ } else
+ Class->addDecl(Invoke);
+ }
}
/// Add a lambda's conversion to function pointers, as described in
@@ -1546,7 +1587,8 @@ static void addBlockPointerConversion(Sema &S,
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
ConversionEPI.TypeQuals = Qualifiers();
ConversionEPI.TypeQuals.addConst();
- QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, None, ConversionEPI);
+ QualType ConvTy =
+ S.Context.getFunctionType(BlockPtrTy, std::nullopt, ConversionEPI);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
@@ -1574,7 +1616,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
// An init-capture is initialized directly from its stored initializer.
if (Cap.isInitCapture())
- return Cap.getVariable()->getInit();
+ return cast<VarDecl>(Cap.getVariable())->getInit();
// For anything else, build an initialization expression. For an implicit
// capture, the capture notionally happens at the capture-default, so use
@@ -1605,7 +1647,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
Init = This;
} else {
assert(Cap.isVariableCapture() && "unknown kind of capture");
- VarDecl *Var = Cap.getVariable();
+ ValueDecl *Var = Cap.getVariable();
Name = Var->getIdentifier();
Init = BuildDeclarationNameExpr(
CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
@@ -1654,7 +1696,7 @@ mapImplicitCaptureStyle(CapturingScopeInfo::ImplicitCaptureStyle ICS) {
bool Sema::CaptureHasSideEffects(const Capture &From) {
if (From.isInitCapture()) {
- Expr *Init = From.getVariable()->getInit();
+ Expr *Init = cast<VarDecl>(From.getVariable())->getInit();
if (Init && Init->HasSideEffects(Context))
return true;
}
@@ -1704,9 +1746,9 @@ FieldDecl *Sema::BuildCaptureField(RecordDecl *RD,
TypeSourceInfo *TSI = nullptr;
if (Capture.isVariableCapture()) {
- auto *Var = Capture.getVariable();
- if (Var->isInitCapture())
- TSI = Capture.getVariable()->getTypeSourceInfo();
+ const auto *Var = dyn_cast_or_null<VarDecl>(Capture.getVariable());
+ if (Var && Var->isInitCapture())
+ TSI = Var->getTypeSourceInfo();
}
// FIXME: Should we really be doing this? A null TypeSourceInfo seems more
@@ -1854,7 +1896,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
return LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType);
} else {
assert(From.isVariableCapture() && "unknown kind of capture");
- VarDecl *Var = From.getVariable();
+ ValueDecl *Var = From.getVariable();
LambdaCaptureKind Kind =
From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
return LambdaCapture(From.getLocation(), IsImplicit, Kind, Var,