diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-03-10 20:44:00 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-03-10 20:44:00 +0000 |
commit | df667e71b1daadeacb230cf94fc717843f1a138a (patch) | |
tree | 72ebde19e19176d2cc776ce1dab15dc5c6e0d5c3 /lib | |
parent | 27b152fa7443f4e24630b997c07def6b0c23925a (diff) |
Extend the notion of active template instantiations to include the
context of a template-id for which we need to instantiate default
template arguments.
In the TextDiagnosticPrinter, don't suppress the caret diagnostic if
we are producing a non-note diagnostic that follows a note diagnostic
with the same location, because notes are (conceptually) a part of the
warning or error that comes before them.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66572 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/Type.cpp | 14 | ||||
-rw-r--r-- | lib/Frontend/TextDiagnosticPrinter.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 64 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 91 |
5 files changed, 162 insertions, 31 deletions
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 205ebef20b..1b7fc1be4a 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1287,10 +1287,9 @@ void TemplateTypeParmType::getAsStringInternal(std::string &InnerString) const { InnerString = Name->getName() + InnerString; } -/// \brief Print a template argument list, including the '<' and '>' -/// enclosing the template arguments. -static std::string printTemplateArgumentList(const TemplateArgument *Args, - unsigned NumArgs) { +std::string ClassTemplateSpecializationType::PrintTemplateArgumentList( + const TemplateArgument *Args, + unsigned NumArgs) { std::string SpecString; SpecString += '<'; for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { @@ -1343,7 +1342,7 @@ void ClassTemplateSpecializationType:: getAsStringInternal(std::string &InnerString) const { std::string SpecString = Template->getNameAsString(); - SpecString += printTemplateArgumentList(getArgs(), getNumArgs()); + SpecString += PrintTemplateArgumentList(getArgs(), getNumArgs()); if (InnerString.empty()) InnerString.swap(SpecString); else @@ -1409,8 +1408,9 @@ void TagType::getAsStringInternal(std::string &InnerString) const { if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(getDecl())) { std::string TemplateArgs - = printTemplateArgumentList(Spec->getTemplateArgs(), - Spec->getNumTemplateArgs()); + = ClassTemplateSpecializationType::PrintTemplateArgumentList( + Spec->getTemplateArgs(), + Spec->getNumTemplateArgs()); InnerString = TemplateArgs + InnerString; } diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 3e6c3ae74b..160b5cfae1 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -278,15 +278,19 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, OS.write(OutStr.begin(), OutStr.size()); OS << '\n'; - // If caret diagnostics are enabled and we have location, we want to emit the - // caret. However, we only do this if the location moved from the last - // diagnostic, or if the diagnostic has ranges. We don't want to emit the - // same caret multiple times if one loc has multiple diagnostics. + // If caret diagnostics are enabled and we have location, we want to + // emit the caret. However, we only do this if the location moved + // from the last diagnostic, if the last diagnostic was a note that + // was part of a different warning or error diagnostic, or if the + // diagnostic has ranges. We don't want to emit the same caret + // multiple times if one loc has multiple diagnostics. if (CaretDiagnostics && Info.getLocation().isValid() && ((LastLoc != Info.getLocation()) || Info.getNumRanges() || + (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) || Info.getNumCodeModificationHints())) { // Cache the LastLoc, it allows us to omit duplicate source/caret spewage. LastLoc = Info.getLocation(); + LastCaretDiagnosticWasNote = (Level == Diagnostic::Note); // Get the ranges into a local array we can hack on. SourceRange Ranges[20]; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index d68924c7c0..c4964bf69b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -245,7 +245,7 @@ public: DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); if (!Diags.isBuiltinNote(DiagID) && !ActiveTemplateInstantiations.empty() && - ActiveTemplateInstantiations.back().Entity + ActiveTemplateInstantiations.back() != LastTemplateInstantiationErrorContext) DB << PostDiagnosticHook(PrintInstantiationStackHook, this); return DB; @@ -1673,16 +1673,61 @@ public: /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { + /// \brief The kind of template instantiation we are performing + enum { + /// We are instantiating a template declaration. The entity is + /// the declaration we're instantiation (e.g., a + /// ClassTemplateSpecializationDecl). + TemplateInstantiation, + + /// We are instantiating a default argument for a template + /// parameter. The Entity is the template, and + /// TemplateArgs/NumTemplateArguments provides the template + /// arguments as specified. + DefaultTemplateArgumentInstantiation + } Kind; + /// \brief The point of instantiation within the source code. SourceLocation PointOfInstantiation; /// \brief The entity that is being instantiated. - ClassTemplateSpecializationDecl *Entity; + uintptr_t Entity; + + // \brief If this the instantiation of a default template + // argument, the list of tempalte arguments. + const TemplateArgument *TemplateArgs; + + /// \brief The number of template arguments in TemplateArgs. + unsigned NumTemplateArgs; /// \brief The source range that covers the construct that cause /// the instantiation, e.g., the template-id that causes a class /// template instantiation. SourceRange InstantiationRange; + + friend bool operator==(const ActiveTemplateInstantiation &X, + const ActiveTemplateInstantiation &Y) { + if (X.Kind != Y.Kind) + return false; + + if (X.Entity != Y.Entity) + return false; + + switch (X.Kind) { + case TemplateInstantiation: + return true; + + case DefaultTemplateArgumentInstantiation: + return X.TemplateArgs == Y.TemplateArgs; + } + + return true; + } + + friend bool operator!=(const ActiveTemplateInstantiation &X, + const ActiveTemplateInstantiation &Y) { + return !(X == Y); + } }; /// \brief List of active template instantiations. @@ -1701,7 +1746,7 @@ public: /// instantiation backtraces when there are multiple errors in the /// same instantiation. FIXME: Does this belong in Sema? It's tough /// to implement it anywhere else. - ClassTemplateSpecializationDecl *LastTemplateInstantiationErrorContext; + ActiveTemplateInstantiation LastTemplateInstantiationErrorContext; /// \brief A stack object to be created when performing template /// instantiation. @@ -1715,9 +1760,19 @@ public: /// Destruction of this object will pop the named instantiation off /// the stack. struct InstantiatingTemplate { + /// \brief Note that we are instantiating a class template. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *Entity, SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are instantiating a default argument in a + /// template-id. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange = SourceRange()); + ~InstantiatingTemplate(); /// \brief Determines whether we have exceeded the maximum @@ -1728,6 +1783,9 @@ public: Sema &SemaRef; bool Invalid; + bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, + SourceRange InstantiationRange); + InstantiatingTemplate(const InstantiatingTemplate&); // not implemented InstantiatingTemplate& diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index fc1173d9d1..ea91a3836a 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -825,10 +825,15 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. - if (ArgType->isDependentType()) + if (ArgType->isDependentType()) { + InstantiatingTemplate Inst(*this, TemplateLoc, + Template, &Converted[0], + Converted.size(), + SourceRange(TemplateLoc, RAngleLoc)); ArgType = InstantiateType(ArgType, &Converted[0], Converted.size(), TTP->getDefaultArgumentLoc(), TTP->getDeclName()); + } if (ArgType.isNull()) return true; @@ -888,6 +893,11 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, QualType NTTPType = NTTP->getType(); if (NTTPType->isDependentType()) { // Instantiate the type of the non-type template parameter. + InstantiatingTemplate Inst(*this, TemplateLoc, + Template, &Converted[0], + Converted.size(), + SourceRange(TemplateLoc, RAngleLoc)); + NTTPType = InstantiateType(NTTPType, &Converted[0], Converted.size(), NTTP->getLocation(), diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 057b256ddd..21694b2e73 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -30,19 +30,38 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *Entity, SourceRange InstantiationRange) : SemaRef(SemaRef) { - if (SemaRef.ActiveTemplateInstantiations.size() - > SemaRef.getLangOptions().InstantiationDepth) { - SemaRef.Diag(PointOfInstantiation, - diag::err_template_recursion_depth_exceeded) - << SemaRef.getLangOptions().InstantiationDepth - << InstantiationRange; - SemaRef.Diag(PointOfInstantiation, diag::note_template_recursion_depth) - << SemaRef.getLangOptions().InstantiationDepth; - Invalid = true; - } else { + + Invalid = CheckInstantiationDepth(PointOfInstantiation, + InstantiationRange); + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind = ActiveTemplateInstantiation::TemplateInstantiation; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Entity = reinterpret_cast<uintptr_t>(Entity); + Inst.InstantiationRange = InstantiationRange; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + Invalid = false; + } +} + +Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, + SourceLocation PointOfInstantiation, + TemplateDecl *Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange) + : SemaRef(SemaRef) { + + Invalid = CheckInstantiationDepth(PointOfInstantiation, + InstantiationRange); + if (!Invalid) { ActiveTemplateInstantiation Inst; + Inst.Kind + = ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation; Inst.PointOfInstantiation = PointOfInstantiation; - Inst.Entity = Entity; + Inst.Entity = reinterpret_cast<uintptr_t>(Template); + Inst.TemplateArgs = TemplateArgs; + Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; SemaRef.ActiveTemplateInstantiations.push_back(Inst); Invalid = false; @@ -54,12 +73,28 @@ Sema::InstantiatingTemplate::~InstantiatingTemplate() { SemaRef.ActiveTemplateInstantiations.pop_back(); } +bool Sema::InstantiatingTemplate::CheckInstantiationDepth( + SourceLocation PointOfInstantiation, + SourceRange InstantiationRange) { + if (SemaRef.ActiveTemplateInstantiations.size() + <= SemaRef.getLangOptions().InstantiationDepth) + return false; + + SemaRef.Diag(PointOfInstantiation, + diag::err_template_recursion_depth_exceeded) + << SemaRef.getLangOptions().InstantiationDepth + << InstantiationRange; + SemaRef.Diag(PointOfInstantiation, diag::note_template_recursion_depth) + << SemaRef.getLangOptions().InstantiationDepth; + return true; +} + /// \brief Post-diagnostic hook for printing the instantiation stack. void Sema::PrintInstantiationStackHook(unsigned, void *Cookie) { Sema &SemaRef = *static_cast<Sema*>(Cookie); SemaRef.PrintInstantiationStack(); SemaRef.LastTemplateInstantiationErrorContext - = SemaRef.ActiveTemplateInstantiations.back().Entity; + = SemaRef.ActiveTemplateInstantiations.back(); } /// \brief Prints the current instantiation stack through a series of @@ -70,10 +105,30 @@ void Sema::PrintInstantiationStack() { ActiveEnd = ActiveTemplateInstantiations.rend(); Active != ActiveEnd; ++Active) { - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), - diag::note_template_class_instantiation_here) - << Context.getTypeDeclType(Active->Entity) - << Active->InstantiationRange; + switch (Active->Kind) { + case ActiveTemplateInstantiation::TemplateInstantiation: { + ClassTemplateSpecializationDecl *Spec + = cast<ClassTemplateSpecializationDecl>((Decl*)Active->Entity); + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_template_class_instantiation_here) + << Context.getTypeDeclType(Spec) + << Active->InstantiationRange; + break; + } + + case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: { + TemplateDecl *Template = cast<TemplateDecl>((Decl *)Active->Entity); + std::string TemplateArgsStr + = ClassTemplateSpecializationType::PrintTemplateArgumentList( + Active->TemplateArgs, + Active->NumTemplateArgs); + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_default_arg_instantiation_here) + << (Template->getNameAsString() + TemplateArgsStr) + << Active->InstantiationRange; + break; + } + } } } @@ -482,6 +537,10 @@ QualType Sema::InstantiateType(QualType T, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation Loc, DeclarationName Entity) { + assert(!ActiveTemplateInstantiations.empty() && + "Cannot perform an instantiation without some context on the " + "instantiation stack"); + // If T is not a dependent type, there is nothing to do. if (!T->isDependentType()) return T; |