]> granicus.if.org Git - clang/commitdiff
Introduce support for emitting diagnostics (warnings + their notes)
authorDouglas Gregor <dgregor@apple.com>
Tue, 12 Oct 2010 23:32:35 +0000 (23:32 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 12 Oct 2010 23:32:35 +0000 (23:32 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116373 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/Basic/Diagnostic.h
include/clang/Basic/PartialDiagnostic.h
include/clang/Sema/Sema.h
include/clang/Sema/TemplateDeduction.h
lib/Sema/Sema.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaTemplateInstantiate.cpp
test/CXX/temp/temp.arg/temp.arg.type/p2.cpp

index 0d1caca00a9c508843975a49a53a9657f1434d1a..e2850d9f048564d6a7877c95ac558a8ca6db4aa5 100644 (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(...);
index cd0da97e2ba34384eac9d5a942b3eb941246850d..1d96044a7184a45c45e8c36b902ab66a68493f8b 100644 (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
index 7e0497836870d494d813a9c89977e6aaa780394c..dcad3b2c9c7450be27fe81aaf703601a0e394518 100644 (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
index ac32e9c24f6d7db69a6d0c0f13e5445c76d5ac18..7cc35713aace70169bff50b1d8df8d566a816c26 100644 (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.
   ///
index a0046a2caa1e3b43f3e0e9f12d983fa98b70dd26..1b3572a6498b33a96e2384741751250cd7dc303e 100644 (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);
 }
index 68bb2b072339ddd094f924fd1442d23c8e066451..609465c50523d58924cffcab46829758d583a901 100644 (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);
index 04c15e3f0019299c738c8f04780e72b814bae0be..00a3e27edc94e5e9eb165c8024343769ad9b3c16 100644 (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();
   }
index 7f0f2767c64143bc674f95327b86563e615bde93..1e48930f9723e000f46a692fd20c0593edc56450 100644 (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);
index 1437238f3bf12d45e3760420fe863f2a317f01a2..078669a556a743ad95c710153a202eaa7934df3d 100644 (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);
   }
index ec928ea4b7bbe1b2559082943a2fd276dd6cdb10..a569a966fa3f31dea2f555d33631c50ccf86ff54 100644 (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;
index ce3748b901a11957d6059fc570ccf3e4fa6cff8d..ae9052b704a32459d2d7eef86de79c16fd8e9b63 100644 (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;
 }
 
index 98b8ccd8d850d987f92d514bbcb3b5a5f35e36dc..2bc0e40b39a5bdfd9c58fbd5f226efb2e880d2c3 100644 (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.
index 5c44ccb63532099f0c3184af08c37b9ad47ee21d..11bfe3e41308bb6b4a201ca4dda6499a8adb88f6 100644 (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
+  }
+}