From: Douglas Gregor Date: Tue, 10 Mar 2009 20:44:00 +0000 (+0000) Subject: Extend the notion of active template instantiations to include the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=df667e71b1daadeacb230cf94fc717843f1a138a;p=clang 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 --- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 1c0a081c45..2487da61c8 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1449,6 +1449,11 @@ public: static bool anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs); + /// \brief Print a template argument list, including the '<' and '>' + /// enclosing the template arguments. + static std::string PrintTemplateArgumentList(const TemplateArgument *Args, + unsigned NumArgs); + typedef const TemplateArgument * iterator; iterator begin() const { return getArgs(); } diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 46d81445b6..271e14d8a1 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -649,6 +649,8 @@ DIAG(err_template_implicit_instantiate_undefined, ERROR, "implicit instantiation of undefined template %0") DIAG(note_template_class_instantiation_here, NOTE, "in instantiation of template class %0 requested here") +DIAG(note_default_arg_instantiation_here, NOTE, + "in instantiation of default argument for '%0' required here") DIAG(err_unexpected_typedef, ERROR, "unexpected type name %0: expected expression") diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h index c9fbae6ebb..eeff279513 100644 --- a/include/clang/Frontend/TextDiagnosticPrinter.h +++ b/include/clang/Frontend/TextDiagnosticPrinter.h @@ -28,6 +28,7 @@ class SourceManager; class TextDiagnosticPrinter : public DiagnosticClient { SourceLocation LastWarningLoc; FullSourceLoc LastLoc; + bool LastCaretDiagnosticWasNote; llvm::raw_ostream &OS; bool ShowColumn; bool CaretDiagnostics; @@ -35,8 +36,8 @@ class TextDiagnosticPrinter : public DiagnosticClient { public: TextDiagnosticPrinter(llvm::raw_ostream &os, bool showColumn = true, bool caretDiagnistics = true, bool showLocation = true) - : OS(os), ShowColumn(showColumn), CaretDiagnostics(caretDiagnistics), - ShowLocation(showLocation) {} + : LastCaretDiagnosticWasNote(false), OS(os), ShowColumn(showColumn), + CaretDiagnostics(caretDiagnistics), ShowLocation(showLocation) {} void PrintIncludeStack(SourceLocation Loc, const SourceManager &SM); 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(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(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(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(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((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((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; diff --git a/test/SemaTemplate/instantiation-default-1.cpp b/test/SemaTemplate/instantiation-default-1.cpp index 57071f4640..3060fdc6fd 100644 --- a/test/SemaTemplate/instantiation-default-1.cpp +++ b/test/SemaTemplate/instantiation-default-1.cpp @@ -32,7 +32,8 @@ void test_Def2(Def2 *d2) { d2->foo(); } -Def2 *d2; +typedef int& int_ref_t; +Def2 *d2; // expected-note{{in instantiation of default argument for 'Def2' required here}} template<> struct Def1 { }; // expected-error{{redefinition of 'Def1'}} diff --git a/test/SemaTemplate/instantiation-default-2.cpp b/test/SemaTemplate/instantiation-default-2.cpp index e91a98e2f7..9d6b047f37 100644 --- a/test/SemaTemplate/instantiation-default-2.cpp +++ b/test/SemaTemplate/instantiation-default-2.cpp @@ -15,4 +15,4 @@ Constant *c5; Constant *c6; // expected-error{{non-type template argument of type 'float (*)(int, double)' cannot be converted to a value of type 'float (*)(int, int)'}} -Constant *c7; +Constant *c7; // expected-note{{in instantiation of default argument for 'Constant' required here}}