Skip to content

Commit

Permalink
Move unexpanded parameter handling into CapturingScopeInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
Sirraide committed Oct 10, 2024
1 parent 9c073cc commit eac7b11
Show file tree
Hide file tree
Showing 15 changed files with 110 additions and 66 deletions.
3 changes: 2 additions & 1 deletion clang/include/clang/AST/ComputeDependence.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ ExprDependence computeDependence(ArrayInitLoopExpr *E);
ExprDependence computeDependence(ImplicitValueInitExpr *E);
ExprDependence computeDependence(InitListExpr *E);
ExprDependence computeDependence(ExtVectorElementExpr *E);
ExprDependence computeDependence(BlockExpr *E);
ExprDependence computeDependence(BlockExpr *E,
bool ContainsUnexpandedParameterPack);
ExprDependence computeDependence(AsTypeExpr *E);
ExprDependence computeDependence(DeclRefExpr *E, const ASTContext &Ctx);
ExprDependence computeDependence(RecoveryExpr *E);
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -6369,9 +6369,9 @@ class BlockExpr : public Expr {
protected:
BlockDecl *TheBlock;
public:
BlockExpr(BlockDecl *BD, QualType ty)
BlockExpr(BlockDecl *BD, QualType ty, bool ContainsUnexpandedParameterPack)
: Expr(BlockExprClass, ty, VK_PRValue, OK_Ordinary), TheBlock(BD) {
setDependence(computeDependence(this));
setDependence(computeDependence(this, ContainsUnexpandedParameterPack));
}

/// Build an empty block expression.
Expand Down
12 changes: 6 additions & 6 deletions clang/include/clang/Sema/ScopeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -724,10 +724,16 @@ class CapturingScopeInfo : public FunctionScopeInfo {
/// is deduced (e.g. a lambda or block with omitted return type).
bool HasImplicitReturnType = false;

/// Whether this contains an unexpanded parameter pack.
bool ContainsUnexpandedParameterPack = false;

/// ReturnType - The target type of return statements in this context,
/// or null if unknown.
QualType ReturnType;

/// Packs introduced by this, if any.
SmallVector<NamedDecl*, 4> LocalPacks;

void addCapture(ValueDecl *Var, bool isBlock, bool isByref, bool isNested,
SourceLocation Loc, SourceLocation EllipsisLoc,
QualType CaptureType, bool Invalid) {
Expand Down Expand Up @@ -895,12 +901,6 @@ class LambdaScopeInfo final :
/// Whether any of the capture expressions requires cleanups.
CleanupInfo Cleanup;

/// Whether the lambda contains an unexpanded parameter pack.
bool ContainsUnexpandedParameterPack = false;

/// Packs introduced by this lambda, if any.
SmallVector<NamedDecl*, 4> LocalPacks;

/// Source range covering the explicit template parameter list (if it exists).
SourceRange ExplicitTemplateParamsRange;

Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -750,10 +750,10 @@ class Sema final : public SemaBase {
/// Retrieve the current block, if any.
sema::BlockScopeInfo *getCurBlock();

/// Get the innermost lambda enclosing the current location, if any. This
/// looks through intervening non-lambda scopes such as local functions and
/// blocks.
sema::LambdaScopeInfo *getEnclosingLambda() const;
/// Get the innermost lambda or block enclosing the current location, if any.
/// This looks through intervening non-lambda, non-block scopes such as local
/// functions.
sema::CapturingScopeInfo *getEnclosingLambdaOrBlock() const;

/// Retrieve the current lambda scope info, if any.
/// \param IgnoreNonLambdaCapturingScope true if should find the top-most
Expand Down
16 changes: 8 additions & 8 deletions clang/include/clang/Sema/Template.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,10 +411,10 @@ enum class TemplateSubstitutionKind : char {
/// lookup will search our outer scope.
bool CombineWithOuterScope;

/// Whether this scope is being used to instantiate a lambda expression,
/// in which case it should be reused for instantiating the lambda's
/// FunctionProtoType.
bool InstantiatingLambda = false;
/// Whether this scope is being used to instantiate a lambda or block
/// expression, in which case it should be reused for instantiating the
/// lambda's FunctionProtoType.
bool InstantiatingLambdaOrBlock = false;

/// If non-NULL, the template parameter pack that has been
/// partially substituted per C++0x [temp.arg.explicit]p9.
Expand All @@ -431,10 +431,10 @@ enum class TemplateSubstitutionKind : char {

public:
LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false,
bool InstantiatingLambda = false)
bool InstantiatingLambdaOrBlock = false)
: SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
CombineWithOuterScope(CombineWithOuterScope),
InstantiatingLambda(InstantiatingLambda) {
InstantiatingLambdaOrBlock(InstantiatingLambdaOrBlock) {
SemaRef.CurrentInstantiationScope = this;
}

Expand Down Expand Up @@ -561,8 +561,8 @@ enum class TemplateSubstitutionKind : char {
/// Determine whether D is a pack expansion created in this scope.
bool isLocalPackExpansion(const Decl *D);

/// Determine whether this scope is for instantiating a lambda.
bool isLambda() const { return InstantiatingLambda; }
/// Determine whether this scope is for instantiating a lambda or block.
bool isLambdaOrBlock() const { return InstantiatingLambdaOrBlock; }
};

class TemplateDeclInstantiator
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/AST/ComputeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,13 @@ ExprDependence clang::computeDependence(ExtVectorElementExpr *E) {
return E->getBase()->getDependence();
}

ExprDependence clang::computeDependence(BlockExpr *E) {
ExprDependence clang::computeDependence(BlockExpr *E,
bool ContainsUnexpandedParameterPack) {
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
if (E->getBlockDecl()->isDependentContext())
D |= ExprDependence::Instantiation;
if (ContainsUnexpandedParameterPack)
D |= ExprDependence::UnexpandedPack;
return D;
}

Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2382,18 +2382,19 @@ FunctionScopeInfo *Sema::getEnclosingFunction() const {
return nullptr;
}

LambdaScopeInfo *Sema::getEnclosingLambda() const {
CapturingScopeInfo *Sema::getEnclosingLambdaOrBlock() const {
for (auto *Scope : llvm::reverse(FunctionScopes)) {
if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Scope)) {
if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext) &&
if (auto *CSI = dyn_cast<CapturingScopeInfo>(Scope)) {
auto *LSI = dyn_cast<LambdaScopeInfo>(CSI);
if (LSI && LSI->Lambda && !LSI->Lambda->Encloses(CurContext) &&
LSI->AfterParameterList) {
// 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.
assert(!CodeSynthesisContexts.empty());
return nullptr;
}
return LSI;
return CSI;
}
}
return nullptr;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15139,8 +15139,8 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// we know that references to that pack must also be expanded within the
// lambda scope.
if (New->isParameterPack())
if (auto *LSI = getEnclosingLambda())
LSI->LocalPacks.push_back(New);
if (auto *CSI = getEnclosingLambdaOrBlock())
CSI->LocalPacks.push_back(New);

if (New->getType().hasNonTrivialToPrimitiveDestructCUnion() ||
New->getType().hasNonTrivialToPrimitiveCopyCUnion())
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16356,7 +16356,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
PoppedFunctionScopePtr ScopeRAII = PopFunctionScopeInfo(&WP, BD, BlockTy);

BlockExpr *Result = new (Context) BlockExpr(BD, BlockTy);
BlockExpr *Result = new (Context)
BlockExpr(BD, BlockTy, BSI->ContainsUnexpandedParameterPack);

// If the block isn't obviously global, i.e. it captures anything at
// all, then we need to do a few things in the surrounding context:
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2350,7 +2350,10 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
Block->setBody(new (Context) CompoundStmt(ConvLocation));

// Create the block literal expression.
Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType());
// TODO: Do we ever get here if we have unexpanded packs in the lambda???
Expr *BuildBlock =
new (Context) BlockExpr(Block, Conv->getConversionType(),
/*ContainsUnexpandedParameterPack=*/false);
ExprCleanupObjects.push_back(Block);
Cleanup.setExprNeedsCleanups(true);

Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1010,8 +1010,8 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
Param->setAccess(AS_public);

if (Param->isParameterPack())
if (auto *LSI = getEnclosingLambda())
LSI->LocalPacks.push_back(Param);
if (auto *CSI = getEnclosingLambdaOrBlock())
CSI->LocalPacks.push_back(Param);

if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName);
Expand Down Expand Up @@ -1542,8 +1542,8 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
Param->setInvalidDecl();

if (Param->isParameterPack())
if (auto *LSI = getEnclosingLambda())
LSI->LocalPacks.push_back(Param);
if (auto *CSI = getEnclosingLambdaOrBlock())
CSI->LocalPacks.push_back(Param);

if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(),
Expand Down Expand Up @@ -1593,7 +1593,7 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(
Param->setAccess(AS_public);

if (Param->isParameterPack())
if (auto *LSI = getEnclosingLambda())
if (auto *LSI = getEnclosingLambdaOrBlock())
LSI->LocalPacks.push_back(Param);

// If the template template parameter has a name, then link the identifier
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1693,12 +1693,18 @@ namespace {
if (SemaRef.RebuildingImmediateInvocation)
return E;
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
/*InstantiatingLambda=*/true);
/*InstantiatingLambdaOrBlock=*/true);
Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);

return inherited::TransformLambdaExpr(E);
}

ExprResult TransformBlockExpr(BlockExpr *E) {
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
/*InstantiatingLambdaOrBlock=*/true);
return inherited::TransformBlockExpr(E);
}

ExprResult RebuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
LambdaScopeInfo *LSI) {
CXXMethodDecl *MD = LSI->CallOperator;
Expand Down Expand Up @@ -2475,7 +2481,7 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
CXXRecordDecl *ThisContext,
Qualifiers ThisTypeQuals,
Fn TransformExceptionSpec) {
// If this is a lambda, the transformation MUST be done in the
// If this is a lambda or block, the transformation MUST be done in the
// CurrentInstantiationScope since it introduces a mapping of
// the original to the newly created transformed parameters.
//
Expand All @@ -2484,7 +2490,7 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
// a second one.
LocalInstantiationScope *Current = getSema().CurrentInstantiationScope;
std::optional<LocalInstantiationScope> Scope;
if (!Current || !Current->isLambda())
if (!Current || !Current->isLambdaOrBlock())
Scope.emplace(SemaRef, /*CombineWithOuterScope=*/true);

return inherited::TransformFunctionProtoType(
Expand Down
46 changes: 30 additions & 16 deletions clang/lib/Sema/SemaTemplateVariadic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace {

SmallVectorImpl<UnexpandedParameterPack> &Unexpanded;

bool InLambda = false;
bool InLambdaOrBlock = false;
unsigned DepthLimit = (unsigned)-1;

#ifndef NDEBUG
Expand Down Expand Up @@ -140,7 +140,7 @@ namespace {
/// do not contain unexpanded parameter packs.
bool TraverseStmt(Stmt *S) {
Expr *E = dyn_cast_or_null<Expr>(S);
if ((E && E->containsUnexpandedParameterPack()) || InLambda)
if ((E && E->containsUnexpandedParameterPack()) || InLambdaOrBlock)
return inherited::TraverseStmt(S);

return true;
Expand All @@ -149,7 +149,7 @@ namespace {
/// Suppress traversal into types that do not contain
/// unexpanded parameter packs.
bool TraverseType(QualType T) {
if ((!T.isNull() && T->containsUnexpandedParameterPack()) || InLambda)
if ((!T.isNull() && T->containsUnexpandedParameterPack()) || InLambdaOrBlock)
return inherited::TraverseType(T);

return true;
Expand All @@ -160,7 +160,7 @@ namespace {
bool TraverseTypeLoc(TypeLoc TL) {
if ((!TL.getType().isNull() &&
TL.getType()->containsUnexpandedParameterPack()) ||
InLambda)
InLambdaOrBlock)
return inherited::TraverseTypeLoc(TL);

return true;
Expand Down Expand Up @@ -262,20 +262,34 @@ namespace {
if (!Lambda->containsUnexpandedParameterPack())
return true;

bool WasInLambda = InLambda;
bool WasInLambdaOrBlock = InLambdaOrBlock;
unsigned OldDepthLimit = DepthLimit;

InLambda = true;
InLambdaOrBlock = true;
if (auto *TPL = Lambda->getTemplateParameterList())
DepthLimit = TPL->getDepth();

inherited::TraverseLambdaExpr(Lambda);

InLambda = WasInLambda;
InLambdaOrBlock = WasInLambdaOrBlock;
DepthLimit = OldDepthLimit;
return true;
}

/// Analogously for blocks.
bool TraverseBlockExpr(BlockExpr* Block) {
if (!Block->containsUnexpandedParameterPack())
return true;

bool WasInLambdaOrBlock = InLambdaOrBlock;
InLambdaOrBlock = true;

inherited::TraverseBlockExpr(Block);

InLambdaOrBlock = WasInLambdaOrBlock;
return true;
}

/// Suppress traversal within pack expansions in lambda captures.
bool TraverseLambdaCapture(LambdaExpr *Lambda, const LambdaCapture *C,
Expr *Init) {
Expand Down Expand Up @@ -323,11 +337,11 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,

// If we are within a lambda expression and referencing a pack that is not
// declared within the lambda itself, that lambda contains an unexpanded
// parameter pack, and we are done.
// parameter pack, and we are done. Analogously for blocks.
// FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it
// later.
SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences;
if (auto *LSI = getEnclosingLambda()) {
SmallVector<UnexpandedParameterPack, 4> ParamPackReferences;
if (sema::CapturingScopeInfo *CSI = getEnclosingLambdaOrBlock()) {
for (auto &Pack : Unexpanded) {
auto DeclaresThisPack = [&](NamedDecl *LocalPack) {
if (auto *TTPT = Pack.first.dyn_cast<const TemplateTypeParmType *>()) {
Expand All @@ -336,11 +350,11 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
}
return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack);
};
if (llvm::any_of(LSI->LocalPacks, DeclaresThisPack))
LambdaParamPackReferences.push_back(Pack);
if (llvm::any_of(CSI->LocalPacks, DeclaresThisPack))
ParamPackReferences.push_back(Pack);
}

if (LambdaParamPackReferences.empty()) {
if (ParamPackReferences.empty()) {
// Construct in lambda only references packs declared outside the lambda.
// That's OK for now, but the lambda itself is considered to contain an
// unexpanded pack in this case, which will require expansion outside the
Expand All @@ -363,16 +377,16 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
}
// Coumpound-statements outside the lambda are OK for now; we'll check
// for those when we finish handling the lambda.
if (Func == LSI)
if (Func == CSI)
break;
}

if (!EnclosingStmtExpr) {
LSI->ContainsUnexpandedParameterPack = true;
CSI->ContainsUnexpandedParameterPack = true;
return false;
}
} else {
Unexpanded = LambdaParamPackReferences;
Unexpanded = ParamPackReferences;
}
}

Expand Down
7 changes: 3 additions & 4 deletions clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm
Original file line number Diff line number Diff line change
Expand Up @@ -119,17 +119,16 @@ void call_with_lambda() {

template<typename ... Args> static void f1()
{
(void)^(Args args) { // expected-error{{block contains unexpanded parameter pack 'Args'}}
(void)^(Args args) { // expected-error{{expression contains unexpanded parameter pack 'Args'}}
};
}

template<typename ... Args> static void f2()
{
// FIXME: Allow this.
f(
^(Args args) // expected-error{{block contains unexpanded parameter pack 'Args'}}
^(Args args)
{ }
... // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
...
);
}

Expand Down
Loading

0 comments on commit eac7b11

Please sign in to comment.