// 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;
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.
/// 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(...);
/// 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];
*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) {
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]);
}
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]);
}
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));
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
/// \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.
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.
/// 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.
///
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
ActiveTemplateInstantiation::InstantiationKind Kind,
+ sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange = SourceRange());
/// \brief Note that we are instantiating as part of template
ClassTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
+ sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange = SourceRange());
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
private:
Sema &SemaRef;
bool Invalid;
-
bool CheckInstantiationDepth(SourceLocation PointOfInstantiation,
SourceRange InstantiationRange);
/// 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
#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 {
class TemplateArgumentList;
namespace sema {
-
+
/// \brief Provides information about an attempted template argument
/// deduction, whose success or failure was described by a
/// TemplateDeductionResult value.
/// 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&);
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.
///
#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"
}
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;
}
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);
}
/// 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);
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) {
if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
return true;
-
+
From = FixOverloadedFunctionReference(From, Found, Fn);
FromType = From->getType();
}
S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor,
S.PDiag(diag::err_access_dtor_temp) << T);
S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor);
+ S.DiagnoseUseOfDecl(Destructor, CurInitExpr->getLocStart());
}
}
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);
// placement new (5.3.4), as well as non-default initialization (8.5).
if (Best->Function)
S.MarkDeclarationReferenced(Loc, Best->Function);
+
return OR_Success;
}
// 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) {
// 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
} 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;
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;
}
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);
}
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);
}
Matched = Specialization;
}
-
+
return Matched;
}
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);
}
// 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;
return Result;
InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
- Deduced.data(), Deduced.size());
+ Deduced.data(), Deduced.size(), Info);
if (Inst)
return TDK_InstantiationDepth;
// 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;
// actual function declaration.
InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
FunctionTemplate, Deduced.data(), Deduced.size(),
- ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution);
+ ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
+ Info);
if (Inst)
return TDK_InstantiationDepth;
TemplateArgumentLoc Arg = getTrivialTemplateArgumentLoc(*this,
Deduced[I],
NTTPType,
- SourceLocation());
+ Info.getLocation());
// Check the template argument, converting it as necessary.
if (CheckTemplateArgument(Param, Arg,
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;
}
Decl *Entity,
SourceRange InstantiationRange)
: SemaRef(SemaRef) {
-
Invalid = CheckInstantiationDepth(PointOfInstantiation,
InstantiationRange);
if (!Invalid) {
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
ActiveTemplateInstantiation::InstantiationKind Kind,
+ sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange)
: SemaRef(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);
ClassTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
+ sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange)
: SemaRef(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);
}
}
-bool Sema::isSFINAEContext() const {
+TemplateDeductionInfo *Sema::isSFINAEContext() const {
using llvm::SmallVector;
for (SmallVector<ActiveTemplateInstantiation, 16>::const_reverse_iterator
Active = ActiveTemplateInstantiations.rbegin(),
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:
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;
}
//===----------------------------------------------------------------------===/
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,
// 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);
// 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());
}
}
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;
}
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;
}
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.
}
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.
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
+ }
+}