From 77faa365cb2322cfc8edf58a4f5d68f2370cc39a Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 19 Oct 2011 00:07:01 +0000 Subject: [PATCH] -Wc++98-compat: warn if a SFINAE substitution in C++11 suppresses an access control diagnostic. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142463 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Diagnostic.h | 5 +++ include/clang/Basic/DiagnosticSemaKinds.td | 3 ++ lib/Sema/Sema.cpp | 38 ++++++++++++++++------ test/SemaCXX/cxx98-compat.cpp | 9 +++++ 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index ae0f6ea0cf..7dde271c38 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -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; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8d8a888e7e..5c4ecc8f9d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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, DefaultIgnore, NoSFINAE; // C++ name lookup def err_incomplete_nested_name_spec : Error< diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 4a9d8a5efb..8346cc475f 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -625,18 +625,9 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { if (llvm::Optional 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: - // 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 - // type traits. - if (!SemaRef.AccessCheckingSFINAE && - !SemaRef.getLangOptions().CPlusPlus0x) - break; - case DiagnosticIDs::SFINAE_SubstitutionFailure: // Count this failure so that we know that template argument deduction // has failed. @@ -646,6 +637,33 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { 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 + // type traits. + if (!SemaRef.AccessCheckingSFINAE && + !SemaRef.getLangOptions().CPlusPlus0x) + break; + + 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; diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp index 84dc87ac3d..8da54f0da6 100644 --- a/test/SemaCXX/cxx98-compat.cpp +++ b/test/SemaCXX/cxx98-compat.cpp @@ -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::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());