aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/Diagnostic.h16
-rw-r--r--include/clang/Basic/PartialDiagnostic.h53
-rw-r--r--include/clang/Sema/Sema.h27
-rw-r--r--include/clang/Sema/TemplateDeduction.h25
-rw-r--r--lib/Sema/Sema.cpp55
-rw-r--r--lib/Sema/SemaExpr.cpp18
-rw-r--r--lib/Sema/SemaExprCXX.cpp6
-rw-r--r--lib/Sema/SemaInit.cpp4
-rw-r--r--lib/Sema/SemaOverload.cpp25
-rw-r--r--lib/Sema/SemaTemplate.cpp3
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp22
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp55
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.type/p2.cpp25
13 files changed, 265 insertions, 69 deletions
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 0d1caca00a..e2850d9f04 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/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/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index cd0da97e2b..1d96044a71 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/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]);
}
@@ -263,6 +302,13 @@ public:
}
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));
return PD;
@@ -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<SourceLocation, PartialDiagnostic> PartialDiagnosticAt;
} // end namespace clang
#endif
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 7e04978368..dcad3b2c9c 100644
--- a/include/clang/Sema/Sema.h
+++ b/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<CallExpr *, 8> 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<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> >
+ 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/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h
index ac32e9c24f..7cc35713aa 100644
--- a/include/clang/Sema/TemplateDeduction.h
+++ b/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<PartialDiagnosticAt, 4> 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<PartialDiagnosticAt>::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/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index a0046a2caa..1b3572a649 100644
--- a/lib/Sema/Sema.cpp
+++ b/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/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 68bb2b0723..609465c505 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/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<FunctionDecl>(D)) {
+ // If there were any diagnostics suppressed by template argument deduction,
+ // emit them now.
+ llvm::DenseMap<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> >::iterator
+ Pos = SuppressedDiagnostics.find(D->getCanonicalDecl());
+ if (Pos != SuppressedDiagnostics.end()) {
+ llvm::SmallVectorImpl<PartialDiagnosticAt> &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<DeprecatedAttr>())
EmitDeprecationWarning(D, DA->getMessage(), Loc);
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 04c15e3f00..00a3e27edc 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/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<CXXDestructorDecl*>(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/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 7f0f2767c6..1e48930f97 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/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/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 1437238f3b..078669a556 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/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<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
llvm::SmallVector<FunctionDecl *, 4> 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<FunctionDecl>(Specialization->getCanonicalDecl());
assert(FunctionType
== Context.getCanonicalType(Specialization->getType()));
- Matches.push_back(std::make_pair(I.getPair(),
- cast<FunctionDecl>(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<FunctionDecl>(*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<FunctionDecl>(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/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index ec928ea4b7..a569a966fa 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/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/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index ce3748b901..ae9052b704 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/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<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> >::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/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 98b8ccd8d8..2bc0e40b39 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/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<uintptr_t>(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<uintptr_t>(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<ActiveTemplateInstantiation, 16>::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<PartialDiagnosticAt, 1> 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<ClassTemplatePartialSpecializationDecl *,
- TemplateArgumentList *> MatchResult;
+ typedef PartialSpecMatchResult MatchResult;
llvm::SmallVector<MatchResult, 4> Matched;
llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> 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<MatchResult, 4>::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<MatchResult, 4>::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/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp b/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp
index 5c44ccb635..11bfe3e413 100644
--- a/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp
+++ b/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp
@@ -11,11 +11,32 @@ template<typename T> struct B {
B<function> b; // expected-note{{instantiation of}}
template <typename T> 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 <typename R, typename A1> void f0(R (*)(A1));
+ template <typename T> int f1(T);
+ template <typename T, typename U> 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 tem