diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index 0d1caca00a9c..e2850d9f0485 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -585,7 +585,8 @@ private: // diagnostic is in flight at a time. friend class DiagnosticBuilder; friend class DiagnosticInfo; - + friend class PartialDiagnostic; + /// CurDiagLoc - This is the location of the current diagnostic that is in /// flight. FullSourceLoc CurDiagLoc; @@ -667,6 +668,8 @@ class DiagnosticBuilder { explicit DiagnosticBuilder(Diagnostic *diagObj) : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixItHints(0) {} + friend class PartialDiagnostic; + public: /// Copy constructor. When copied, this "takes" the diagnostic info from the /// input and neuters it. @@ -703,6 +706,17 @@ public: /// isActive - Determine whether this diagnostic is still active. bool isActive() const { return DiagObj != 0; } + /// \brief Retrieve the active diagnostic ID. + /// + /// \pre \c isActive() + unsigned getDiagID() const { + assert(isActive() && "Diagnostic is inactive"); + return DiagObj->CurDiagID; + } + + /// \brief Clear out the current diagnostic. + void Clear() { DiagObj = 0; } + /// Operator bool: conversion of DiagnosticBuilder to bool always returns /// true. This allows is to be used in boolean error contexts like: /// return Diag(...); diff --git a/clang/include/clang/Basic/PartialDiagnostic.h b/clang/include/clang/Basic/PartialDiagnostic.h index cd0da97e2ba3..1d96044a7184 100644 --- a/clang/include/clang/Basic/PartialDiagnostic.h +++ b/clang/include/clang/Basic/PartialDiagnostic.h @@ -57,6 +57,10 @@ public: /// what sort of argument kind it is. intptr_t DiagArgumentsVal[MaxArguments]; + /// \brief The values for the various substitution positions that have + /// string arguments. + std::string DiagArgumentsStr[MaxArguments]; + /// DiagRanges - The list of ranges added to this diagnostic. It currently /// only support 10 ranges, could easily be extended if needed. CharSourceRange DiagRanges[10]; @@ -186,6 +190,26 @@ public: *this->DiagStorage = *Other.DiagStorage; } + PartialDiagnostic(const DiagnosticInfo &Other, StorageAllocator &Allocator) + : DiagID(Other.getID()), DiagStorage(0), Allocator(&Allocator) + { + // Copy arguments. + for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) { + if (Other.getArgKind(I) == Diagnostic::ak_std_string) + AddString(Other.getArgStdStr(I)); + else + AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I)); + } + + // Copy source ranges. + for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I) + AddSourceRange(Other.getRange(I)); + + // Copy fix-its. + for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I) + AddFixItHint(Other.getFixItHint(I)); + } + PartialDiagnostic &operator=(const PartialDiagnostic &Other) { DiagID = Other.DiagID; if (Other.DiagStorage) { @@ -216,13 +240,28 @@ public: DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V; } + void AddString(llvm::StringRef V) const { + if (!DiagStorage) + DiagStorage = getStorage(); + + assert(DiagStorage->NumDiagArgs < Storage::MaxArguments && + "Too many arguments to diagnostic!"); + DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] + = Diagnostic::ak_std_string; + DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = V; + } + void Emit(const DiagnosticBuilder &DB) const { if (!DiagStorage) return; // Add all arguments. for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) { - DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i], + if ((Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i] + == Diagnostic::ak_std_string) + DB.AddString(DiagStorage->DiagArgumentsStr[i]); + else + DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i], (Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]); } @@ -230,7 +269,7 @@ public: for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i) DB.AddSourceRange(DiagStorage->DiagRanges[i]); - // Add all code modification hints + // Add all fix-its. for (unsigned i = 0, e = DiagStorage->NumFixItHints; i != e; ++i) DB.AddFixItHint(DiagStorage->FixItHints[i]); } @@ -262,6 +301,13 @@ public: return PD; } + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + llvm::StringRef S) { + + PD.AddString(S); + return PD; + } + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, const SourceRange &R) { PD.AddSourceRange(CharSourceRange::getTokenRange(R)); @@ -288,6 +334,9 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, return DB; } +/// \brief A partial diagnostic along with the source location where this +/// diagnostic occurs. +typedef std::pair PartialDiagnosticAt; } // end namespace clang #endif diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 7e0497836870..dcad3b2c9c74 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3266,6 +3266,10 @@ public: /// \brief The number of template arguments in TemplateArgs. unsigned NumTemplateArgs; + /// \brief The template deduction info object associated with the + /// substitution or checking of explicit or deduced template arguments. + sema::TemplateDeductionInfo *DeductionInfo; + /// \brief The source range that covers the construct that cause /// the instantiation, e.g., the template-id that causes a class /// template instantiation. @@ -3273,7 +3277,7 @@ public: ActiveTemplateInstantiation() : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), - NumTemplateArgs(0) {} + NumTemplateArgs(0), DeductionInfo(0) {} /// \brief Determines whether this template is an actual instantiation /// that should be counted toward the maximum instantiation depth. @@ -3343,7 +3347,15 @@ public: /// The top of this stack is used by a fixit instantiating unresolved /// function calls to fix the AST to match the textual change it prints. llvm::SmallVector CallsUndergoingInstantiation; - + + /// \brief For each declaration that involved template argument deduction, the + /// set of diagnostics that were suppressed during that template argument + /// deduction. + /// + /// FIXME: Serialize this structure to the AST file. + llvm::DenseMap > + SuppressedDiagnostics; + /// \brief A stack object to be created when performing template /// instantiation. /// @@ -3377,6 +3389,7 @@ public: const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, ActiveTemplateInstantiation::InstantiationKind Kind, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are instantiating as part of template @@ -3386,6 +3399,7 @@ public: ClassTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -3432,7 +3446,6 @@ public: private: Sema &SemaRef; bool Invalid; - bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, SourceRange InstantiationRange); @@ -3448,9 +3461,11 @@ public: /// template argument substitution failures are not considered /// errors. /// - /// When this routine returns true, the emission of most diagnostics - /// will be suppressed and there will be no local error recovery. - bool isSFINAEContext() const; + /// \returns The nearest template-deduction context object, if we are in a + /// SFINAE context, which can be used to capture diagnostics that will be + /// suppressed. Otherwise, returns NULL to indicate that we are not within a + /// SFINAE context. + sema::TemplateDeductionInfo *isSFINAEContext() const; /// \brief RAII class used to determine whether SFINAE has /// trapped any errors that occur during template argument diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h index ac32e9c24f6d..7cc35713aace 100644 --- a/clang/include/clang/Sema/TemplateDeduction.h +++ b/clang/include/clang/Sema/TemplateDeduction.h @@ -13,7 +13,9 @@ #ifndef LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H #define LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H +#include "clang/Basic/PartialDiagnostic.h" #include "clang/AST/DeclTemplate.h" +#include "llvm/ADT/SmallVector.h" namespace clang { @@ -21,7 +23,7 @@ class ASTContext; class TemplateArgumentList; namespace sema { - + /// \brief Provides information about an attempted template argument /// deduction, whose success or failure was described by a /// TemplateDeductionResult value. @@ -37,6 +39,10 @@ class TemplateDeductionInfo { /// deduction is occurring. SourceLocation Loc; + /// \brief Warnings (and follow-on notes) that were suppressed due to + /// SFINAE while performing template argument deduction. + llvm::SmallVector SuppressedDiagnostics; + // do not implement these TemplateDeductionInfo(const TemplateDeductionInfo&); TemplateDeductionInfo &operator=(const TemplateDeductionInfo&); @@ -69,6 +75,23 @@ public: Deduced = NewDeduced; } + /// \brief Add a new diagnostic to the set of diagnostics + void addSuppressedDiagnostic(SourceLocation Loc, const PartialDiagnostic &PD) { + SuppressedDiagnostics.push_back(std::make_pair(Loc, PD)); + } + + /// \brief Iterator over the set of suppressed diagnostics. + typedef llvm::SmallVectorImpl::const_iterator + diag_iterator; + + /// \brief Returns an iterator at the beginning of the sequence of suppressed + /// diagnostics. + diag_iterator diag_begin() const { return SuppressedDiagnostics.begin(); } + + /// \brief Returns an iterator at the end of the sequence of suppressed + /// diagnostics. + diag_iterator diag_end() const { return SuppressedDiagnostics.end(); } + /// \brief The template parameter to which a template argument /// deduction failure refers. /// diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index a0046a2caa1e..1b3572a6498b 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/APFloat.h" #include "clang/Sema/CXXFieldCollector.h" +#include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/PrettyDeclStackTrace.h" @@ -433,6 +434,41 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() { } Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { + if (!isActive()) + return; + + if (TemplateDeductionInfo *Info = SemaRef.isSFINAEContext()) { + switch (Diagnostic::getDiagnosticSFINAEResponse(getDiagID())) { + case Diagnostic::SFINAE_Report: + // Fall through; we'll report the diagnostic below. + break; + + case Diagnostic::SFINAE_SubstitutionFailure: + // Count this failure so that we know that template argument deduction + // has failed. + ++SemaRef.NumSFINAEErrors; + SemaRef.Diags.setLastDiagnosticIgnored(); + SemaRef.Diags.Clear(); + Clear(); + return; + + case Diagnostic::SFINAE_Suppress: + // Make a copy of this suppressed diagnostic and store it with the + // template-deduction information; + DiagnosticInfo DiagInfo(&SemaRef.Diags); + Info->addSuppressedDiagnostic(DiagInfo.getLocation(), + PartialDiagnostic(DiagInfo, + SemaRef.Context.getDiagAllocator())); + + // Suppress this diagnostic. + SemaRef.Diags.setLastDiagnosticIgnored(); + SemaRef.Diags.Clear(); + Clear(); + return; + } + } + + // Emit the diagnostic. if (!this->Emit()) return; @@ -451,25 +487,6 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { } Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID) { - if (isSFINAEContext()) { - switch (Diagnostic::getDiagnosticSFINAEResponse(DiagID)) { - case Diagnostic::SFINAE_Report: - // Fall through; we'll report the diagnostic below. - break; - - case Diagnostic::SFINAE_SubstitutionFailure: - // Count this failure so that we know that template argument deduction - // has failed. - ++NumSFINAEErrors; - // Fall through - - case Diagnostic::SFINAE_Suppress: - // Suppress this diagnostic. - Diags.setLastDiagnosticIgnored(); - return SemaDiagnosticBuilder(*this); - } - } - DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); return SemaDiagnosticBuilder(DB, *this, DiagID); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 68bb2b072339..609465c50523 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -56,6 +56,24 @@ using namespace sema; /// referenced), false otherwise. /// bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { + if (getLangOptions().CPlusPlus && isa(D)) { + // If there were any diagnostics suppressed by template argument deduction, + // emit them now. + llvm::DenseMap >::iterator + Pos = SuppressedDiagnostics.find(D->getCanonicalDecl()); + if (Pos != SuppressedDiagnostics.end()) { + llvm::SmallVectorImpl &Suppressed = Pos->second; + for (unsigned I = 0, N = Suppressed.size(); I != N; ++I) + Diag(Suppressed[I].first, Suppressed[I].second); + + // Clear out the list of suppressed diagnostics, so that we don't emit + // them again for this specialization. However, we don't remove this + // entry from the table, because we want to avoid ever emitting these + // diagnostics again. + Suppressed.clear(); + } + } + // See if the decl is deprecated. if (const DeprecatedAttr *DA = D->getAttr()) EmitDeprecationWarning(D, DA->getMessage(), Loc); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 04c15e3f0019..00a3e27edc94 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1551,9 +1551,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, return ExprError(); if (!RD->hasTrivialDestructor()) - if (const CXXDestructorDecl *Dtor = LookupDestructor(RD)) + if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { MarkDeclarationReferenced(StartLoc, const_cast(Dtor)); + DiagnoseUseOfDecl(Dtor, StartLoc); + } } if (!OperatorDelete) { @@ -1829,7 +1831,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) return true; - + From = FixOverloadedFunctionReference(From, Found, Fn); FromType = From->getType(); } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 7f0f2767c641..1e48930f9723 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3765,6 +3765,7 @@ InitializationSequence::Perform(Sema &S, S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor, S.PDiag(diag::err_access_dtor_temp) << T); S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor); + S.DiagnoseUseOfDecl(Destructor, CurInitExpr->getLocStart()); } } @@ -3858,7 +3859,8 @@ InitializationSequence::Perform(Sema &S, unsigned NumExprs = ConstructorArgs.size(); Expr **Exprs = (Expr **)ConstructorArgs.take(); S.MarkDeclarationReferenced(Loc, Constructor); - + S.DiagnoseUseOfDecl(Constructor, Loc); + TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); if (!TSInfo) TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 1437238f3bf1..078669a556a7 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5489,6 +5489,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, // placement new (5.3.4), as well as non-default initialization (8.5). if (Best->Function) S.MarkDeclarationReferenced(Loc, Best->Function); + return OR_Success; } @@ -6313,7 +6314,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // whose type matches exactly. llvm::SmallVector, 4> Matches; llvm::SmallVector NonMatches; - + bool FoundNonTemplateFunction = false; for (UnresolvedSetIterator I = OvlExpr->decls_begin(), E = OvlExpr->decls_end(); I != E; ++I) { @@ -6344,7 +6345,6 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // resulting template argument list is used to generate a single // function template specialization, which is added to the set of // overloaded functions considered. - // FIXME: We don't really want to build the specialization here, do we? FunctionDecl *Specialization = 0; TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc()); if (TemplateDeductionResult Result @@ -6355,10 +6355,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } else { // Template argument deduction ensures that we have an exact match. // This function template specicalization works. + Specialization = cast(Specialization->getCanonicalDecl()); assert(FunctionType == Context.getCanonicalType(Specialization->getType())); - Matches.push_back(std::make_pair(I.getPair(), - cast(Specialization->getCanonicalDecl()))); + Matches.push_back(std::make_pair(I.getPair(), Specialization)); } continue; @@ -6403,10 +6403,11 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, return 0; } else if (Matches.size() == 1) { FunctionDecl *Result = Matches[0].second; - FoundResult = Matches[0].first; + FoundResult = Matches[0].first; MarkDeclarationReferenced(From->getLocStart(), Result); - if (Complain) + if (Complain) { CheckAddressOfMemberAccess(OvlExpr, Matches[0].first); + } return Result; } @@ -6441,10 +6442,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, MarkDeclarationReferenced(From->getLocStart(), *Result); FoundResult = Matches[Result - MatchesCopy.begin()].first; - if (Complain) { + if (Complain) CheckUnresolvedAccess(*this, OvlExpr, FoundResult); - DiagnoseUseOfDecl(FoundResult, OvlExpr->getNameLoc()); - } return cast(*Result); } @@ -6464,10 +6463,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (Matches.size() == 1) { MarkDeclarationReferenced(From->getLocStart(), Matches[0].second); FoundResult = Matches[0].first; - if (Complain) { + if (Complain) CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); - DiagnoseUseOfDecl(Matches[0].first, OvlExpr->getNameLoc()); - } return cast(Matches[0].second); } @@ -6543,7 +6540,7 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { Matched = Specialization; } - + return Matched; } @@ -6734,7 +6731,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, case OR_Success: { FunctionDecl *FDecl = Best->Function; CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); - DiagnoseUseOfDecl(Best->FoundDecl, ULE->getNameLoc()); + DiagnoseUseOfDecl(FDecl? FDecl : Best->FoundDecl, ULE->getNameLoc()); Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index ec928ea4b7bb..a569a966fa3f 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2363,6 +2363,9 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, // template-argument for a template type-parameter. // C++0x allows these, and even in C++03 we allow them as an extension with // a warning. + // + // FIXME: We're not handling the "type compounded from any of these types" + // case. SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); if (!LangOpts.CPlusPlus0x) { const TagType *Tag = 0; diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index ce3748b901a1..ae9052b704a3 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1127,7 +1127,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, return Result; InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial, - Deduced.data(), Deduced.size()); + Deduced.data(), Deduced.size(), Info); if (Inst) return TDK_InstantiationDepth; @@ -1214,7 +1214,8 @@ Sema::SubstituteExplicitTemplateArguments( // and then substitute them into the function parameter types. InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), FunctionTemplate, Deduced.data(), Deduced.size(), - ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution); + ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution, + Info); if (Inst) return TDK_InstantiationDepth; @@ -1374,7 +1375,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // actual function declaration. InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), FunctionTemplate, Deduced.data(), Deduced.size(), - ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution, + Info); if (Inst) return TDK_InstantiationDepth; @@ -1429,7 +1431,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentLoc Arg = getTrivialTemplateArgumentLoc(*this, Deduced[I], NTTPType, - SourceLocation()); + Info.getLocation()); // Check the template argument, converting it as necessary. if (CheckTemplateArgument(Param, Arg, @@ -1515,6 +1517,18 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, return TDK_SubstitutionFailure; } + // If we suppressed any diagnostics while performing template argument + // deduction, and if we haven't already instantiated this declaration, + // keep track of these diagnostics. They'll be emitted if this specialization + // is actually used. + if (Info.diag_begin() != Info.diag_end()) { + llvm::DenseMap >::iterator + Pos = SuppressedDiagnostics.find(Specialization->getCanonicalDecl()); + if (Pos == SuppressedDiagnostics.end()) + SuppressedDiagnostics[Specialization->getCanonicalDecl()] + .append(Info.diag_begin(), Info.diag_end()); + } + return TDK_Success; } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 98b8ccd8d850..2bc0e40b39a5 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -148,7 +148,6 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity, SourceRange InstantiationRange) : SemaRef(SemaRef) { - Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -192,6 +191,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, ActiveTemplateInstantiation::InstantiationKind Kind, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) : SemaRef(SemaRef) { @@ -204,6 +204,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Inst.Entity = reinterpret_cast(FunctionTemplate); Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; + Inst.DeductionInfo = &DeductionInfo; Inst.InstantiationRange = InstantiationRange; SemaRef.ActiveTemplateInstantiations.push_back(Inst); @@ -217,6 +218,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, ClassTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) : SemaRef(SemaRef) { @@ -228,6 +230,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Inst.Entity = reinterpret_cast(PartialSpec); Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; + Inst.DeductionInfo = &DeductionInfo; Inst.InstantiationRange = InstantiationRange; SemaRef.ActiveTemplateInstantiations.push_back(Inst); @@ -516,7 +519,7 @@ void Sema::PrintInstantiationStack() { } } -bool Sema::isSFINAEContext() const { +TemplateDeductionInfo *Sema::isSFINAEContext() const { using llvm::SmallVector; for (SmallVector::const_reverse_iterator Active = ActiveTemplateInstantiations.rbegin(), @@ -528,7 +531,7 @@ bool Sema::isSFINAEContext() const { case ActiveTemplateInstantiation::TemplateInstantiation: case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: // This is a template instantiation, so there is no SFINAE. - return false; + return 0; case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: @@ -542,11 +545,12 @@ bool Sema::isSFINAEContext() const { case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: // We're either substitution explicitly-specified template arguments // or deduced template arguments, so SFINAE applies. - return true; + assert(Active->DeductionInfo && "Missing deduction info pointer"); + return Active->DeductionInfo; } } - return false; + return 0; } //===----------------------------------------------------------------------===/ @@ -1255,6 +1259,16 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, return Invalid; } +namespace { + /// \brief A partial specialization whose template arguments have matched + /// a given template-id. + struct PartialSpecMatchResult { + ClassTemplatePartialSpecializationDecl *Partial; + TemplateArgumentList *Args; + llvm::SmallVector Diagnostics; + }; +} + bool Sema::InstantiateClassTemplateSpecialization( SourceLocation PointOfInstantiation, @@ -1304,8 +1318,7 @@ Sema::InstantiateClassTemplateSpecialization( // matching the template arguments of the class template // specialization with the template argument lists of the partial // specializations. - typedef std::pair MatchResult; + typedef PartialSpecMatchResult MatchResult; llvm::SmallVector Matched; llvm::SmallVector PartialSpecs; Template->getPartialSpecializations(PartialSpecs); @@ -1320,7 +1333,10 @@ Sema::InstantiateClassTemplateSpecialization( // diagnostics, later. (void)Result; } else { - Matched.push_back(std::make_pair(Partial, Info.take())); + Matched.push_back(PartialSpecMatchResult()); + Matched.back().Partial = Partial; + Matched.back().Args = Info.take(); + Matched.back().Diagnostics.append(Info.diag_begin(), Info.diag_end()); } } @@ -1341,9 +1357,9 @@ Sema::InstantiateClassTemplateSpecialization( for (llvm::SmallVector::iterator P = Best + 1, PEnd = Matched.end(); P != PEnd; ++P) { - if (getMoreSpecializedPartialSpecialization(P->first, Best->first, + if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, PointOfInstantiation) - == P->first) + == P->Partial) Best = P; } @@ -1354,9 +1370,9 @@ Sema::InstantiateClassTemplateSpecialization( PEnd = Matched.end(); P != PEnd; ++P) { if (P != Best && - getMoreSpecializedPartialSpecialization(P->first, Best->first, + getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, PointOfInstantiation) - != Best->first) { + != Best->Partial) { Ambiguous = true; break; } @@ -1372,16 +1388,17 @@ Sema::InstantiateClassTemplateSpecialization( for (llvm::SmallVector::iterator P = Matched.begin(), PEnd = Matched.end(); P != PEnd; ++P) - Diag(P->first->getLocation(), diag::note_partial_spec_match) - << getTemplateArgumentBindingsText(P->first->getTemplateParameters(), - *P->second); + Diag(P->Partial->getLocation(), diag::note_partial_spec_match) + << getTemplateArgumentBindingsText( + P->Partial->getTemplateParameters(), + *P->Args); return true; } } // Instantiate using the best class template partial specialization. - ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->first; + ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->Partial; while (OrigPartialSpec->getInstantiatedFromMember()) { // If we've found an explicit specialization of this class template, // stop here and use that as the pattern. @@ -1392,7 +1409,11 @@ Sema::InstantiateClassTemplateSpecialization( } Pattern = OrigPartialSpec; - ClassTemplateSpec->setInstantiationOf(Best->first, Best->second); + ClassTemplateSpec->setInstantiationOf(Best->Partial, Best->Args); + + // Report any suppressed diagnostics. + for (unsigned I = 0, N = Best->Diagnostics.size(); I != N; ++I) + Diag(Best->Diagnostics[I].first, Best->Diagnostics[I].second); } else { // -- If no matches are found, the instantiation is generated // from the primary template. diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp index 5c44ccb63532..11bfe3e41308 100644 --- a/clang/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp +++ b/clang/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp @@ -11,11 +11,32 @@ template struct B { B b; // expected-note{{instantiation of}} template int f0(void *, const T&); // expected-note{{candidate template ignored: substitution failure}} -enum {e}; +enum {e}; // expected-note{{unnamed type used in template argument was declared here}} void test_f0(int n) { - int i = f0(0, e); // FIXME: We should get a warning here, at least + int i = f0(0, e); // expected-warning{{template argument uses unnamed type}} int vla[n]; f0(0, vla); // expected-error{{no matching function for call to 'f0'}} } +namespace N0 { + template void f0(R (*)(A1)); + template int f1(T); + template int f1(T, U); + enum {e1}; // expected-note 2{{unnamed type used in template argument was declared here}} + enum {e2}; // expected-note 2{{unnamed type used in template argument was declared here}} + enum {e3}; // FIXME: expected unnamed type used in template argument was declared here + + template struct X; + template struct X { }; + + void f() { + f0( // expected-warning{{template argument uses unnamed type}} + &f1<__typeof__(e1)>); // expected-warning{{template argument uses unnamed type}} + int (*fp1)(int, __typeof__(e2)) = f1; // expected-warning{{template argument uses unnamed type}} + f1(e2); // expected-warning{{template argument uses unnamed type}} + f1(e2); + + X<__typeof__(e3)*> x; // FIXME: should warn about unnamed type + } +}