diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 0b5d337a0766..e7f2dccd5c98 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -760,6 +760,13 @@ public: /// types, values, and templates. TemplateName getCanonicalTemplateName(TemplateName Name); + /// \brief Retrieve the "canonical" template argument. + /// + /// The canonical template argument is the simplest template argument + /// (which may be a type, value, expression, or declaration) that + /// expresses the value of the argument. + TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg); + /// Type Query functions. If the type is an instance of the specified class, /// return the Type pointer for the underlying maximally pretty type. This /// is a member of ASTContext because this may need to do some amount of diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 06835cb5ce8c..d607ca7702f0 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1669,26 +1669,53 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, QualType Canon) { - if (!Canon.isNull()) + if (Canon.isNull()) { + // Build the canonical template specialization type, since no type + // was provided. + TemplateName CanonTemplate = getCanonicalTemplateName(Template); + llvm::SmallVector CanonArgs; + CanonArgs.reserve(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) + CanonArgs.push_back(getCanonicalTemplateArgument(Args[I])); + + // Determine whether this canonical template specialization type already + // exists. + llvm::FoldingSetNodeID ID; + TemplateSpecializationType::Profile(ID, CanonTemplate, + CanonArgs.data(), NumArgs); + + void *InsertPos = 0; + TemplateSpecializationType *Spec + = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + + if (!Spec) { + // Allocate a new canonical template specialization type. + void *Mem = Allocate((sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * NumArgs), + 8); + Spec = new (Mem) TemplateSpecializationType(CanonTemplate, + CanonArgs.data(), NumArgs, + QualType()); + Types.push_back(Spec); + TemplateSpecializationTypes.InsertNode(Spec, InsertPos); + } + + Canon = QualType(Spec, 0); + assert(Canon->isDependentType() && + "Non-dependent template-id type must have a canonical type"); + } else Canon = getCanonicalType(Canon); - llvm::FoldingSetNodeID ID; - TemplateSpecializationType::Profile(ID, Template, Args, NumArgs); - - void *InsertPos = 0; - TemplateSpecializationType *Spec - = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); - - if (Spec) - return QualType(Spec, 0); - + // Allocate the (non-canonical) template specialization type, but don't + // try to unique it: these types typically have location information that + // we don't unique and don't want to lose. void *Mem = Allocate((sizeof(TemplateSpecializationType) + sizeof(TemplateArgument) * NumArgs), 8); - Spec = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, Canon); + TemplateSpecializationType *Spec + = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, Canon); + Types.push_back(Spec); - TemplateSpecializationTypes.InsertNode(Spec, InsertPos); - return QualType(Spec, 0); } @@ -2013,6 +2040,49 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { return DTN->CanonicalTemplateName; } +TemplateArgument +ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + return Arg; + + case TemplateArgument::Expression: + // FIXME: Build canonical expression? + return Arg; + + case TemplateArgument::Declaration: + return TemplateArgument(SourceLocation(), + Arg.getAsDecl()->getCanonicalDecl()); + + case TemplateArgument::Integral: + return TemplateArgument(SourceLocation(), + *Arg.getAsIntegral(), + getCanonicalType(Arg.getIntegralType())); + + case TemplateArgument::Type: + return TemplateArgument(SourceLocation(), + getCanonicalType(Arg.getAsType())); + + case TemplateArgument::Pack: { + // FIXME: Allocate in ASTContext + TemplateArgument *CanonArgs = new TemplateArgument[Arg.pack_size()]; + unsigned Idx = 0; + for (TemplateArgument::pack_iterator A = Arg.pack_begin(), + AEnd = Arg.pack_end(); + A != AEnd; (void)++A, ++Idx) + CanonArgs[Idx] = getCanonicalTemplateArgument(*A); + + TemplateArgument Result; + Result.setArgumentPack(CanonArgs, Arg.pack_size(), false); + return Result; + } + } + + // Silence GCC warning + assert(false && "Unhandled template argument kind"); + return TemplateArgument(); +} + NestedNameSpecifier * ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { if (!NNS) diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index ce382dbdad6c..686b78d02335 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -171,52 +171,32 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { // better to fix that redundancy. TemplateParameterList *Params = getTemplateParameters(); - llvm::SmallVector TemplateArgs; - llvm::SmallVector CanonTemplateArgs; TemplateArgs.reserve(Params->size()); - CanonTemplateArgs.reserve(Params->size()); - - for (TemplateParameterList::iterator - Param = Params->begin(), ParamEnd = Params->end(); + for (TemplateParameterList::iterator Param = Params->begin(), + ParamEnd = Params->end(); Param != ParamEnd; ++Param) { if (isa(*Param)) { QualType ParamType = Context.getTypeDeclType(cast(*Param)); TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(), ParamType)); - CanonTemplateArgs.push_back( - TemplateArgument((*Param)->getLocation(), - Context.getCanonicalType(ParamType))); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*Param)) { - // FIXME: Build canonical expression, too! Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(), NTTP->getLocation(), NTTP->getType()->isDependentType(), /*Value-dependent=*/true); TemplateArgs.push_back(TemplateArgument(E)); - CanonTemplateArgs.push_back(TemplateArgument(E)); } else { TemplateTemplateParmDecl *TTP = cast(*Param); TemplateArgs.push_back(TemplateArgument(TTP->getLocation(), TTP)); - CanonTemplateArgs.push_back(TemplateArgument(TTP->getLocation(), - TTP->getCanonicalDecl())); } } - // FIXME: I should really move the "build-the-canonical-type" logic - // into ASTContext::getTemplateSpecializationType. - TemplateName Name = TemplateName(this); - QualType CanonType = Context.getTemplateSpecializationType( - Context.getCanonicalTemplateName(Name), - &CanonTemplateArgs[0], - CanonTemplateArgs.size()); - CommonPtr->InjectedClassNameType - = Context.getTemplateSpecializationType(Name, + = Context.getTemplateSpecializationType(TemplateName(this), &TemplateArgs[0], - TemplateArgs.size(), - CanonType); + TemplateArgs.size()); return CommonPtr->InjectedClassNameType; } @@ -290,6 +270,7 @@ void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, return; } + // FIXME: Allocate in ASTContext Args.Args = new TemplateArgument[NumArgs]; for (unsigned I = 0; I != Args.NumArgs; ++I) Args.Args[I] = args[I]; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 9ab6164c4846..97812046f7f2 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -874,67 +874,6 @@ translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, } } -/// \brief Build a canonical version of a template argument list. -/// -/// This function builds a canonical version of the given template -/// argument list, where each of the template arguments has been -/// converted into its canonical form. This routine is typically used -/// to canonicalize a template argument list when the template name -/// itself is dependent. When the template name refers to an actual -/// template declaration, Sema::CheckTemplateArgumentList should be -/// used to check and canonicalize the template arguments. -/// -/// \param TemplateArgs The incoming template arguments. -/// -/// \param NumTemplateArgs The number of template arguments in \p -/// TemplateArgs. -/// -/// \param Canonical A vector to be filled with the canonical versions -/// of the template arguments. -/// -/// \param Context The ASTContext in which the template arguments live. -static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs, - llvm::SmallVectorImpl &Canonical, - ASTContext &Context) { - Canonical.reserve(NumTemplateArgs); - for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) { - switch (TemplateArgs[Idx].getKind()) { - case TemplateArgument::Null: - assert(false && "Should never see a NULL template argument here"); - break; - - case TemplateArgument::Expression: - // FIXME: Build canonical expression (!) - Canonical.push_back(TemplateArgs[Idx]); - break; - - case TemplateArgument::Declaration: - Canonical.push_back( - TemplateArgument(SourceLocation(), - TemplateArgs[Idx].getAsDecl()->getCanonicalDecl())); - break; - - case TemplateArgument::Integral: - Canonical.push_back(TemplateArgument(SourceLocation(), - *TemplateArgs[Idx].getAsIntegral(), - TemplateArgs[Idx].getIntegralType())); - break; - - case TemplateArgument::Type: { - QualType CanonType - = Context.getCanonicalType(TemplateArgs[Idx].getAsType()); - Canonical.push_back(TemplateArgument(SourceLocation(), CanonType)); - break; - } - - case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); - break; - } - } -} - QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -945,22 +884,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, if (!Template) { // The template name does not resolve to a template, so we just // build a dependent template-id type. - - // Canonicalize the template arguments to build the canonical - // template-id type. - llvm::SmallVector CanonicalTemplateArgs; - CanonicalizeTemplateArguments(TemplateArgs, NumTemplateArgs, - CanonicalTemplateArgs, Context); - - TemplateName CanonName = Context.getCanonicalTemplateName(Name); - QualType CanonType - = Context.getTemplateSpecializationType(CanonName, - &CanonicalTemplateArgs[0], - CanonicalTemplateArgs.size()); - - // Build the dependent template-id type. return Context.getTemplateSpecializationType(Name, TemplateArgs, - NumTemplateArgs, CanonType); + NumTemplateArgs); } // Check that the template argument list is well-formed for this @@ -992,6 +917,12 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, CanonType = Context.getTemplateSpecializationType(CanonName, Converted.getFlatArguments(), Converted.flatSize()); + + // FIXME: CanonType is not actually the canonical type, and unfortunately + // it is a TemplateTypeSpecializationType that we will never use again. + // In the future, we need to teach getTemplateSpecializationType to only + // build the canonical type and return that to us. + CanonType = Context.getCanonicalType(CanonType); } else if (ClassTemplateDecl *ClassTemplate = dyn_cast(Template)) { // Find the class template specialization declaration that