diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaCodeComplete.cpp | 6 | ||||
-rwxr-xr-x | clang/lib/Sema/SemaTemplate.cpp | 351 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 15 | ||||
-rwxr-xr-x | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 59 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 6 |
6 files changed, 350 insertions, 90 deletions
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index e14c63d557a..7260977c634 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -2986,7 +2986,11 @@ static void AddTemplateParameterChunks( if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) { if (TTP->wasDeclaredWithTypename()) PlaceholderStr = "typename"; - else + else if (const auto *TC = TTP->getTypeConstraint()) { + llvm::raw_string_ostream OS(PlaceholderStr); + TC->print(OS, Policy); + OS.flush(); + } else PlaceholderStr = "class"; if (TTP->getIdentifier()) { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 6f22326e8fc..1184446796e 100755 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -976,20 +976,23 @@ ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) { /// If the type parameter has a default argument, it will be added /// later via ActOnTypeParameterDefault. NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, - SourceLocation EllipsisLoc, - SourceLocation KeyLoc, - IdentifierInfo *ParamName, - SourceLocation ParamNameLoc, - unsigned Depth, unsigned Position, - SourceLocation EqualLoc, - ParsedType DefaultArg) { + SourceLocation EllipsisLoc, + SourceLocation KeyLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, unsigned Position, + SourceLocation EqualLoc, + ParsedType DefaultArg, + bool HasTypeConstraint) { assert(S->isTemplateParamScope() && "Template type parameter not in template parameter scope!"); bool IsParameterPack = EllipsisLoc.isValid(); - TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create( - Context, Context.getTranslationUnitDecl(), KeyLoc, ParamNameLoc, Depth, - Position, ParamName, Typename, IsParameterPack); + TemplateTypeParmDecl *Param + = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(), + KeyLoc, ParamNameLoc, Depth, Position, + ParamName, Typename, IsParameterPack, + HasTypeConstraint); Param->setAccess(AS_public); if (Param->isParameterPack()) @@ -1036,6 +1039,125 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, return Param; } +/// Convert the parser's template argument list representation into our form. +static TemplateArgumentListInfo +makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { + TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc, + TemplateId.RAngleLoc); + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(), + TemplateId.NumArgs); + S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs); + return TemplateArgs; +} + +bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr, + TemplateTypeParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc) { + ConceptDecl *CD = + cast<ConceptDecl>(TypeConstr->Template.get().getAsTemplateDecl()); + + // C++2a [temp.param]p4: + // [...] The concept designated by a type-constraint shall be a type + // concept ([temp.concept]). + if (!CD->isTypeConcept()) { + Diag(TypeConstr->TemplateNameLoc, + diag::err_type_constraint_non_type_concept); + return true; + } + + bool WereArgsSpecified = TypeConstr->LAngleLoc.isValid(); + + if (!WereArgsSpecified && + CD->getTemplateParameters()->getMinRequiredArguments() > 1) { + Diag(TypeConstr->TemplateNameLoc, + diag::err_type_constraint_missing_arguments) << CD; + return true; + } + + TemplateArgumentListInfo TemplateArgs; + if (TypeConstr->LAngleLoc.isValid()) { + TemplateArgs = + makeTemplateArgumentListInfo(*this, *TypeConstr); + } + return AttachTypeConstraint( + TypeConstr->SS.isSet() ? TypeConstr->SS.getWithLocInContext(Context) : + NestedNameSpecifierLoc(), + DeclarationNameInfo(DeclarationName(TypeConstr->Name), + TypeConstr->TemplateNameLoc), CD, + TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, + ConstrainedParameter, EllipsisLoc); +} + +/// Attach a type-constraint to a template parameter. +/// \returns true if an error occured. This can happen if the +/// immediately-declared constraint could not be formed (e.g. incorrect number +/// of arguments for the named concept). +bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, + DeclarationNameInfo NameInfo, + ConceptDecl *NamedConcept, + const TemplateArgumentListInfo *TemplateArgs, + TemplateTypeParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc) { + // C++2a [temp.param]p4: + // [...] If Q is of the form C<A1, ..., An>, then let E' be + // C<T, A1, ..., An>. Otherwise, let E' be C<T>. [...] + const ASTTemplateArgumentListInfo *ArgsAsWritten = + TemplateArgs ? ASTTemplateArgumentListInfo::Create(Context, + *TemplateArgs) : nullptr; + + QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0); + TemplateArgumentListInfo ConstraintArgs; + ConstraintArgs.addArgument( + TemplateArgumentLoc( + TemplateArgument(ParamAsArgument), + TemplateArgumentLocInfo( + Context.getTrivialTypeSourceInfo(ParamAsArgument, + ConstrainedParameter->getLocation())))); + if (TemplateArgs) { + ConstraintArgs.setRAngleLoc(TemplateArgs->getRAngleLoc()); + ConstraintArgs.setLAngleLoc(TemplateArgs->getLAngleLoc()); + for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments()) + ConstraintArgs.addArgument(ArgLoc); + } + + // C++2a [temp.param]p4: + // [...] This constraint-expression E is called the immediately-declared + // constraint of T. [...] + CXXScopeSpec SS; + SS.Adopt(NS); + ExprResult ImmediatelyDeclaredConstraint = CheckConceptTemplateId(SS, + /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept, + NamedConcept, &ConstraintArgs); + if (ImmediatelyDeclaredConstraint.isInvalid()) + return true; + + if (ConstrainedParameter->isParameterPack()) { + // C++2a [temp.param]p4: + // [...] If T is not a pack, then E is E', otherwise E is (E' && ...). + // + // We have the following case: + // + // template<typename T> concept C1 = true; + // template<C1... T> struct s1; + // + // The constraint: (C1<T> && ...) + ImmediatelyDeclaredConstraint = + BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(), + ImmediatelyDeclaredConstraint.get(), BO_LAnd, + EllipsisLoc, /*RHS=*/nullptr, + /*RParenLoc=*/SourceLocation(), + /*NumExpansions=*/None).get(); + if (ImmediatelyDeclaredConstraint.isInvalid()) + return true; + } + + ConstrainedParameter->setTypeConstraint(NS, NameInfo, + /*FoundDecl=*/NamedConcept, + NamedConcept, ArgsAsWritten, + ImmediatelyDeclaredConstraint.get()); + return false; +} + /// Check that the type of a non-type template parameter is /// well-formed. /// @@ -1868,7 +1990,23 @@ private: SemaRef.Context, DC, TTP->getBeginLoc(), TTP->getLocation(), /*Depth*/ 0, Depth1IndexAdjustment + TTP->getIndex(), TTP->getIdentifier(), TTP->wasDeclaredWithTypename(), - TTP->isParameterPack()); + TTP->isParameterPack(), TTP->hasTypeConstraint(), + TTP->isExpandedParameterPack() ? + llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None); + if (const auto *TC = TTP->getTypeConstraint()) { + TemplateArgumentListInfo TransformedArgs; + const auto *ArgsAsWritten = TC->getTemplateArgsAsWritten(); + if (SemaRef.Subst(ArgsAsWritten->getTemplateArgs(), + ArgsAsWritten->NumTemplateArgs, TransformedArgs, + Args)) + SemaRef.AttachTypeConstraint( + TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), + TC->getNamedConcept(), &TransformedArgs, NewTTP, + NewTTP->isParameterPack() + ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc() + : SourceLocation()); + } if (TTP->hasDefaultArgument()) { TypeSourceInfo *InstantiatedDefaultArg = SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args, @@ -2177,6 +2315,17 @@ static bool DiagnoseUnexpandedParameterPacks(Sema &S, TemplateParameterList *Params = TTP->getTemplateParameters(); for (unsigned I = 0, N = Params->size(); I != N; ++I) { NamedDecl *P = Params->getParam(I); + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(P)) { + if (!TTP->isParameterPack()) + if (const TypeConstraint *TC = TTP->getTypeConstraint()) + if (TC->hasExplicitTemplateArgs()) + for (auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments()) + if (S.DiagnoseUnexpandedParameterPack(ArgLoc, + Sema::UPPC_TypeConstraint)) + return true; + continue; + } + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) { if (!NTTP->isParameterPack() && S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(), @@ -3711,17 +3860,6 @@ static bool isSameAsPrimaryTemplate(TemplateParameterList *Params, return true; } -/// Convert the parser's template argument list representation into our form. -static TemplateArgumentListInfo -makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { - TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc, - TemplateId.RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(), - TemplateId.NumArgs); - S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs); - return TemplateArgs; -} - template<typename PartialSpecDecl> static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) { if (Partial->getDeclContext()->isDependentContext()) @@ -4233,14 +4371,14 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name, ExprResult Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - SourceLocation ConceptNameLoc, + const DeclarationNameInfo &ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs) { assert(NamedConcept && "A concept template id without a template?"); llvm::SmallVector<TemplateArgument, 4> Converted; - if (CheckTemplateArgumentList(NamedConcept, ConceptNameLoc, + if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(), const_cast<TemplateArgumentListInfo&>(*TemplateArgs), /*PartialTemplateArgs=*/false, Converted, /*UpdateArgsWithConversion=*/false)) @@ -4259,14 +4397,14 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, {NamedConcept->getConstraintExpr()}, Converted, SourceRange(SS.isSet() ? SS.getBeginLoc() : - ConceptNameLoc, - TemplateArgs->getRAngleLoc()), - Satisfaction)) + ConceptNameInfo.getLoc(), + TemplateArgs->getRAngleLoc()), + Satisfaction)) return ExprError(); return ConceptSpecializationExpr::Create(Context, SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{}, - TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept, + TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted, AreArgsDependent ? nullptr : &Satisfaction); } @@ -4312,8 +4450,7 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, } if (R.getAsSingle<ConceptDecl>()) { - return CheckConceptTemplateId(SS, TemplateKWLoc, - R.getLookupNameInfo().getBeginLoc(), + return CheckConceptTemplateId(SS, TemplateKWLoc, R.getLookupNameInfo(), R.getFoundDecl(), R.getAsSingle<ConceptDecl>(), TemplateArgs); } @@ -5116,7 +5253,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - if (CheckTemplateTemplateArgument(Params, Arg)) + if (CheckTemplateTemplateArgument(TempParm, Params, Arg)) return true; Converted.push_back(Arg.getArgument()); @@ -5156,6 +5293,12 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, /// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us /// is not a pack expansion, so returns an empty Optional. static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) { + if (TemplateTypeParmDecl *TTP + = dyn_cast<TemplateTypeParmDecl>(Param)) { + if (TTP->isExpandedParameterPack()) + return TTP->getNumExpansionParameters(); + } + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { if (NTTP->isExpandedParameterPack()) @@ -6894,7 +7037,8 @@ static void DiagnoseTemplateParameterListArityMismatch( /// /// This routine implements the semantics of C++ [temp.arg.template]. /// It returns true if an error occurred, and false otherwise. -bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params, +bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, + TemplateParameterList *Params, TemplateArgumentLoc &Arg) { TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern(); TemplateDecl *Template = Name.getAsTemplateDecl(); @@ -6933,6 +7077,9 @@ bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params, // C++1z [temp.arg.template]p3: (DR 150) // A template-argument matches a template template-parameter P when P // is at least as specialized as the template-argument A. + // FIXME: We should enable RelaxedTemplateTemplateArgs by default as it is a + // defect report resolution from C++17 and shouldn't be introduced by + // concepts. if (getLangOpts().RelaxedTemplateTemplateArgs) { // Quick check for the common case: // If P contains a parameter pack, then A [...] matches P if each of A's @@ -6940,12 +7087,39 @@ bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params, // the template-parameter-list of P. if (TemplateParameterListsAreEqual( Template->getTemplateParameters(), Params, false, - TPL_TemplateTemplateArgumentMatch, Arg.getLocation())) + TPL_TemplateTemplateArgumentMatch, Arg.getLocation()) && + // If the argument has no associated constraints, then the parameter is + // definitely at least as specialized as the argument. + // Otherwise - we need a more thorough check. + !Template->hasAssociatedConstraints()) return false; if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template, - Arg.getLocation())) + Arg.getLocation())) { + // C++2a[temp.func.order]p2 + // [...] If both deductions succeed, the partial ordering selects the + // more constrained template as described by the rules in + // [temp.constr.order]. + SmallVector<const Expr *, 3> ParamsAC, TemplateAC; + Params->getAssociatedConstraints(ParamsAC); + Template->getAssociatedConstraints(TemplateAC); + bool IsParamAtLeastAsConstrained; + if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, + IsParamAtLeastAsConstrained)) + return true; + if (!IsParamAtLeastAsConstrained) { + Diag(Arg.getLocation(), + diag::err_template_template_parameter_not_at_least_as_constrained) + << Template << Param << Arg.getSourceRange(); + Diag(Param->getLocation(), diag::note_entity_declared_at) << Param; + Diag(Template->getLocation(), diag::note_entity_declared_at) + << Template; + MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, ParamsAC, Template, + TemplateAC); + return true; + } return false; + } // FIXME: Produce better diagnostics for deduction failures. } @@ -7123,7 +7297,6 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, bool Complain, Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) { - // TODO: Concepts: Check constrained-parameter constraints here. // Check the actual kind (type, non-type, template). if (Old->getKind() != New->getKind()) { if (Complain) { @@ -7177,50 +7350,73 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, // template parameter and one of the non-type template parameter types // is dependent, then we must wait until template instantiation time // to actually compare the arguments. - if (Kind == Sema::TPL_TemplateTemplateArgumentMatch && - (OldNTTP->getType()->isDependentType() || - NewNTTP->getType()->isDependentType())) - return true; - - if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) { - if (Complain) { - unsigned NextDiag = diag::err_template_nontype_parm_different_type; - if (TemplateArgLoc.isValid()) { - S.Diag(TemplateArgLoc, - diag::err_template_arg_template_params_mismatch); - NextDiag = diag::note_template_nontype_parm_different_type; + if (Kind != Sema::TPL_TemplateTemplateArgumentMatch || + (!OldNTTP->getType()->isDependentType() && + !NewNTTP->getType()->isDependentType())) + if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) { + if (Complain) { + unsigned NextDiag = diag::err_template_nontype_parm_different_type; + if (TemplateArgLoc.isValid()) { + S.Diag(TemplateArgLoc, + diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_nontype_parm_different_type; + } + S.Diag(NewNTTP->getLocation(), NextDiag) + << NewNTTP->getType() + << (Kind != Sema::TPL_TemplateMatch); + S.Diag(OldNTTP->getLocation(), + diag::note_template_nontype_parm_prev_declaration) + << OldNTTP->getType(); } - S.Diag(NewNTTP->getLocation(), NextDiag) - << NewNTTP->getType() - << (Kind != Sema::TPL_TemplateMatch); - S.Diag(OldNTTP->getLocation(), - diag::note_template_nontype_parm_prev_declaration) - << OldNTTP->getType(); - } - return false; - } - - return true; + return false; + } } - // For template template parameters, check the template parameter types. // The template parameter lists of template template // parameters must agree. - if (TemplateTemplateParmDecl *OldTTP + else if (TemplateTemplateParmDecl *OldTTP = dyn_cast<TemplateTemplateParmDecl>(Old)) { TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New); - return S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), - OldTTP->getTemplateParameters(), - Complain, + if (!S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), + OldTTP->getTemplateParameters(), + Complain, (Kind == Sema::TPL_TemplateMatch ? Sema::TPL_TemplateTemplateParmMatch : Kind), - TemplateArgLoc); - } + TemplateArgLoc)) + return false; + } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) { + const Expr *NewC = nullptr, *OldC = nullptr; + if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint()) + NewC = TC->getImmediatelyDeclaredConstraint(); + if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint()) + OldC = TC->getImmediatelyDeclaredConstraint(); + + auto Diagnose = [&] { + S.Diag(NewC ? NewC->getBeginLoc() : New->getBeginLoc(), + diag::err_template_different_type_constraint); + S.Diag(OldC ? OldC->getBeginLoc() : Old->getBeginLoc(), + diag::note_template_prev_declaration) << /*declaration*/0; + }; - // TODO: Concepts: Match immediately-introduced-constraint for type - // constraints + if (!NewC != !OldC) { + if (Complain) + Diagnose(); + return false; + } + + if (NewC) { + llvm::FoldingSetNodeID OldCID, NewCID; + OldC->Profile(OldCID, S.Context, /*Canonical=*/true); + NewC->Profile(NewCID, S.Context, /*Canonical=*/true); + if (OldCID != NewCID) { + if (Complain) + Diagnose(); + return false; + } + } + } return true; } @@ -7247,15 +7443,6 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S, << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc()); } -static void -DiagnoseTemplateParameterListRequiresClauseMismatch(Sema &S, - TemplateParameterList *New, - TemplateParameterList *Old){ - S.Diag(New->getTemplateLoc(), diag::err_template_different_requires_clause); - S.Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration) - << /*declaration*/0; -} - /// Determine whether the given template parameter lists are /// equivalent. /// @@ -7348,9 +7535,17 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, if (Kind != TPL_TemplateTemplateArgumentMatch) { const Expr *NewRC = New->getRequiresClause(); const Expr *OldRC = Old->getRequiresClause(); + + auto Diagnose = [&] { + Diag(NewRC ? NewRC->getBeginLoc() : New->getTemplateLoc(), + diag::err_template_different_requires_clause); + Diag(OldRC ? OldRC->getBeginLoc() : Old->getTemplateLoc(), + diag::note_template_prev_declaration) << /*declaration*/0; + }; + if (!NewRC != !OldRC) { if (Complain) - DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old); + Diagnose(); return false; } @@ -7360,7 +7555,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, NewRC->Profile(NewRCID, Context, /*Canonical=*/true); if (OldRCID != NewRCID) { if (Complain) - DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old); + Diagnose(); return false; } } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index e626948cb5d..1b9f1b2144d 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -643,6 +643,10 @@ static TemplateParameter makeTemplateParameter(Decl *D) { /// If \p Param is an expanded parameter pack, get the number of expansions. static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) { + if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) + if (TTP->isExpandedParameterPack()) + return TTP->getNumExpansionParameters(); + if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) if (NTTP->isExpandedParameterPack()) return NTTP->getNumExpansionTypes(); @@ -4542,11 +4546,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, // Build template<class TemplParam> void Func(FuncParam); TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create( - Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false); + Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false, + false); QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0); NamedDecl *TemplParamPtr = TemplParam; FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt( - Loc, Loc, TemplParamPtr, Loc, nullptr); + Context, Loc, Loc, TemplParamPtr, Loc, nullptr); QualType FuncParam = SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false) @@ -5276,9 +5281,8 @@ Sema::getMoreSpecializedPartialSpecialization( return nullptr; if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2)) return nullptr; - if (AtLeastAsConstrained1 == AtLeastAsConstrained2) { + if (AtLeastAsConstrained1 == AtLeastAsConstrained2) return nullptr; - } return AtLeastAsConstrained1 ? PS1 : PS2; } @@ -5352,7 +5356,8 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( SFINAETrap Trap(*this); Context.getInjectedTemplateArgs(P, PArgs); - TemplateArgumentListInfo PArgList(P->getLAngleLoc(), P->getRAngleLoc()); + TemplateArgumentListInfo PArgList(P->getLAngleLoc(), + P->getRAngleLoc()); for (unsigned I = 0, N = P->size(); I != N; ++I) { // Unwrap packs that getInjectedTemplateArgs wrapped around pack // expansions, to form an "as written" argument list. diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index ce94c036eb1..64500d0a26d 100755 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2479,13 +2479,68 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( // TODO: don't always clone when decls are refcounted. assert(D->getTypeForDecl()->isTemplateTypeParmType()); + Optional<unsigned> NumExpanded; + + if (const TypeConstraint *TC = D->getTypeConstraint()) { + if (D->isPackExpansion() && !D->isExpandedParameterPack()) { + assert(TC->getTemplateArgsAsWritten() && + "type parameter can only be an expansion when explicit arguments " + "are specified"); + // The template type parameter pack's type is a pack expansion of types. + // Determine whether we need to expand this parameter pack into separate + // types. + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + for (auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments()) + SemaRef.collectUnexpandedParameterPacks(ArgLoc, Unexpanded); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + if (SemaRef.CheckParameterPacksForExpansion( + cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc(), + SourceRange(TC->getConceptNameLoc(), + TC->hasExplicitTemplateArgs() ? + TC->getTemplateArgsAsWritten()->getRAngleLoc() : + TC->getConceptNameInfo().getEndLoc()), + Unexpanded, TemplateArgs, Expand, RetainExpansion, NumExpanded)) + return nullptr; + } + } + TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create( SemaRef.Context, Owner, D->getBeginLoc(), D->getLocation(), D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(), - D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack()); + D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack(), + D->hasTypeConstraint(), NumExpanded); + Inst->setAccess(AS_public); Inst->setImplicit(D->isImplicit()); - + if (auto *TC = D->getTypeConstraint()) { + // TODO: Concepts: do not instantiate the constraint (delayed constraint + // substitution) + const ASTTemplateArgumentListInfo *TemplArgInfo + = TC->getTemplateArgsAsWritten(); + TemplateArgumentListInfo InstArgs; + + if (TemplArgInfo) { + InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); + InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); + if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(), + TemplArgInfo->NumTemplateArgs, + InstArgs, TemplateArgs)) + return nullptr; + } + if (SemaRef.AttachTypeConstraint( + TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), + TC->getNamedConcept(), &InstArgs, Inst, + D->isParameterPack() + ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc() + : SourceLocation())) + return nullptr; + } if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { TypeSourceInfo *InstantiatedDefaultArg = SemaRef.SubstType(D->getDefaultArgumentInfo(), TemplateArgs, diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index d77542be53f..3884fdae8fe 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3016,7 +3016,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(), /*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(), TemplateParameterDepth, AutoParameterPosition, - /*Identifier*/ nullptr, false, IsParameterPack); + /*Identifier*/ nullptr, false, IsParameterPack, + /*HasTypeConstraint=*/false); CorrespondingTemplateParam->setImplicit(); LSI->TemplateParams.push_back(CorrespondingTemplateParam); // Replace the 'auto' in the function parameter with this invented diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 1d775dab67b..3b827fbc950 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3064,13 +3064,13 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildConceptSpecializationExpr(NestedNameSpecifierLoc NNS, - SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc, + SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, TemplateArgumentListInfo *TALI) { CXXScopeSpec SS; SS.Adopt(NNS); ExprResult Result = getSema().CheckConceptTemplateId(SS, TemplateKWLoc, - ConceptNameLoc, + ConceptNameInfo, FoundDecl, NamedConcept, TALI); if (Result.isInvalid()) @@ -11175,7 +11175,7 @@ TreeTransform<Derived>::TransformConceptSpecializationExpr( return getDerived().RebuildConceptSpecializationExpr( E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(), - E->getConceptNameLoc(), E->getFoundDecl(), E->getNamedConcept(), + E->getConceptNameInfo(), E->getFoundDecl(), E->getNamedConcept(), &TransArgs); } |