diff options
Diffstat (limited to 'lib/Sema/SemaTemplateVariadic.cpp')
-rw-r--r-- | lib/Sema/SemaTemplateVariadic.cpp | 183 |
1 files changed, 139 insertions, 44 deletions
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 9f572007d8a7..d81837dad508 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -26,6 +26,19 @@ using namespace clang; // Visitor that collects unexpanded parameter packs //---------------------------------------------------------------------------- +/// \brief Retrieve the depth and index of a parameter pack. +static std::pair<unsigned, unsigned> +getDepthAndIndex(NamedDecl *ND) { + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) + return std::make_pair(TTP->getDepth(), TTP->getIndex()); + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) + return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); + + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); + return std::make_pair(TTP->getDepth(), TTP->getIndex()); +} + namespace { /// \brief A class that collects unexpanded parameter packs. class CollectUnexpandedParameterPacksVisitor : @@ -36,15 +49,36 @@ namespace { SmallVectorImpl<UnexpandedParameterPack> &Unexpanded; - bool InLambda; - + bool InLambda = false; + unsigned DepthLimit = (unsigned)-1; + + void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) { + if (auto *PVD = dyn_cast<ParmVarDecl>(ND)) { + // For now, the only problematic case is a generic lambda's templated + // call operator, so we don't need to look for all the other ways we + // could have reached a dependent parameter pack. + auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext()); + auto *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr; + if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit) + return; + } else if (getDepthAndIndex(ND).first >= DepthLimit) + return; + + Unexpanded.push_back({ND, Loc}); + } + void addUnexpanded(const TemplateTypeParmType *T, + SourceLocation Loc = SourceLocation()) { + if (T->getDepth() < DepthLimit) + Unexpanded.push_back({T, Loc}); + } + public: explicit CollectUnexpandedParameterPacksVisitor( - SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) - : Unexpanded(Unexpanded), InLambda(false) { } + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) + : Unexpanded(Unexpanded) {} bool shouldWalkTypesOfTypeLocs() const { return false; } - + //------------------------------------------------------------------------ // Recording occurrences of (unexpanded) parameter packs. //------------------------------------------------------------------------ @@ -52,7 +86,7 @@ namespace { /// \brief Record occurrences of template type parameter packs. bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { if (TL.getTypePtr()->isParameterPack()) - Unexpanded.push_back(std::make_pair(TL.getTypePtr(), TL.getNameLoc())); + addUnexpanded(TL.getTypePtr(), TL.getNameLoc()); return true; } @@ -63,7 +97,7 @@ namespace { /// Ideally, this routine would never be used. bool VisitTemplateTypeParmType(TemplateTypeParmType *T) { if (T->isParameterPack()) - Unexpanded.push_back(std::make_pair(T, SourceLocation())); + addUnexpanded(T); return true; } @@ -72,18 +106,18 @@ namespace { /// parameter packs in an expression. bool VisitDeclRefExpr(DeclRefExpr *E) { if (E->getDecl()->isParameterPack()) - Unexpanded.push_back(std::make_pair(E->getDecl(), E->getLocation())); + addUnexpanded(E->getDecl(), E->getLocation()); return true; } /// \brief Record occurrences of template template parameter packs. bool TraverseTemplateName(TemplateName Template) { - if (TemplateTemplateParmDecl *TTP - = dyn_cast_or_null<TemplateTemplateParmDecl>( - Template.getAsTemplateDecl())) + if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>( + Template.getAsTemplateDecl())) { if (TTP->isParameterPack()) - Unexpanded.push_back(std::make_pair(TTP, SourceLocation())); + addUnexpanded(TTP); + } return inherited::TraverseTemplateName(Template); } @@ -127,7 +161,7 @@ namespace { return true; } - /// \brief Suppress traversel into types with location information + /// \brief Suppress traversal into types with location information /// that do not contain unexpanded parameter packs. bool TraverseTypeLoc(TypeLoc TL) { if ((!TL.getType().isNull() && @@ -138,13 +172,48 @@ namespace { return true; } - /// \brief Suppress traversal of non-parameter declarations, since - /// they cannot contain unexpanded parameter packs. + /// \brief Suppress traversal of parameter packs. bool TraverseDecl(Decl *D) { - if ((D && isa<ParmVarDecl>(D)) || InLambda) - return inherited::TraverseDecl(D); + // A function parameter pack is a pack expansion, so cannot contain + // an unexpanded parameter pack. Likewise for a template parameter + // pack that contains any references to other packs. + if (D->isParameterPack()) + return true; - return true; + return inherited::TraverseDecl(D); + } + + /// \brief Suppress traversal of pack-expanded attributes. + bool TraverseAttr(Attr *A) { + if (A->isPackExpansion()) + return true; + + return inherited::TraverseAttr(A); + } + + /// \brief Suppress traversal of pack expansion expressions and types. + ///@{ + bool TraversePackExpansionType(PackExpansionType *T) { return true; } + bool TraversePackExpansionTypeLoc(PackExpansionTypeLoc TL) { return true; } + bool TraversePackExpansionExpr(PackExpansionExpr *E) { return true; } + bool TraverseCXXFoldExpr(CXXFoldExpr *E) { return true; } + + ///@} + + /// \brief Suppress traversal of using-declaration pack expansion. + bool TraverseUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { + if (D->isPackExpansion()) + return true; + + return inherited::TraverseUnresolvedUsingValueDecl(D); + } + + /// \brief Suppress traversal of using-declaration pack expansion. + bool TraverseUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { + if (D->isPackExpansion()) + return true; + + return inherited::TraverseUnresolvedUsingTypenameDecl(D); } /// \brief Suppress traversal of template argument pack expansions. @@ -163,6 +232,22 @@ namespace { return inherited::TraverseTemplateArgumentLoc(ArgLoc); } + /// \brief Suppress traversal of base specifier pack expansions. + bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) { + if (Base.isPackExpansion()) + return true; + + return inherited::TraverseCXXBaseSpecifier(Base); + } + + /// \brief Suppress traversal of mem-initializer pack expansions. + bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { + if (Init->isPackExpansion()) + return true; + + return inherited::TraverseConstructorInitializer(Init); + } + /// \brief Note whether we're traversing a lambda containing an unexpanded /// parameter pack. In this case, the unexpanded pack can occur anywhere, /// including all the places where we normally wouldn't look. Within a @@ -175,25 +260,27 @@ namespace { return true; bool WasInLambda = InLambda; - InLambda = true; + unsigned OldDepthLimit = DepthLimit; - // If any capture names a function parameter pack, that pack is expanded - // when the lambda is expanded. - for (LambdaExpr::capture_iterator I = Lambda->capture_begin(), - E = Lambda->capture_end(); - I != E; ++I) { - if (I->capturesVariable()) { - VarDecl *VD = I->getCapturedVar(); - if (VD->isParameterPack()) - Unexpanded.push_back(std::make_pair(VD, I->getLocation())); - } - } + InLambda = true; + if (auto *TPL = Lambda->getTemplateParameterList()) + DepthLimit = TPL->getDepth(); inherited::TraverseLambdaExpr(Lambda); InLambda = WasInLambda; + DepthLimit = OldDepthLimit; return true; } + + /// Suppress traversal within pack expansions in lambda captures. + bool TraverseLambdaCapture(LambdaExpr *Lambda, const LambdaCapture *C, + Expr *Init) { + if (C->isPackExpansion()) + return true; + + return inherited::TraverseLambdaCapture(Lambda, C, Init); + } }; } @@ -220,13 +307,33 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, if (Unexpanded.empty()) return false; - // If we are within a lambda expression, that lambda contains an unexpanded + // If we are within a lambda expression and referencing a pack that is not + // a parameter of the lambda itself, that lambda contains an unexpanded // parameter pack, and we are done. // FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it // later. + SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences; for (unsigned N = FunctionScopes.size(); N; --N) { if (sema::LambdaScopeInfo *LSI = dyn_cast<sema::LambdaScopeInfo>(FunctionScopes[N-1])) { + if (N == FunctionScopes.size()) { + for (auto &Param : Unexpanded) { + auto *PD = dyn_cast_or_null<ParmVarDecl>( + Param.first.dyn_cast<NamedDecl *>()); + if (PD && PD->getDeclContext() == LSI->CallOperator) + LambdaParamPackReferences.push_back(Param); + } + } + + // If we have references to a parameter pack of the innermost enclosing + // lambda, only diagnose those ones. We don't know whether any other + // unexpanded parameters referenced herein are actually unexpanded; + // they might be expanded at an outer level. + if (!LambdaParamPackReferences.empty()) { + Unexpanded = LambdaParamPackReferences; + break; + } + LSI->ContainsUnexpandedParameterPack = true; return false; } @@ -520,19 +627,6 @@ ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, PackExpansionExpr(Context.DependentTy, Pattern, EllipsisLoc, NumExpansions); } -/// \brief Retrieve the depth and index of a parameter pack. -static std::pair<unsigned, unsigned> -getDepthAndIndex(NamedDecl *ND) { - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) - return std::make_pair(TTP->getDepth(), TTP->getIndex()); - - if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) - return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); - - TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); - return std::make_pair(TTP->getDepth(), TTP->getIndex()); -} - bool Sema::CheckParameterPacksForExpansion( SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef<UnexpandedParameterPack> Unexpanded, @@ -725,6 +819,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_half: case TST_float: case TST_double: + case TST_Float16: case TST_float128: case TST_bool: case TST_decimal32: |