]> granicus.if.org Git - clang/commitdiff
-Wc++98-compat: warn if a SFINAE substitution in C++11 suppresses an access
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 19 Oct 2011 00:07:01 +0000 (00:07 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 19 Oct 2011 00:07:01 +0000 (00:07 +0000)
control diagnostic.

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

include/clang/Basic/Diagnostic.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.cpp
test/SemaCXX/cxx98-compat.cpp

index ae0f6ea0cf1a209f9cdf1cc9407dad8455bd0edd..7dde271c38fc8dd42e4aee78544991ca579870e9 100644 (file)
@@ -740,6 +740,11 @@ public:
     assert(isActive() && "DiagnosticsEngine is inactive");
     return DiagObj->CurDiagID;
   }
+
+  /// \brief Retrieve the active diagnostic's location.
+  ///
+  /// \pre \c isActive()
+  SourceLocation getLocation() const { return DiagObj->CurDiagLoc; }
   
   /// \brief Clear out the current diagnostic.
   void Clear() { DiagObj = 0; }
index 8d8a888e7e45f3ab5fec0839dabc05e30ecdd1d6..5c4ecc8f9d58229c1b8eb38cd39f65adca235342 100644 (file)
@@ -808,6 +808,9 @@ def note_access_constrained_by_path : Note<
   " inheritance here">;
 def note_access_protected_restricted : Note<
   "object type %select{|%1 }0must derive from context type %2">;
+def warn_cxx98_compat_sfinae_access_control : Warning<
+  "substitution failure due to access control is incompatible with C++98">,
+  InGroup<CXX98Compat>, DefaultIgnore, NoSFINAE;
   
 // C++ name lookup
 def err_incomplete_nested_name_spec : Error<
index 4a9d8a5efbfb31d063e79ca8be1ef689be3ddab5..8346cc475ffd91d3cbf808f601c49191432951cf 100644 (file)
@@ -625,10 +625,19 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
   if (llvm::Optional<TemplateDeductionInfo*> Info = SemaRef.isSFINAEContext()) {
     switch (DiagnosticIDs::getDiagnosticSFINAEResponse(getDiagID())) {
     case DiagnosticIDs::SFINAE_Report:
-      // Fall through; we'll report the diagnostic below.
+      // We'll report the diagnostic below.
       break;
       
-    case DiagnosticIDs::SFINAE_AccessControl:
+    case DiagnosticIDs::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 DiagnosticIDs::SFINAE_AccessControl: {
       // Per C++ Core Issue 1170, access control is part of SFINAE.
       // Additionally, the AccessCheckingSFINAE flag can be used to temporary
       // make access control a part of SFINAE for the purposes of checking
@@ -636,16 +645,25 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
       if (!SemaRef.AccessCheckingSFINAE &&
           !SemaRef.getLangOptions().CPlusPlus0x)
         break;
-        
-    case DiagnosticIDs::SFINAE_SubstitutionFailure:
-      // Count this failure so that we know that template argument deduction
-      // has failed.
+
+      SourceLocation Loc = getLocation();
+
+      // Suppress this diagnostic.
       ++SemaRef.NumSFINAEErrors;
       SemaRef.Diags.setLastDiagnosticIgnored();
       SemaRef.Diags.Clear();
       Clear();
+
+      // Now the diagnostic state is clear, produce a C++98 compatibility
+      // warning.
+      SemaRef.Diag(Loc, diag::warn_cxx98_compat_sfinae_access_control);
+
+      // The last diagnostic which Sema produced was ignored. Suppress any
+      // notes attached to it.
+      SemaRef.Diags.setLastDiagnosticIgnored();
       return;
-      
+    }
+
     case DiagnosticIDs::SFINAE_Suppress:
       // Make a copy of this suppressed diagnostic and store it with the
       // template-deduction information;
index 84dc87ac3dc3422b355634d4b0012bdc46141833..8da54f0da65313c42d5f2604e7ec94c95d8704dd 100644 (file)
@@ -170,3 +170,12 @@ struct BadFriends {
 };
 
 int n = {}; // expected-warning {{scalar initialized from empty initializer list is incompatible with C++98}}
+
+class PrivateMember {
+  struct ImPrivate {};
+};
+template<typename T> typename T::ImPrivate SFINAEAccessControl(T t) { // expected-warning {{substitution failure due to access control is incompatible with C++98}} expected-note {{while substituting deduced template arguments into function template 'SFINAEAccessControl' [with T = PrivateMember]}}
+  return typename T::ImPrivate();
+}
+int SFINAEAccessControl(...) { return 0; }
+int CheckSFINAEAccessControl = SFINAEAccessControl(PrivateMember());