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,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(...);

View File

@ -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<SourceLocation, PartialDiagnostic> PartialDiagnosticAt;
} // end namespace clang
#endif

View File

@ -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

View File

@ -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.
///

View File

@ -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);
}

View File

@ -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);

View File

@ -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();
}

View File

@ -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);

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).
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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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.

View File

@ -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 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
}
}