forked from OSchip/llvm-project
[Clang] Fix references to captured variables in dependant context.
D119136 changed how captures are handled in a lambda call operator declaration, but did not properly handled dependant context, which led to crash when refering to init-captures in a trailing return type. We fix that bug by making transformations more symetric with parsing, ie. we first create the call operator, then transform the capture, then compute the type of the lambda call operaror. This ensures captures exist and have the right type when we parse a trailing requires-clause / return type. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D124012
This commit is contained in:
parent
26d575eb08
commit
69dd89fdcb
|
@ -6828,15 +6828,6 @@ public:
|
|||
unsigned LambdaDependencyKind,
|
||||
LambdaCaptureDefault CaptureDefault);
|
||||
|
||||
/// Start the definition of a lambda expression.
|
||||
CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class,
|
||||
SourceRange IntroducerRange,
|
||||
TypeSourceInfo *MethodType,
|
||||
SourceLocation EndLoc,
|
||||
ArrayRef<ParmVarDecl *> Params,
|
||||
ConstexprSpecKind ConstexprKind,
|
||||
Expr *TrailingRequiresClause);
|
||||
|
||||
/// Number lambda for linkage purposes if necessary.
|
||||
void handleLambdaNumbering(
|
||||
CXXRecordDecl *Class, CXXMethodDecl *Method,
|
||||
|
@ -6849,9 +6840,16 @@ public:
|
|||
LambdaCaptureDefault CaptureDefault,
|
||||
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,
|
||||
ArrayRef<ParmVarDecl *> Params, bool HasExplicitResultType);
|
||||
|
||||
/// Perform initialization analysis of the init-capture and perform
|
||||
/// any implicit conversions such as an lvalue-to-rvalue conversion if
|
||||
/// not being used to initialize a reference.
|
||||
|
|
|
@ -377,76 +377,6 @@ buildTypeForLambdaCallOperator(Sema &S, clang::CXXRecordDecl *Class,
|
|||
return MethodType;
|
||||
}
|
||||
|
||||
/// Start the definition of a lambda expression.
|
||||
/// In this overload, we do not know the type yet
|
||||
CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
|
||||
SourceRange IntroducerRange,
|
||||
TypeSourceInfo *MethodTypeInfo,
|
||||
SourceLocation EndLoc,
|
||||
ArrayRef<ParmVarDecl *> Params,
|
||||
ConstexprSpecKind ConstexprKind,
|
||||
Expr *TrailingRequiresClause) {
|
||||
|
||||
LambdaScopeInfo *LSI = getCurLambda();
|
||||
|
||||
TemplateParameterList *TemplateParams =
|
||||
getGenericLambdaTemplateParameterList(LSI, *this);
|
||||
|
||||
// At this point, we may not know the type of the lambda, if we have not
|
||||
// parsed a trailing return type yet
|
||||
QualType MethodType = MethodTypeInfo
|
||||
? buildTypeForLambdaCallOperator(
|
||||
*this, Class, TemplateParams, MethodTypeInfo)
|
||||
: QualType();
|
||||
|
||||
// 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_None, 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(
|
||||
CXXRecordDecl *Class, CXXMethodDecl *Method,
|
||||
Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) {
|
||||
|
@ -517,12 +447,11 @@ static void buildLambdaScopeReturnType(Sema &S, LambdaScopeInfo *LSI,
|
|||
}
|
||||
}
|
||||
|
||||
static void buildLambdaScopeCaptures(LambdaScopeInfo *LSI,
|
||||
CXXMethodDecl *CallOperator,
|
||||
SourceRange IntroducerRange,
|
||||
LambdaCaptureDefault CaptureDefault,
|
||||
SourceLocation CaptureDefaultLoc,
|
||||
bool ExplicitParams, bool Mutable) {
|
||||
void Sema::buildLambdaScope(LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator,
|
||||
SourceRange IntroducerRange,
|
||||
LambdaCaptureDefault CaptureDefault,
|
||||
SourceLocation CaptureDefaultLoc,
|
||||
bool ExplicitParams, bool Mutable) {
|
||||
LSI->CallOperator = CallOperator;
|
||||
CXXRecordDecl *LambdaClass = CallOperator->getParent();
|
||||
LSI->Lambda = LambdaClass;
|
||||
|
@ -536,17 +465,6 @@ static void buildLambdaScopeCaptures(LambdaScopeInfo *LSI,
|
|||
LSI->Mutable = Mutable;
|
||||
}
|
||||
|
||||
void Sema::buildLambdaScope(LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator,
|
||||
SourceRange IntroducerRange,
|
||||
LambdaCaptureDefault CaptureDefault,
|
||||
SourceLocation CaptureDefaultLoc,
|
||||
bool ExplicitParams, bool ExplicitResultType,
|
||||
bool Mutable) {
|
||||
buildLambdaScopeCaptures(LSI, CallOperator, IntroducerRange, CaptureDefault,
|
||||
CaptureDefaultLoc, ExplicitParams, Mutable);
|
||||
buildLambdaScopeReturnType(*this, LSI, CallOperator, ExplicitResultType);
|
||||
}
|
||||
|
||||
void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
|
||||
LSI->finishedExplicitCaptures();
|
||||
}
|
||||
|
@ -953,28 +871,76 @@ static TypeSourceInfo *getLambdaType(Sema &S, LambdaIntroducer &Intro,
|
|||
return MethodTyInfo;
|
||||
}
|
||||
|
||||
static CXXMethodDecl *CreateMethod(Sema &S, SourceRange IntroducerRange,
|
||||
CXXRecordDecl *Class) {
|
||||
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 =
|
||||
S.Context.DeclarationNames.getCXXOperatorName(OO_Call);
|
||||
Context.DeclarationNames.getCXXOperatorName(OO_Call);
|
||||
DeclarationNameLoc MethodNameLoc =
|
||||
DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange.getBegin());
|
||||
CXXMethodDecl *Method = CXXMethodDecl::Create(
|
||||
S.Context, Class, SourceLocation(),
|
||||
Context, Class, SourceLocation(),
|
||||
DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
|
||||
MethodNameLoc),
|
||||
QualType(), nullptr, SC_None, S.getCurFPFeatures().isFPConstrained(),
|
||||
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,
|
||||
ArrayRef<ParmVarDecl *> Params, bool HasExplicitResultType) {
|
||||
|
||||
LambdaScopeInfo *const LSI = getCurrentLambdaScopeUnsafe(*this);
|
||||
|
||||
if (TrailingRequiresClause)
|
||||
Method->setTrailingRequiresClause(TrailingRequiresClause);
|
||||
|
||||
TemplateParameterList *TemplateParams =
|
||||
getGenericLambdaTemplateParameterList(LSI, *this);
|
||||
|
||||
auto DC = Method->getLexicalDeclContext();
|
||||
Method->setLexicalDeclContext(LSI->Lambda);
|
||||
if (TemplateParams) {
|
||||
FunctionTemplateDecl *const 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);
|
||||
}
|
||||
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);
|
||||
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::ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurrentScope) {
|
||||
|
||||
LambdaScopeInfo *const LSI = getCurLambda();
|
||||
|
@ -1016,7 +982,7 @@ void Sema::ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurrentScope) {
|
|||
// by the lambda-expression's parameter-declaration-clause and
|
||||
// trailing-return-type respectively.
|
||||
|
||||
CXXMethodDecl *Method = CreateMethod(*this, Intro.Range, Class);
|
||||
CXXMethodDecl *Method = CreateLambdaCallOperator(Intro.Range, Class);
|
||||
LSI->CallOperator = Method;
|
||||
Method->setLexicalDeclContext(CurContext);
|
||||
|
||||
|
@ -1297,55 +1263,24 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
SmallVector<ParmVarDecl *, 8> Params;
|
||||
bool ExplicitResultType;
|
||||
|
||||
SourceLocation TypeLoc, LambdaLoc;
|
||||
SourceLocation TypeLoc, CallOperatorLoc;
|
||||
if (ParamInfo.getNumTypeObjects() == 0) {
|
||||
LambdaLoc = TypeLoc = Intro.Range.getEnd();
|
||||
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();
|
||||
LambdaLoc = ParamInfo.getSourceRange().getEnd();
|
||||
CallOperatorLoc = ParamInfo.getSourceRange().getEnd();
|
||||
}
|
||||
|
||||
CXXRecordDecl *Class = LSI->Lambda;
|
||||
CXXMethodDecl *Method = LSI->CallOperator;
|
||||
|
||||
if (auto *C = ParamInfo.getTrailingRequiresClause())
|
||||
Method->setTrailingRequiresClause(C);
|
||||
|
||||
TemplateParameterList *TemplateParams =
|
||||
getGenericLambdaTemplateParameterList(LSI, *this);
|
||||
|
||||
auto DC = Method->getLexicalDeclContext();
|
||||
Method->setLexicalDeclContext(Class);
|
||||
if (TemplateParams) {
|
||||
FunctionTemplateDecl *const TemplateMethod = FunctionTemplateDecl::Create(
|
||||
Context, Class, Method->getLocation(), Method->getDeclName(),
|
||||
TemplateParams, Method);
|
||||
TemplateMethod->setAccess(AS_public);
|
||||
Method->setDescribedFunctionTemplate(TemplateMethod);
|
||||
Class->addDecl(TemplateMethod);
|
||||
TemplateMethod->setLexicalDeclContext(DC);
|
||||
} else {
|
||||
Class->addDecl(Method);
|
||||
}
|
||||
Method->setLexicalDeclContext(DC);
|
||||
Class->setLambdaIsGeneric(TemplateParams);
|
||||
|
||||
TypeSourceInfo *MethodTyInfo = getLambdaType(
|
||||
*this, Intro, ParamInfo, getCurScope(), TypeLoc, ExplicitResultType);
|
||||
|
||||
Class->setLambdaTypeInfo(MethodTyInfo);
|
||||
Method->setInnerLocStart(LambdaLoc);
|
||||
Method->setLocation(Intro.Range.getBegin());
|
||||
Method->setTypeSourceInfo(MethodTyInfo);
|
||||
Method->setType(buildTypeForLambdaCallOperator(*this, Class, TemplateParams,
|
||||
MethodTyInfo));
|
||||
Method->setConstexprKind(ParamInfo.getDeclSpec().getConstexprSpecifier());
|
||||
buildLambdaScopeReturnType(*this, LSI, Method, ExplicitResultType);
|
||||
|
||||
LSI->ExplicitParams = ParamInfo.getNumTypeObjects() != 0;
|
||||
|
||||
if (ParamInfo.isFunctionDeclarator() != 0 &&
|
||||
|
@ -1359,14 +1294,15 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
}
|
||||
}
|
||||
|
||||
CompleteLambdaCallOperator(Method, Intro.Range.getBegin(), CallOperatorLoc,
|
||||
ParamInfo.getTrailingRequiresClause(),
|
||||
MethodTyInfo,
|
||||
ParamInfo.getDeclSpec().getConstexprSpecifier(),
|
||||
Params, ExplicitResultType);
|
||||
|
||||
ContextRAII ManglingContext(*this, Class->getDeclContext());
|
||||
|
||||
CheckParmsForFunctionDef(Params, /*CheckParameterNames=*/false);
|
||||
|
||||
if (LSI->ExplicitParams) {
|
||||
Method->setParams(Params);
|
||||
CheckCXXDefaultArguments(Method);
|
||||
}
|
||||
CheckCXXDefaultArguments(Method);
|
||||
|
||||
// This represents the function body for the lambda function, check if we
|
||||
// have to apply optnone due to a pragma.
|
||||
|
|
|
@ -12966,44 +12966,6 @@ TreeTransform<Derived>::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<FunctionProtoTypeLoc>();
|
||||
|
||||
TypeLocBuilder NewCallOpTLBuilder;
|
||||
SmallVector<QualType, 4> 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);
|
||||
}
|
||||
|
||||
// Transform the trailing requires clause
|
||||
ExprResult NewTrailingRequiresClause;
|
||||
if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause())
|
||||
// FIXME: Concepts: Substitution into requires clause should only happen
|
||||
// when checking satisfaction.
|
||||
NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
|
||||
|
||||
// Create the local class that will describe the lambda.
|
||||
|
||||
// FIXME: DependencyKind below is wrong when substituting inside a templated
|
||||
|
@ -13019,10 +12981,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
|||
DependencyKind = CXXRecordDecl::LDK_NeverDependent;
|
||||
|
||||
CXXRecordDecl *OldClass = E->getLambdaClass();
|
||||
CXXRecordDecl *Class =
|
||||
getSema().createLambdaClosureType(E->getIntroducerRange(), NewCallOpTSI,
|
||||
DependencyKind, E->getCaptureDefault());
|
||||
|
||||
CXXRecordDecl *Class = getSema().createLambdaClosureType(
|
||||
E->getIntroducerRange(), nullptr, DependencyKind, E->getCaptureDefault());
|
||||
getDerived().transformedLocalDecl(OldClass, {Class});
|
||||
|
||||
Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling;
|
||||
|
@ -13032,35 +12992,19 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
|||
OldClass->getDeviceLambdaManglingNumber(),
|
||||
OldClass->getLambdaContextDecl());
|
||||
|
||||
// Build the call operator.
|
||||
CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition(
|
||||
Class, E->getIntroducerRange(), NewCallOpTSI,
|
||||
E->getCallOperator()->getEndLoc(),
|
||||
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
|
||||
E->getCallOperator()->getConstexprKind(),
|
||||
NewTrailingRequiresClause.get());
|
||||
CXXMethodDecl *NewCallOperator =
|
||||
getSema().CreateLambdaCallOperator(E->getIntroducerRange(), Class);
|
||||
NewCallOperator->setLexicalDeclContext(getSema().CurContext);
|
||||
|
||||
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);
|
||||
// Enter the scope of the lambda.
|
||||
getSema().buildLambdaScope(LSI, NewCallOperator, E->getIntroducerRange(),
|
||||
E->getCaptureDefault(), E->getCaptureDefaultLoc(),
|
||||
E->hasExplicitParameters(), E->isMutable());
|
||||
|
||||
// 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.
|
||||
|
@ -13182,6 +13126,60 @@ TreeTransform<Derived>::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();
|
||||
FunctionProtoTypeLoc OldCallOpFPTL =
|
||||
OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
|
||||
|
||||
TypeLocBuilder NewCallOpTLBuilder;
|
||||
SmallVector<QualType, 4> 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);
|
||||
}
|
||||
|
||||
// Transform the trailing requires clause
|
||||
ExprResult NewTrailingRequiresClause;
|
||||
if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause())
|
||||
// FIXME: Concepts: Substitution into requires clause should only happen
|
||||
// when checking satisfaction.
|
||||
NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
|
||||
|
||||
getSema().CompleteLambdaCallOperator(
|
||||
NewCallOperator, E->getCallOperator()->getLocation(),
|
||||
E->getCallOperator()->getInnerLocStart(), NewTrailingRequiresClause.get(),
|
||||
NewCallOpTSI, E->getCallOperator()->getConstexprKind(),
|
||||
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().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(
|
||||
|
|
|
@ -43,10 +43,21 @@ X infer_X_return_type_2(X x) {
|
|||
}(5);
|
||||
}
|
||||
|
||||
struct Incomplete; // expected-note{{forward declaration of 'Incomplete'}}
|
||||
struct Incomplete; // expected-note 2{{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 <typename T>
|
||||
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<Incomplete>(10); // expected-note {{requested here}}
|
||||
}
|
||||
|
|
|
@ -163,6 +163,35 @@ void dependent(U&& u) {
|
|||
[&]() requires is_same<decltype(u), T> {}();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void dependent_init_capture(T x = 0) {
|
||||
[ y = x + 1, x ]() mutable -> decltype(y + x) requires(is_same<decltype((y)), int &> && is_same<decltype((x)), int &>) {
|
||||
return y;
|
||||
}
|
||||
();
|
||||
[ y = x + 1, x ]() -> decltype(y + x) requires(is_same<decltype((y)), const int &> && is_same<decltype((x)), const int &>) {
|
||||
return y;
|
||||
}
|
||||
();
|
||||
}
|
||||
|
||||
template <typename T, typename...>
|
||||
struct extract_type {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename... T>
|
||||
void dependent_variadic_capture(T... x) {
|
||||
[... y = x, x... ](auto...) mutable -> typename extract_type<decltype(y)...>::type requires((is_same<decltype((y)), int &> && ...) && (is_same<decltype((x)), int &> && ...)) {
|
||||
return 0;
|
||||
}
|
||||
(x...);
|
||||
[... y = x, x... ](auto...) -> typename extract_type<decltype(y)...>::type requires((is_same<decltype((y)), const int &> && ...) && (is_same<decltype((x)), const int &> && ...)) {
|
||||
return 0;
|
||||
}
|
||||
(x...);
|
||||
}
|
||||
|
||||
void test_dependent() {
|
||||
int v = 0;
|
||||
int & r = v;
|
||||
|
@ -170,6 +199,8 @@ void test_dependent() {
|
|||
dependent<int&>(v);
|
||||
dependent<int&>(r);
|
||||
dependent<const int&>(cr);
|
||||
dependent_init_capture(0);
|
||||
dependent_variadic_capture(1, 2, 3, 4);
|
||||
}
|
||||
|
||||
void test_CWG2569_tpl(auto a) {
|
||||
|
|
Loading…
Reference in New Issue