Introduce support for emitting diagnostics (warnings + their notes)

that are suppressed during template argument deduction. This change
queues diagnostics computed during template argument deduction. Then,
if the resulting function template specialization or partial
specialization is chosen by overload resolution or partial ordering
(respectively), we will emit the queued diagnostics at that point. 

This addresses most of PR6784. However, the check for unnamed/local
template arguments (which existed before this change) is still only
skin-deep, and needs to be extended to look deeper into types. It must
be improved to finish PR6784.

llvm-svn: 116373
This commit is contained in:
Douglas Gregor 2010-10-12 23:32:35 +00:00
parent 67f70aaf5a
commit 5bb5e4ad9d
13 changed files with 265 additions and 69 deletions

View File

@ -585,6 +585,7 @@ private:
// diagnostic is in flight at a time. // diagnostic is in flight at a time.
friend class DiagnosticBuilder; friend class DiagnosticBuilder;
friend class DiagnosticInfo; friend class DiagnosticInfo;
friend class PartialDiagnostic;
/// CurDiagLoc - This is the location of the current diagnostic that is in /// CurDiagLoc - This is the location of the current diagnostic that is in
/// flight. /// flight.
@ -667,6 +668,8 @@ class DiagnosticBuilder {
explicit DiagnosticBuilder(Diagnostic *diagObj) explicit DiagnosticBuilder(Diagnostic *diagObj)
: DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixItHints(0) {} : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixItHints(0) {}
friend class PartialDiagnostic;
public: public:
/// Copy constructor. When copied, this "takes" the diagnostic info from the /// Copy constructor. When copied, this "takes" the diagnostic info from the
/// input and neuters it. /// input and neuters it.
@ -703,6 +706,17 @@ public:
/// isActive - Determine whether this diagnostic is still active. /// isActive - Determine whether this diagnostic is still active.
bool isActive() const { return DiagObj != 0; } 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 /// Operator bool: conversion of DiagnosticBuilder to bool always returns
/// true. This allows is to be used in boolean error contexts like: /// true. This allows is to be used in boolean error contexts like:
/// return Diag(...); /// return Diag(...);

View File

@ -57,6 +57,10 @@ public:
/// what sort of argument kind it is. /// what sort of argument kind it is.
intptr_t DiagArgumentsVal[MaxArguments]; 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 /// DiagRanges - The list of ranges added to this diagnostic. It currently
/// only support 10 ranges, could easily be extended if needed. /// only support 10 ranges, could easily be extended if needed.
CharSourceRange DiagRanges[10]; CharSourceRange DiagRanges[10];
@ -186,6 +190,26 @@ public:
*this->DiagStorage = *Other.DiagStorage; *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) { PartialDiagnostic &operator=(const PartialDiagnostic &Other) {
DiagID = Other.DiagID; DiagID = Other.DiagID;
if (Other.DiagStorage) { if (Other.DiagStorage) {
@ -216,12 +240,27 @@ public:
DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V; 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 { void Emit(const DiagnosticBuilder &DB) const {
if (!DiagStorage) if (!DiagStorage)
return; return;
// Add all arguments. // Add all arguments.
for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) { for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) {
if ((Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]
== Diagnostic::ak_std_string)
DB.AddString(DiagStorage->DiagArgumentsStr[i]);
else
DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i], DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i],
(Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]); (Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]);
} }
@ -230,7 +269,7 @@ public:
for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i) for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i)
DB.AddSourceRange(DiagStorage->DiagRanges[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) for (unsigned i = 0, e = DiagStorage->NumFixItHints; i != e; ++i)
DB.AddFixItHint(DiagStorage->FixItHints[i]); DB.AddFixItHint(DiagStorage->FixItHints[i]);
} }
@ -262,6 +301,13 @@ public:
return PD; 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, friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
const SourceRange &R) { const SourceRange &R) {
PD.AddSourceRange(CharSourceRange::getTokenRange(R)); PD.AddSourceRange(CharSourceRange::getTokenRange(R));
@ -288,6 +334,9 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
return 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 } // end namespace clang
#endif #endif

View File

@ -3266,6 +3266,10 @@ public:
/// \brief The number of template arguments in TemplateArgs. /// \brief The number of template arguments in TemplateArgs.
unsigned NumTemplateArgs; 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 /// \brief The source range that covers the construct that cause
/// the instantiation, e.g., the template-id that causes a class /// the instantiation, e.g., the template-id that causes a class
/// template instantiation. /// template instantiation.
@ -3273,7 +3277,7 @@ public:
ActiveTemplateInstantiation() ActiveTemplateInstantiation()
: Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0),
NumTemplateArgs(0) {} NumTemplateArgs(0), DeductionInfo(0) {}
/// \brief Determines whether this template is an actual instantiation /// \brief Determines whether this template is an actual instantiation
/// that should be counted toward the maximum instantiation depth. /// that should be counted toward the maximum instantiation depth.
@ -3344,6 +3348,14 @@ public:
/// function calls to fix the AST to match the textual change it prints. /// function calls to fix the AST to match the textual change it prints.
llvm::SmallVector<CallExpr *, 8> CallsUndergoingInstantiation; 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 /// \brief A stack object to be created when performing template
/// instantiation. /// instantiation.
/// ///
@ -3377,6 +3389,7 @@ public:
const TemplateArgument *TemplateArgs, const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs, unsigned NumTemplateArgs,
ActiveTemplateInstantiation::InstantiationKind Kind, ActiveTemplateInstantiation::InstantiationKind Kind,
sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange = SourceRange()); SourceRange InstantiationRange = SourceRange());
/// \brief Note that we are instantiating as part of template /// \brief Note that we are instantiating as part of template
@ -3386,6 +3399,7 @@ public:
ClassTemplatePartialSpecializationDecl *PartialSpec, ClassTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgument *TemplateArgs, const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs, unsigned NumTemplateArgs,
sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange = SourceRange()); SourceRange InstantiationRange = SourceRange());
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@ -3432,7 +3446,6 @@ public:
private: private:
Sema &SemaRef; Sema &SemaRef;
bool Invalid; bool Invalid;
bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, bool CheckInstantiationDepth(SourceLocation PointOfInstantiation,
SourceRange InstantiationRange); SourceRange InstantiationRange);
@ -3448,9 +3461,11 @@ public:
/// template argument substitution failures are not considered /// template argument substitution failures are not considered
/// errors. /// errors.
/// ///
/// When this routine returns true, the emission of most diagnostics /// \returns The nearest template-deduction context object, if we are in a
/// will be suppressed and there will be no local error recovery. /// SFINAE context, which can be used to capture diagnostics that will be
bool isSFINAEContext() const; /// 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 /// \brief RAII class used to determine whether SFINAE has
/// trapped any errors that occur during template argument /// trapped any errors that occur during template argument

View File

@ -13,7 +13,9 @@
#ifndef LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H #ifndef LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H
#define LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H #define LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclTemplate.h"
#include "llvm/ADT/SmallVector.h"
namespace clang { namespace clang {
@ -37,6 +39,10 @@ class TemplateDeductionInfo {
/// deduction is occurring. /// deduction is occurring.
SourceLocation Loc; 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 // do not implement these
TemplateDeductionInfo(const TemplateDeductionInfo&); TemplateDeductionInfo(const TemplateDeductionInfo&);
TemplateDeductionInfo &operator=(const TemplateDeductionInfo&); TemplateDeductionInfo &operator=(const TemplateDeductionInfo&);
@ -69,6 +75,23 @@ public:
Deduced = NewDeduced; 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 /// \brief The template parameter to which a template argument
/// deduction failure refers. /// deduction failure refers.
/// ///

View File

@ -19,6 +19,7 @@
#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/APFloat.h" #include "llvm/ADT/APFloat.h"
#include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/CXXFieldCollector.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/ObjCMethodList.h"
#include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/PrettyDeclStackTrace.h"
@ -433,6 +434,41 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() {
} }
Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { 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()) if (!this->Emit())
return; return;
@ -451,25 +487,6 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
} }
Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID) { 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); DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID);
return SemaDiagnosticBuilder(DB, *this, DiagID); return SemaDiagnosticBuilder(DB, *this, DiagID);
} }

View File

@ -56,6 +56,24 @@ using namespace sema;
/// referenced), false otherwise. /// referenced), false otherwise.
/// ///
bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { 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. // See if the decl is deprecated.
if (const DeprecatedAttr *DA = D->getAttr<DeprecatedAttr>()) if (const DeprecatedAttr *DA = D->getAttr<DeprecatedAttr>())
EmitDeprecationWarning(D, DA->getMessage(), Loc); EmitDeprecationWarning(D, DA->getMessage(), Loc);

View File

@ -1551,9 +1551,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
return ExprError(); return ExprError();
if (!RD->hasTrivialDestructor()) if (!RD->hasTrivialDestructor())
if (const CXXDestructorDecl *Dtor = LookupDestructor(RD)) if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) {
MarkDeclarationReferenced(StartLoc, MarkDeclarationReferenced(StartLoc,
const_cast<CXXDestructorDecl*>(Dtor)); const_cast<CXXDestructorDecl*>(Dtor));
DiagnoseUseOfDecl(Dtor, StartLoc);
}
} }
if (!OperatorDelete) { if (!OperatorDelete) {

View File

@ -3765,6 +3765,7 @@ InitializationSequence::Perform(Sema &S,
S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor, S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor,
S.PDiag(diag::err_access_dtor_temp) << T); S.PDiag(diag::err_access_dtor_temp) << T);
S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor); S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor);
S.DiagnoseUseOfDecl(Destructor, CurInitExpr->getLocStart());
} }
} }
@ -3858,6 +3859,7 @@ InitializationSequence::Perform(Sema &S,
unsigned NumExprs = ConstructorArgs.size(); unsigned NumExprs = ConstructorArgs.size();
Expr **Exprs = (Expr **)ConstructorArgs.take(); Expr **Exprs = (Expr **)ConstructorArgs.take();
S.MarkDeclarationReferenced(Loc, Constructor); S.MarkDeclarationReferenced(Loc, Constructor);
S.DiagnoseUseOfDecl(Constructor, Loc);
TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
if (!TSInfo) if (!TSInfo)

View File

@ -5489,6 +5489,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
// placement new (5.3.4), as well as non-default initialization (8.5). // placement new (5.3.4), as well as non-default initialization (8.5).
if (Best->Function) if (Best->Function)
S.MarkDeclarationReferenced(Loc, Best->Function); S.MarkDeclarationReferenced(Loc, Best->Function);
return OR_Success; return OR_Success;
} }
@ -6344,7 +6345,6 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// resulting template argument list is used to generate a single // resulting template argument list is used to generate a single
// function template specialization, which is added to the set of // function template specialization, which is added to the set of
// overloaded functions considered. // overloaded functions considered.
// FIXME: We don't really want to build the specialization here, do we?
FunctionDecl *Specialization = 0; FunctionDecl *Specialization = 0;
TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc()); TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc());
if (TemplateDeductionResult Result if (TemplateDeductionResult Result
@ -6355,10 +6355,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
} else { } else {
// Template argument deduction ensures that we have an exact match. // Template argument deduction ensures that we have an exact match.
// This function template specicalization works. // This function template specicalization works.
Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl());
assert(FunctionType assert(FunctionType
== Context.getCanonicalType(Specialization->getType())); == Context.getCanonicalType(Specialization->getType()));
Matches.push_back(std::make_pair(I.getPair(), Matches.push_back(std::make_pair(I.getPair(), Specialization));
cast<FunctionDecl>(Specialization->getCanonicalDecl())));
} }
continue; continue;
@ -6405,8 +6405,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
FunctionDecl *Result = Matches[0].second; FunctionDecl *Result = Matches[0].second;
FoundResult = Matches[0].first; FoundResult = Matches[0].first;
MarkDeclarationReferenced(From->getLocStart(), Result); MarkDeclarationReferenced(From->getLocStart(), Result);
if (Complain) if (Complain) {
CheckAddressOfMemberAccess(OvlExpr, Matches[0].first); CheckAddressOfMemberAccess(OvlExpr, Matches[0].first);
}
return Result; return Result;
} }
@ -6441,10 +6442,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
MarkDeclarationReferenced(From->getLocStart(), *Result); MarkDeclarationReferenced(From->getLocStart(), *Result);
FoundResult = Matches[Result - MatchesCopy.begin()].first; FoundResult = Matches[Result - MatchesCopy.begin()].first;
if (Complain) { if (Complain)
CheckUnresolvedAccess(*this, OvlExpr, FoundResult); CheckUnresolvedAccess(*this, OvlExpr, FoundResult);
DiagnoseUseOfDecl(FoundResult, OvlExpr->getNameLoc());
}
return cast<FunctionDecl>(*Result); return cast<FunctionDecl>(*Result);
} }
@ -6464,10 +6463,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
if (Matches.size() == 1) { if (Matches.size() == 1) {
MarkDeclarationReferenced(From->getLocStart(), Matches[0].second); MarkDeclarationReferenced(From->getLocStart(), Matches[0].second);
FoundResult = Matches[0].first; FoundResult = Matches[0].first;
if (Complain) { if (Complain)
CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first);
DiagnoseUseOfDecl(Matches[0].first, OvlExpr->getNameLoc());
}
return cast<FunctionDecl>(Matches[0].second); return cast<FunctionDecl>(Matches[0].second);
} }
@ -6734,7 +6731,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
case OR_Success: { case OR_Success: {
FunctionDecl *FDecl = Best->Function; FunctionDecl *FDecl = Best->Function;
CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); CheckUnresolvedLookupAccess(ULE, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, ULE->getNameLoc()); DiagnoseUseOfDecl(FDecl? FDecl : Best->FoundDecl, ULE->getNameLoc());
Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc);
} }

View File

@ -2363,6 +2363,9 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
// template-argument for a template type-parameter. // template-argument for a template type-parameter.
// C++0x allows these, and even in C++03 we allow them as an extension with // C++0x allows these, and even in C++03 we allow them as an extension with
// a warning. // a warning.
//
// FIXME: We're not handling the "type compounded from any of these types"
// case.
SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
if (!LangOpts.CPlusPlus0x) { if (!LangOpts.CPlusPlus0x) {
const TagType *Tag = 0; const TagType *Tag = 0;

View File

@ -1127,7 +1127,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
return Result; return Result;
InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial, InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
Deduced.data(), Deduced.size()); Deduced.data(), Deduced.size(), Info);
if (Inst) if (Inst)
return TDK_InstantiationDepth; return TDK_InstantiationDepth;
@ -1214,7 +1214,8 @@ Sema::SubstituteExplicitTemplateArguments(
// and then substitute them into the function parameter types. // and then substitute them into the function parameter types.
InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
FunctionTemplate, Deduced.data(), Deduced.size(), FunctionTemplate, Deduced.data(), Deduced.size(),
ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution); ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution,
Info);
if (Inst) if (Inst)
return TDK_InstantiationDepth; return TDK_InstantiationDepth;
@ -1374,7 +1375,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// actual function declaration. // actual function declaration.
InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
FunctionTemplate, Deduced.data(), Deduced.size(), FunctionTemplate, Deduced.data(), Deduced.size(),
ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
Info);
if (Inst) if (Inst)
return TDK_InstantiationDepth; return TDK_InstantiationDepth;
@ -1429,7 +1431,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentLoc Arg = getTrivialTemplateArgumentLoc(*this, TemplateArgumentLoc Arg = getTrivialTemplateArgumentLoc(*this,
Deduced[I], Deduced[I],
NTTPType, NTTPType,
SourceLocation()); Info.getLocation());
// Check the template argument, converting it as necessary. // Check the template argument, converting it as necessary.
if (CheckTemplateArgument(Param, Arg, if (CheckTemplateArgument(Param, Arg,
@ -1515,6 +1517,18 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
return TDK_SubstitutionFailure; 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; return TDK_Success;
} }

View File

@ -148,7 +148,6 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Decl *Entity, Decl *Entity,
SourceRange InstantiationRange) SourceRange InstantiationRange)
: SemaRef(SemaRef) { : SemaRef(SemaRef) {
Invalid = CheckInstantiationDepth(PointOfInstantiation, Invalid = CheckInstantiationDepth(PointOfInstantiation,
InstantiationRange); InstantiationRange);
if (!Invalid) { if (!Invalid) {
@ -192,6 +191,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
const TemplateArgument *TemplateArgs, const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs, unsigned NumTemplateArgs,
ActiveTemplateInstantiation::InstantiationKind Kind, ActiveTemplateInstantiation::InstantiationKind Kind,
sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange) SourceRange InstantiationRange)
: SemaRef(SemaRef) { : SemaRef(SemaRef) {
@ -204,6 +204,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
Inst.Entity = reinterpret_cast<uintptr_t>(FunctionTemplate); Inst.Entity = reinterpret_cast<uintptr_t>(FunctionTemplate);
Inst.TemplateArgs = TemplateArgs; Inst.TemplateArgs = TemplateArgs;
Inst.NumTemplateArgs = NumTemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs;
Inst.DeductionInfo = &DeductionInfo;
Inst.InstantiationRange = InstantiationRange; Inst.InstantiationRange = InstantiationRange;
SemaRef.ActiveTemplateInstantiations.push_back(Inst); SemaRef.ActiveTemplateInstantiations.push_back(Inst);
@ -217,6 +218,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
ClassTemplatePartialSpecializationDecl *PartialSpec, ClassTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgument *TemplateArgs, const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs, unsigned NumTemplateArgs,
sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange) SourceRange InstantiationRange)
: SemaRef(SemaRef) { : SemaRef(SemaRef) {
@ -228,6 +230,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec); Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
Inst.TemplateArgs = TemplateArgs; Inst.TemplateArgs = TemplateArgs;
Inst.NumTemplateArgs = NumTemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs;
Inst.DeductionInfo = &DeductionInfo;
Inst.InstantiationRange = InstantiationRange; Inst.InstantiationRange = InstantiationRange;
SemaRef.ActiveTemplateInstantiations.push_back(Inst); SemaRef.ActiveTemplateInstantiations.push_back(Inst);
@ -516,7 +519,7 @@ void Sema::PrintInstantiationStack() {
} }
} }
bool Sema::isSFINAEContext() const { TemplateDeductionInfo *Sema::isSFINAEContext() const {
using llvm::SmallVector; using llvm::SmallVector;
for (SmallVector<ActiveTemplateInstantiation, 16>::const_reverse_iterator for (SmallVector<ActiveTemplateInstantiation, 16>::const_reverse_iterator
Active = ActiveTemplateInstantiations.rbegin(), Active = ActiveTemplateInstantiations.rbegin(),
@ -528,7 +531,7 @@ bool Sema::isSFINAEContext() const {
case ActiveTemplateInstantiation::TemplateInstantiation: case ActiveTemplateInstantiation::TemplateInstantiation:
case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
// This is a template instantiation, so there is no SFINAE. // This is a template instantiation, so there is no SFINAE.
return false; return 0;
case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution:
@ -542,11 +545,12 @@ bool Sema::isSFINAEContext() const {
case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution:
// We're either substitution explicitly-specified template arguments // We're either substitution explicitly-specified template arguments
// or deduced template arguments, so SFINAE applies. // 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; 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 bool
Sema::InstantiateClassTemplateSpecialization( Sema::InstantiateClassTemplateSpecialization(
SourceLocation PointOfInstantiation, SourceLocation PointOfInstantiation,
@ -1304,8 +1318,7 @@ Sema::InstantiateClassTemplateSpecialization(
// matching the template arguments of the class template // matching the template arguments of the class template
// specialization with the template argument lists of the partial // specialization with the template argument lists of the partial
// specializations. // specializations.
typedef std::pair<ClassTemplatePartialSpecializationDecl *, typedef PartialSpecMatchResult MatchResult;
TemplateArgumentList *> MatchResult;
llvm::SmallVector<MatchResult, 4> Matched; llvm::SmallVector<MatchResult, 4> Matched;
llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
Template->getPartialSpecializations(PartialSpecs); Template->getPartialSpecializations(PartialSpecs);
@ -1320,7 +1333,10 @@ Sema::InstantiateClassTemplateSpecialization(
// diagnostics, later. // diagnostics, later.
(void)Result; (void)Result;
} else { } 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, for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
PEnd = Matched.end(); PEnd = Matched.end();
P != PEnd; ++P) { P != PEnd; ++P) {
if (getMoreSpecializedPartialSpecialization(P->first, Best->first, if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
PointOfInstantiation) PointOfInstantiation)
== P->first) == P->Partial)
Best = P; Best = P;
} }
@ -1354,9 +1370,9 @@ Sema::InstantiateClassTemplateSpecialization(
PEnd = Matched.end(); PEnd = Matched.end();
P != PEnd; ++P) { P != PEnd; ++P) {
if (P != Best && if (P != Best &&
getMoreSpecializedPartialSpecialization(P->first, Best->first, getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
PointOfInstantiation) PointOfInstantiation)
!= Best->first) { != Best->Partial) {
Ambiguous = true; Ambiguous = true;
break; break;
} }
@ -1372,16 +1388,17 @@ Sema::InstantiateClassTemplateSpecialization(
for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
PEnd = Matched.end(); PEnd = Matched.end();
P != PEnd; ++P) P != PEnd; ++P)
Diag(P->first->getLocation(), diag::note_partial_spec_match) Diag(P->Partial->getLocation(), diag::note_partial_spec_match)
<< getTemplateArgumentBindingsText(P->first->getTemplateParameters(), << getTemplateArgumentBindingsText(
*P->second); P->Partial->getTemplateParameters(),
*P->Args);
return true; return true;
} }
} }
// Instantiate using the best class template partial specialization. // Instantiate using the best class template partial specialization.
ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->first; ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->Partial;
while (OrigPartialSpec->getInstantiatedFromMember()) { while (OrigPartialSpec->getInstantiatedFromMember()) {
// If we've found an explicit specialization of this class template, // If we've found an explicit specialization of this class template,
// stop here and use that as the pattern. // stop here and use that as the pattern.
@ -1392,7 +1409,11 @@ Sema::InstantiateClassTemplateSpecialization(
} }
Pattern = OrigPartialSpec; 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 { } else {
// -- If no matches are found, the instantiation is generated // -- If no matches are found, the instantiation is generated
// from the primary template. // from the primary template.

View File

@ -11,11 +11,32 @@ template<typename T> struct B {
B<function> b; // expected-note{{instantiation of}} B<function> b; // expected-note{{instantiation of}}
template <typename T> int f0(void *, const T&); // expected-note{{candidate template ignored: substitution failure}} 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) { 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]; int vla[n];
f0(0, vla); // expected-error{{no matching function for call to 'f0'}} 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 template argument was declared here}}
enum {e3}; // FIXME: expected unnamed type used in template argument was declared here
template<typename T> struct X;
template<typename T> struct X<T*> { };
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
}
}