diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-03-09 23:48:35 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-03-09 23:48:35 +0000 |
commit | 40808ce6ac04b102c3b56244a635d6b98eed6d97 (patch) | |
tree | 92301d6219bc011b5ef02707aa8251e30d3f0db0 /lib/Sema/SemaTemplate.cpp | |
parent | e15b486ada22517bd976768cabf80213cef44347 (diff) |
Implement template instantiation for ClassTemplateSpecializationTypes,
such as replacing 'T' in vector<T>. There are a few aspects to this:
- Extend TemplateArgument to allow arbitrary expressions (an
Expr*), and switch ClassTemplateSpecializationType to store
TemplateArguments rather than it's own type-or-expression
representation.
- ClassTemplateSpecializationType can now store dependent types. In
that case, the canonical type is another
ClassTemplateSpecializationType (with default template arguments
expanded) rather than a declaration (we don't build Decls for
dependent types).
- Split ActOnClassTemplateId into ActOnClassTemplateId (called from
the parser) and CheckClassTemplateId (called from
ActOnClassTemplateId and InstantiateType). They're smart enough to
handle dependent types, now.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66509 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 306 |
1 files changed, 195 insertions, 111 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index a55e3a5184..281984de2c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -658,61 +658,115 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, return Invalid; } -Action::TypeResult -Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, +/// \brief Translates template arguments as provided by the parser +/// into template arguments used by semantic analysis. +static void +translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc, - const CXXScopeSpec *SS) { - TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD)); - ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(Template); + llvm::SmallVector<TemplateArgument, 16> &TemplateArgs) { + TemplateArgs.reserve(TemplateArgsIn.size()); + + void **Args = TemplateArgsIn.getArgs(); + bool *ArgIsType = TemplateArgsIn.getArgIsType(); + for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) { + TemplateArgs.push_back( + ArgIsType[Arg]? TemplateArgument(TemplateArgLocs[Arg], + QualType::getFromOpaquePtr(Args[Arg])) + : TemplateArgument(reinterpret_cast<Expr *>(Args[Arg]))); + } +} +QualType Sema::CheckClassTemplateId(ClassTemplateDecl *ClassTemplate, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc) { // Check that the template argument list is well-formed for this // template. llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs; - if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, - TemplateArgs, TemplateArgLocs, RAngleLoc, + if (CheckTemplateArgumentList(ClassTemplate, TemplateLoc, LAngleLoc, + TemplateArgs, NumTemplateArgs, RAngleLoc, ConvertedTemplateArgs)) - return true; + return QualType(); assert((ConvertedTemplateArgs.size() == - Template->getTemplateParameters()->size()) && + ClassTemplate->getTemplateParameters()->size()) && "Converted template argument list is too short!"); - // Find the class template specialization declaration that - // corresponds to these arguments. - llvm::FoldingSetNodeID ID; - ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size()); - void *InsertPos = 0; - ClassTemplateSpecializationDecl *Decl - = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); - if (!Decl) { - // This is the first time we have referenced this class template - // specialization. Create the canonical declaration and add it to - // the set of specializations. - Decl = ClassTemplateSpecializationDecl::Create(Context, + QualType CanonType; + + if (ClassTemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, + NumTemplateArgs)) { + // This class template specialization is a dependent + // type. Therefore, its canonical type is another class template + // specialization type that contains all of the converted + // arguments in canonical form. This ensures that, e.g., A<T> and + // A<T, T> have identical types when A is declared as: + // + // template<typename T, typename U = T> struct A; + + CanonType = Context.getClassTemplateSpecializationType(ClassTemplate, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); + } else { + // Find the class template specialization declaration that + // corresponds to these arguments. + llvm::FoldingSetNodeID ID; + ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); + void *InsertPos = 0; + ClassTemplateSpecializationDecl *Decl + = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); + if (!Decl) { + // This is the first time we have referenced this class template + // specialization. Create the canonical declaration and add it to + // the set of specializations. + Decl = ClassTemplateSpecializationDecl::Create(Context, ClassTemplate->getDeclContext(), - TemplateLoc, - ClassTemplate, - &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size(), - 0); - ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos); - Decl->setLexicalDeclContext(CurContext); + TemplateLoc, + ClassTemplate, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size(), + 0); + ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos); + Decl->setLexicalDeclContext(CurContext); + } + + CanonType = Context.getTypeDeclType(Decl); } // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - QualType Result - = Context.getClassTemplateSpecializationType(Template, - TemplateArgs.size(), - reinterpret_cast<uintptr_t *>(TemplateArgs.getArgs()), - TemplateArgs.getArgIsType(), - Context.getTypeDeclType(Decl)); - TemplateArgs.release(); + return Context.getClassTemplateSpecializationType(ClassTemplate, + TemplateArgs, + NumTemplateArgs, + CanonType); +} + +Action::TypeResult +Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + const CXXScopeSpec *SS) { + TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD)); + ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(Template); + + // Translate the parser's template argument list in our AST format. + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + + QualType Result = CheckClassTemplateId(ClassTemplate, TemplateLoc, + LAngleLoc, + &TemplateArgs[0], + TemplateArgs.size(), + RAngleLoc); + + TemplateArgsIn.release(); return Result.getAsOpaquePtr(); } @@ -721,13 +775,13 @@ Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc, bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - ASTTemplateArgsPtr& Args, - SourceLocation *TemplateArgLocs, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, SourceLocation RAngleLoc, llvm::SmallVectorImpl<TemplateArgument> &Converted) { TemplateParameterList *Params = Template->getTemplateParameters(); unsigned NumParams = Params->size(); - unsigned NumArgs = Args.size(); + unsigned NumArgs = NumTemplateArgs; bool Invalid = false; if (NumArgs > NumParams || @@ -737,7 +791,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // arguments. SourceRange Range; if (NumArgs > NumParams) - Range = SourceRange(TemplateArgLocs[NumParams], RAngleLoc); + Range = SourceRange(TemplateArgs[NumParams].getLocation(), RAngleLoc); Diag(TemplateLoc, diag::err_template_arg_list_different_arity) << (NumArgs > NumParams) << (isa<ClassTemplateDecl>(Template)? 0 : @@ -759,9 +813,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, ParamEnd = Params->end(); Param != ParamEnd; ++Param, ++ArgIdx) { // Decode the template argument - QualType ArgType; - Expr *ArgExpr = 0; - SourceLocation ArgLoc; + TemplateArgument Arg; if (ArgIdx >= NumArgs) { // Retrieve the default template argument from the template // parameter. @@ -769,7 +821,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (!TTP->hasDefaultArgument()) break; - ArgType = TTP->getDefaultArgument(); + QualType ArgType = TTP->getDefaultArgument(); // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. @@ -781,15 +833,14 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (ArgType.isNull()) return true; - ArgLoc = TTP->getDefaultArgumentLoc(); + Arg = TemplateArgument(TTP->getLocation(), ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { if (!NTTP->hasDefaultArgument()) break; // FIXME: Instantiate default argument - ArgExpr = NTTP->getDefaultArgument(); - ArgLoc = NTTP->getDefaultArgumentLoc(); + Arg = TemplateArgument(NTTP->getDefaultArgument()); } else { TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(*Param); @@ -798,29 +849,24 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, break; // FIXME: Instantiate default argument - ArgExpr = TempParm->getDefaultArgument(); - ArgLoc = TempParm->getDefaultArgumentLoc(); + Arg = TemplateArgument(TempParm->getDefaultArgument()); } } else { // Retrieve the template argument produced by the user. - ArgLoc = TemplateArgLocs[ArgIdx]; - - if (Args.getArgIsType()[ArgIdx]) - ArgType = QualType::getFromOpaquePtr(Args.getArgs()[ArgIdx]); - else - ArgExpr = reinterpret_cast<Expr *>(Args.getArgs()[ArgIdx]); + Arg = TemplateArgs[ArgIdx]; } if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { // Check template type parameters. - if (!ArgType.isNull()) { - if (CheckTemplateArgument(TTP, ArgType, ArgLoc)) + if (Arg.getKind() == TemplateArgument::Type) { + if (CheckTemplateArgument(TTP, Arg.getAsType(), Arg.getLocation())) Invalid = true; // Add the converted template type argument. Converted.push_back( - TemplateArgument(Context.getCanonicalType(ArgType))); + TemplateArgument(Arg.getLocation(), + Context.getCanonicalType(Arg.getAsType()))); continue; } @@ -829,9 +875,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // type shall be a type-id. // We have a template type parameter but the template argument - // is an expression. - Diag(ArgExpr->getSourceRange().getBegin(), - diag::err_template_arg_must_be_type); + // is not a type. + Diag(Arg.getLocation(), diag::err_template_arg_must_be_type); Diag((*Param)->getLocation(), diag::note_template_param_here); Invalid = true; } else if (NonTypeTemplateParmDecl *NTTP @@ -859,50 +904,81 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, } } - if (ArgExpr) { - if (CheckTemplateArgument(NTTP, NTTPType, ArgExpr, &Converted)) + switch (Arg.getKind()) { + case TemplateArgument::Expression: { + Expr *E = Arg.getAsExpr(); + if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted)) Invalid = true; - continue; + break; } - // We have a non-type template parameter but the template - // argument is a type. - - // C++ [temp.arg]p2: - // In a template-argument, an ambiguity between a type-id and - // an expression is resolved to a type-id, regardless of the - // form of the corresponding template-parameter. - // - // We warn specifically about this case, since it can be rather - // confusing for users. - if (ArgType->isFunctionType()) - Diag(ArgLoc, diag::err_template_arg_nontype_ambig) - << ArgType; - else - Diag(ArgLoc, diag::err_template_arg_must_be_expr); - Diag((*Param)->getLocation(), diag::note_template_param_here); - Invalid = true; + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + // We've already checked this template argument, so just copy + // it to the list of converted arguments. + Converted.push_back(Arg); + break; + + case TemplateArgument::Type: + // We have a non-type template parameter but the template + // argument is a type. + + // C++ [temp.arg]p2: + // In a template-argument, an ambiguity between a type-id and + // an expression is resolved to a type-id, regardless of the + // form of the corresponding template-parameter. + // + // We warn specifically about this case, since it can be rather + // confusing for users. + if (Arg.getAsType()->isFunctionType()) + Diag(Arg.getLocation(), diag::err_template_arg_nontype_ambig) + << Arg.getAsType(); + else + Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr); + Diag((*Param)->getLocation(), diag::note_template_param_here); + Invalid = true; + } } else { // Check template template parameters. TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(*Param); - if (ArgExpr && isa<DeclRefExpr>(ArgExpr) && - isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) { - if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr))) - Invalid = true; - - // Add the converted template argument. - // FIXME: Need the "canonical" template declaration! - Converted.push_back( - TemplateArgument(cast<DeclRefExpr>(ArgExpr)->getDecl())); - continue; + switch (Arg.getKind()) { + case TemplateArgument::Expression: { + Expr *ArgExpr = Arg.getAsExpr(); + if (ArgExpr && isa<DeclRefExpr>(ArgExpr) && + isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) { + if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr))) + Invalid = true; + + // Add the converted template argument. + // FIXME: Need the "canonical" template declaration! + Converted.push_back( + TemplateArgument(Arg.getLocation(), + cast<DeclRefExpr>(ArgExpr)->getDecl())); + continue; + } + } + // fall through + + case TemplateArgument::Type: { + // We have a template template parameter but the template + // argument does not refer to a template. + Diag(Arg.getLocation(), diag::err_template_arg_must_be_template); + Invalid = true; + break; } - // We have a template template parameter but the template - // argument does not refer to a template. - Diag(ArgLoc, diag::err_template_arg_must_be_template); - Invalid = true; + case TemplateArgument::Declaration: + // We've already checked this template argument, so just copy + // it to the list of converted arguments. + Converted.push_back(Arg); + break; + + case TemplateArgument::Integral: + assert(false && "Integral argument with template template parameter"); + break; + } } } @@ -1109,11 +1185,16 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, llvm::SmallVectorImpl<TemplateArgument> *Converted) { + SourceLocation StartLoc = Arg->getSourceRange().getBegin(); + // If either the parameter has a dependent type or the argument is // type-dependent, there's nothing we can check now. // FIXME: Add template argument to Converted! - if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) + if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) { + // FIXME: Produce a cloned, canonical expression? + Converted->push_back(TemplateArgument(Arg)); return false; + } // C++ [temp.arg.nontype]p5: // The following conversions are performed on each expression used @@ -1188,7 +1269,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, IntegerType->isSignedIntegerType()); CanonicalArg = Value; - Converted->push_back(TemplateArgument(CanonicalArg)); + Converted->push_back(TemplateArgument(StartLoc, CanonicalArg)); } return false; @@ -1252,7 +1333,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; if (Converted) - Converted->push_back(TemplateArgument(Member)); + Converted->push_back(TemplateArgument(StartLoc, Member)); return false; } @@ -1262,7 +1343,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; if (Converted) - Converted->push_back(TemplateArgument(Entity)); + Converted->push_back(TemplateArgument(StartLoc, Entity)); return false; } @@ -1297,7 +1378,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; if (Converted) - Converted->push_back(TemplateArgument(Entity)); + Converted->push_back(TemplateArgument(StartLoc, Entity)); return false; } @@ -1339,7 +1420,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; if (Converted) - Converted->push_back(TemplateArgument(Entity)); + Converted->push_back(TemplateArgument(StartLoc, Entity)); return false; } @@ -1366,7 +1447,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; if (Converted) - Converted->push_back(TemplateArgument(Member)); + Converted->push_back(TemplateArgument(StartLoc, Member)); return false; } @@ -1649,7 +1730,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, DeclTy *TemplateD, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, + ASTTemplateArgsPtr TemplateArgsIn, SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc, AttributeList *Attr, @@ -1701,12 +1782,16 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, Kind = ClassTemplate->getTemplatedDecl()->getTagKind(); } + // Translate the parser's template argument list in our AST format. + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + // Check that the template argument list is well-formed for this // template. llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, - TemplateArgs, TemplateArgLocs, RAngleLoc, - ConvertedTemplateArgs)) + &TemplateArgs[0], TemplateArgs.size(), + RAngleLoc, ConvertedTemplateArgs)) return 0; assert((ConvertedTemplateArgs.size() == @@ -1786,11 +1871,10 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, // template arguments in the specialization. Specialization->setTypeAsWritten( Context.getClassTemplateSpecializationType(ClassTemplate, + &TemplateArgs[0], TemplateArgs.size(), - reinterpret_cast<uintptr_t *>(TemplateArgs.getArgs()), - TemplateArgs.getArgIsType(), Context.getTypeDeclType(Specialization))); - TemplateArgs.release(); + TemplateArgsIn.release(); // C++ [temp.expl.spec]p9: // A template explicit specialization is in the scope of the |