Teach the diagnostic engine to provide more detailed information about
how to handle a diagnostic during template argument deduction, which
may be "substitution failure", "suppress", or "report". This keeps us
from, e.g., emitting warnings while performing template argument
deduction.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99560 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 13e22a0..bce43c2 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -389,6 +389,28 @@
   /// the diagnostic, this returns null.
   static const char *getWarningOptionForDiag(unsigned DiagID);
 
+  /// \brief Enumeration describing how the the emission of a diagnostic should
+  /// be treated when it occurs during C++ template argument deduction.
+  enum SFINAEResponse {
+    /// \brief The diagnostic should not be reported, but it should cause
+    /// template argument deduction to fail.
+    ///
+    /// The vast majority of errors that occur during template argument 
+    /// deduction fall into this category.
+    SFINAE_SubstitutionFailure,
+    
+    /// \brief The diagnostic should be suppressed entirely.
+    ///
+    /// Warnings generally fall into this category.
+    SFINAE_Suppress,
+    
+    /// \brief The diagnostic should be reported.
+    ///
+    /// The diagnostic should be reported. Various fatal errors (e.g., 
+    /// template instantiation depth exceeded) fall into this category.
+    SFINAE_Report
+  };
+  
   /// \brief Determines whether the given built-in diagnostic ID is
   /// for an error that is suppressed if it occurs during C++ template
   /// argument deduction.
@@ -397,7 +419,7 @@
   /// deduction fails but no diagnostic is emitted. Certain classes of
   /// errors, such as those errors that involve C++ access control,
   /// are not SFINAE errors.
-  static bool isBuiltinSFINAEDiag(unsigned DiagID);
+  static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
 
   /// getDiagnosticLevel - Based on the way the client configured the Diagnostic
   /// object, classify the specified diagnostic ID into a Level, consumable by
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 31d3b34..21a8aea 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -124,10 +124,20 @@
   return 0;
 }
 
-bool Diagnostic::isBuiltinSFINAEDiag(unsigned DiagID) {
-  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
-    return Info->SFINAE && Info->Class == CLASS_ERROR;
-  return false;
+Diagnostic::SFINAEResponse 
+Diagnostic::getDiagnosticSFINAEResponse(unsigned DiagID) {
+  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) {
+    if (!Info->SFINAE)
+      return SFINAE_Report;
+
+    if (Info->Class == CLASS_ERROR)
+      return SFINAE_SubstitutionFailure;
+    
+    // Suppress notes, warnings, and extensions;
+    return SFINAE_Suppress;
+  }
+  
+  return SFINAE_Report;
 }
 
 /// getDiagClass - Return the class field of the diagnostic.
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 7190cf0..ccfbe1e 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -348,6 +348,30 @@
   }
 }
 
+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);
+}
+
 Sema::SemaDiagnosticBuilder
 Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
   SemaDiagnosticBuilder Builder(Diag(Loc, PD.getDiagID()));
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 7e2e614..5986b47 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -610,19 +610,7 @@
   };
 
   /// \brief Emit a diagnostic.
-  SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
-    if (isSFINAEContext() && Diagnostic::isBuiltinSFINAEDiag(DiagID)) {
-      // If we encountered an error during template argument
-      // deduction, and that error is one of the SFINAE errors,
-      // suppress the diagnostic.
-      ++NumSFINAEErrors;
-      Diags.setLastDiagnosticIgnored();
-      return SemaDiagnosticBuilder(*this);
-    }
-
-    DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID);
-    return SemaDiagnosticBuilder(DB, *this, DiagID);
-  }
+  SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
 
   /// \brief Emit a partial diagnostic.
   SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD);