CarlosAlbertoEnciso updated this revision to Diff 149261.
CarlosAlbertoEnciso added a comment.

This patch addresses the reviewers comments:

- Additional test cases to cover: -Wunused, -Wall and -Wno-unused-using
- Formatting in ReleaseNotes
- Removed the '-Wunused-usings' alias (GCC compatibility).
- Added individual warning messages for using-declaration, using-directive and 
namespace-alias.
- Fixed SVN attribute changes.


https://reviews.llvm.org/D44826

Files:
  docs/ReleaseNotes.rst
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/ExternalSemaSource.h
  include/clang/Sema/MultiplexExternalSemaSource.h
  include/clang/Sema/Sema.h
  include/clang/Sema/SemaInternal.h
  include/clang/Serialization/ASTBitCodes.h
  include/clang/Serialization/ASTReader.h
  lib/Sema/MultiplexExternalSemaSource.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Serialization/ASTReader.cpp
  lib/Serialization/ASTWriter.cpp
  test/FixIt/fixit.cpp
  test/Modules/Inputs/module.map
  test/Modules/Inputs/warn-unused-using.h
  test/Modules/warn-unused-using.cpp
  test/PCH/cxx-templates.cpp
  test/SemaCXX/coreturn.cpp
  test/SemaCXX/referenced_alias_declaration_1.cpp
  test/SemaCXX/referenced_alias_declaration_2.cpp
  test/SemaCXX/referenced_using_all.cpp
  test/SemaCXX/referenced_using_declaration_1.cpp
  test/SemaCXX/referenced_using_declaration_2.cpp
  test/SemaCXX/referenced_using_directive.cpp
  test/SemaCXX/referenced_using_options.cpp

Index: test/SemaCXX/referenced_using_options.cpp
===================================================================
--- test/SemaCXX/referenced_using_options.cpp
+++ test/SemaCXX/referenced_using_options.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wall -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wunused -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wunused-using -verify %s
+
+namespace N {
+  typedef int Integer;
+}
+
+using N::Integer;   // expected-warning {{unused using declaration 'Integer'}}
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-using"
+using N::Integer;   // no warning
+#pragma clang diagnostic pop
+
+using N::Integer;   // expected-warning {{unused using declaration 'Integer'}}
+
Index: test/SemaCXX/referenced_using_directive.cpp
===================================================================
--- test/SemaCXX/referenced_using_directive.cpp
+++ test/SemaCXX/referenced_using_directive.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wunused-using -verify %s
+
+namespace N {
+  typedef int Integer;
+  int var;
+}
+
+void Fa() {
+  using namespace N;  // Referenced
+  var = 1;
+}
+
+void Fb() {
+  using namespace N;  // expected-warning {{unused using directive 'N'}}
+  N::var = 1;
+}
+
+void Fc() {
+  using namespace N;  // Referenced
+  Integer var = 1;
+}
+
+void Fd() {
+  using namespace N;  // expected-warning {{unused using directive 'N'}}
+  N::Integer var = 1;
+}
+
Index: test/SemaCXX/referenced_using_declaration_2.cpp
===================================================================
--- test/SemaCXX/referenced_using_declaration_2.cpp
+++ test/SemaCXX/referenced_using_declaration_2.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wunused-using -verify %s
+
+namespace N {
+  typedef int Integer;
+  typedef char Char;
+}
+
+using N::Integer;   // expected-warning {{unused using declaration 'Integer'}}
+using N::Char;      // Referenced
+
+void Foo(int p1, N::Integer p2, Char p3) {
+  N::Integer var;
+  var = 0;
+}
+
+using N::Integer;   // Referenced
+Integer Bar() {
+  using N::Char;    // expected-warning {{unused using declaration 'Char'}}
+  return 0;
+}
+
Index: test/SemaCXX/referenced_using_declaration_1.cpp
===================================================================
--- test/SemaCXX/referenced_using_declaration_1.cpp
+++ test/SemaCXX/referenced_using_declaration_1.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wunused-using -verify %s
+
+namespace N {
+  // Types.
+  typedef int Integer;
+  struct Record {
+    int a;
+  };
+
+  // Variables.
+  int var1;
+  int var2;
+
+  // Functions.
+  void func1();
+  void func2();
+}
+
+using N::Integer;   // expected-warning {{unused using declaration 'Integer'}}
+using N::Record;    // expected-warning {{unused using declaration 'Record'}}
+using N::var1;      // expected-warning {{unused using declaration 'var1'}}
+using N::var2;      // expected-warning {{unused using declaration 'var2'}}
+using N::func1;     // expected-warning {{unused using declaration 'func1'}}
+using N::func2;     // expected-warning {{unused using declaration 'func2'}}
+
+void Foo() {
+  using N::Integer; // expected-warning {{unused using declaration 'Integer'}}
+  N::Integer int_var;
+  int_var = 1;
+
+  using N::Record;  // Referenced
+  Record rec_var;
+  rec_var.a = 2;
+
+  using N::var1;    // expected-warning {{unused using declaration 'var1'}}
+  N::var1 = 3;
+
+  using N::var2;    // Referenced
+  var2 = 4;
+
+  using N::func1;   // expected-warning {{unused using declaration 'func1'}}
+  N::func1();
+
+  using N::func2;   // Referenced
+  func2();
+}
+
Index: test/SemaCXX/referenced_using_all.cpp
===================================================================
--- test/SemaCXX/referenced_using_all.cpp
+++ test/SemaCXX/referenced_using_all.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wunused-using -verify %s
+
+namespace A {
+  typedef char Char;
+  typedef int Integer;
+  typedef float Float;
+  int var;
+}
+
+using A::Char;                  // expected-warning {{unused using declaration 'Char'}}
+using A::Integer;               // Referenced
+using A::Float;                 // expected-warning {{unused using declaration 'Float'}}
+
+namespace B {
+  using A::Char;                // Referenced
+  template <class T>
+  T FuncTempl(T p1,Char p2) {
+    using A::Float;             // Referenced
+    typedef Float Type;
+    Integer I;
+    return p1;
+  }
+}
+
+using A::Char;                  // Referenced
+using A::Integer;               // expected-warning {{unused using declaration 'Integer'}}
+namespace ND1 = A;
+void foo() {
+  using A::Integer;             // Referenced
+  namespace ND2 = ND1;          // Referenced
+  {
+    Integer Ivar;
+    namespace ND3 = ND2;        // Referenced
+    {
+      namespace ND4 = ND3;      // Referenced
+      Char Cvar;
+      {
+        using ND4::var;         // Referenced
+        var = 1;
+      }
+    }
+  }
+  using A::Char;                // Referenced
+  using namespace::B;           // Referenced
+  FuncTempl<Char>(1,'a');
+}
+
Index: test/SemaCXX/referenced_alias_declaration_2.cpp
===================================================================
--- test/SemaCXX/referenced_alias_declaration_2.cpp
+++ test/SemaCXX/referenced_alias_declaration_2.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wunused-using -verify %s
+
+namespace A {
+  namespace B {
+    namespace C {
+      typedef int Integer;
+    }
+  }
+}
+
+void foo() {
+  {
+    namespace N_A = A;                // Referenced
+    {
+      namespace N_AB = N_A::B;        // Referenced
+      {
+        namespace N_ABC = N_AB::C;    // Referenced
+        {
+          using N_ABC::Integer;       // Referenced
+          Integer var;
+        }
+      }
+    }
+  }
+  {
+    namespace N_A = A;                // expected-warning {{unused namespace alias 'N_A'}}
+    {
+      namespace N_AB = N_A::B;        // expected-warning {{unused namespace alias 'N_AB'}}
+      {
+        namespace N_ABC = N_AB::C;    // expected-warning {{unused namespace alias 'N_ABC'}}
+        {
+          A::B::C::Integer var;
+        }
+      }
+    }
+  }
+}
+
Index: test/SemaCXX/referenced_alias_declaration_1.cpp
===================================================================
--- test/SemaCXX/referenced_alias_declaration_1.cpp
+++ test/SemaCXX/referenced_alias_declaration_1.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wunused-using -verify %s
+
+namespace N {
+  int var;
+}
+
+void Fa() {
+  namespace NN = N;     // Referenced
+  using namespace NN;   // Referenced
+  var = 1;
+}
+
+void Fb() {
+  namespace NA = N;     // Referenced
+  namespace NB = NA;    // Referenced
+  namespace NC = NB;    // Referenced
+  using namespace NC;   // Referenced
+  var = 2;
+  namespace ND = NC;    // expected-warning {{unused namespace alias 'ND'}}
+}
+
+void Fc() {
+  namespace NA = N;     // expected-warning {{unused namespace alias 'NA'}}
+  using namespace NA;   // expected-warning {{unused using directive 'NA'}}
+  N::var = 3;
+}
+
+void Fd() {
+  namespace NA = N;     // Referenced
+  namespace NB = NA;    // Referenced
+  NB::var = 4;
+}
+
Index: test/SemaCXX/coreturn.cpp
===================================================================
--- test/SemaCXX/coreturn.cpp
+++ test/SemaCXX/coreturn.cpp
@@ -2,7 +2,7 @@
 #include "Inputs/std-coroutine.h"
 
 using std::experimental::suspend_always;
-using std::experimental::suspend_never;
+using std::experimental::suspend_never; // expected-warning {{unused using declaration 'suspend_never'}}
 
 struct awaitable {
   bool await_ready();
Index: test/PCH/cxx-templates.cpp
===================================================================
--- test/PCH/cxx-templates.cpp
+++ test/PCH/cxx-templates.cpp
@@ -5,12 +5,12 @@
 // Test with pch.
 // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
 // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t -verify %s -ast-dump  -o -
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s
 
 // Test with modules.
 // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -x c++-header -emit-pch -o %t %S/cxx-templates.h
 // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t -verify %s -ast-dump  -o -
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS -fmodules-ignore-macro=NO_ERRORS | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -DNO_ERRORS -fmodules-ignore-macro=NO_ERRORS | FileCheck %s
 
 // Test with pch and delayed template parsing.
 // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
Index: test/Modules/warn-unused-using.cpp
===================================================================
--- test/Modules/warn-unused-using.cpp
+++ test/Modules/warn-unused-using.cpp
@@ -0,0 +1,11 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -Wunused-using -x objective-c++ -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -fsyntax-only 2>&1 | FileCheck %s -check-prefix=CHECK_1
+// RUN: %clang_cc1 -Wunused-using -x objective-c++ -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -fsyntax-only 2>&1 | FileCheck %s -check-prefix=CHECK_2 --allow-empty
+
+// For modules, the warning should only fire the first time, when the module is
+// built.
+// CHECK_1: warning: unused using declaration 'CHAR'
+// CHECK_1: warning: unused using declaration 'INT'
+// CHECK_2-NOT: warning: unused using declaration 'CHAR'
+// CHECK_2-NOT: warning: unused using declaration 'INT'
+@import warn_unused_using;
Index: test/Modules/Inputs/warn-unused-using.h
===================================================================
--- test/Modules/Inputs/warn-unused-using.h
+++ test/Modules/Inputs/warn-unused-using.h
@@ -0,0 +1,10 @@
+namespace A {
+  typedef char CHAR;
+}
+namespace B {
+  typedef int INT;
+  using A::CHAR;
+}
+inline void foo() {
+  using B::INT;
+}
Index: test/Modules/Inputs/module.map
===================================================================
--- test/Modules/Inputs/module.map
+++ test/Modules/Inputs/module.map
@@ -307,6 +307,10 @@
   header "warn-unused-local-typedef.h"
 }
 
+module warn_unused_using {
+  header "warn-unused-using.h"
+}
+
 module using_decl {
   module a { header "using-decl-a.h" export * }
   module b { header "using-decl-b.h" export * }
Index: test/FixIt/fixit.cpp
===================================================================
--- test/FixIt/fixit.cpp
+++ test/FixIt/fixit.cpp
@@ -1,12 +1,12 @@
-// RUN: %clang_cc1 -pedantic -Wall -Wno-comment -verify -fcxx-exceptions -x c++ -std=c++98 %s
+// RUN: %clang_cc1 -pedantic -Wall -Wno-unused-using -Wno-comment -verify -fcxx-exceptions -x c++ -std=c++98 %s
 // RUN: cp %s %t-98
-// RUN: not %clang_cc1 -pedantic -Wall -Wno-comment -fcxx-exceptions -fixit -x c++ -std=c++98 %t-98
-// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -Wno-comment -fcxx-exceptions -x c++ -std=c++98 %t-98
+// RUN: not %clang_cc1 -pedantic -Wall -Wno-unused-using -Wno-comment -fcxx-exceptions -fixit -x c++ -std=c++98 %t-98
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -Wno-unused-using -Wno-comment -fcxx-exceptions -x c++ -std=c++98 %t-98
 // RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ -std=c++11 %s 2>&1 | FileCheck %s
-// RUN: %clang_cc1 -pedantic -Wall -Wno-comment -verify -fcxx-exceptions -x c++ -std=c++11 %s
+// RUN: %clang_cc1 -pedantic -Wall -Wno-unused-using -Wno-comment -verify -fcxx-exceptions -x c++ -std=c++11 %s
 // RUN: cp %s %t-11
-// RUN: not %clang_cc1 -pedantic -Wall -Wno-comment -fcxx-exceptions -fixit -x c++ -std=c++11 %t-11
-// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -Wno-comment -fcxx-exceptions -x c++ -std=c++11 %t-11
+// RUN: not %clang_cc1 -pedantic -Wall -Wno-unused-using -Wno-comment -fcxx-exceptions -fixit -x c++ -std=c++11 %t-11
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -Wno-unused-using -Wno-comment -fcxx-exceptions -x c++ -std=c++11 %t-11
 
 /* This is a test of the various code modification hints that are
    provided as part of warning or extension diagnostics. All of the
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -1137,7 +1137,7 @@
   RECORD(OPTIMIZE_PRAGMA_OPTIONS);
   RECORD(MSSTRUCT_PRAGMA_OPTIONS);
   RECORD(POINTERS_TO_MEMBERS_PRAGMA_OPTIONS);
-  RECORD(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES);
+  RECORD(UNUSED_NAMED_DECL_CANDIDATES);
   RECORD(DELETE_EXPRS_TO_ANALYZE);
   RECORD(CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH);
   RECORD(PP_CONDITIONAL_STACK);
@@ -4714,10 +4714,10 @@
     }
   }
 
-  // Build a record containing all of the UnusedLocalTypedefNameCandidates.
-  RecordData UnusedLocalTypedefNameCandidates;
-  for (const TypedefNameDecl *TD : SemaRef.UnusedLocalTypedefNameCandidates)
-    AddDeclRef(TD, UnusedLocalTypedefNameCandidates);
+  // Build a record containing all of the UnusedNameCandidates.
+  RecordData UnusedNamedDeclCandidates;
+  for (const NamedDecl *ND : SemaRef.UnusedNamedDeclCandidates)
+    AddDeclRef(ND, UnusedNamedDeclCandidates);
 
   // Build a record containing all of pending implicit instantiations.
   RecordData PendingInstantiations;
@@ -5035,9 +5035,9 @@
     Stream.EmitRecord(VTABLE_USES, VTableUses);
 
   // Write the record containing potentially unused local typedefs.
-  if (!UnusedLocalTypedefNameCandidates.empty())
-    Stream.EmitRecord(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES,
-                      UnusedLocalTypedefNameCandidates);
+  if (!UnusedNamedDeclCandidates.empty())
+    Stream.EmitRecord(UNUSED_NAMED_DECL_CANDIDATES,
+                      UnusedNamedDeclCandidates);
 
   // Write the record containing pending implicit instantiations.
   if (!PendingInstantiations.empty())
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -3442,10 +3442,9 @@
       PointersToMembersPragmaLocation = ReadSourceLocation(F, Record[1]);
       break;
 
-    case UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES:
+    case UNUSED_NAMED_DECL_CANDIDATES:
       for (unsigned I = 0, N = Record.size(); I != N; ++I)
-        UnusedLocalTypedefNameCandidates.push_back(
-            getGlobalDeclID(F, Record[I]));
+        UnusedNamedDeclCandidates.push_back(getGlobalDeclID(F, Record[I]));
       break;
 
     case CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH:
@@ -8088,16 +8087,15 @@
   ExtVectorDecls.clear();
 }
 
-void ASTReader::ReadUnusedLocalTypedefNameCandidates(
-    llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) {
-  for (unsigned I = 0, N = UnusedLocalTypedefNameCandidates.size(); I != N;
+void ASTReader::ReadUnusedNamedDeclCandidates(
+    llvm::SmallSetVector<const NamedDecl *, 4> &Decls) {
+  for (unsigned I = 0, N = UnusedNamedDeclCandidates.size(); I != N;
        ++I) {
-    TypedefNameDecl *D = dyn_cast_or_null<TypedefNameDecl>(
-        GetDecl(UnusedLocalTypedefNameCandidates[I]));
-    if (D)
-      Decls.insert(D);
+    if (auto *ND = dyn_cast_or_null<NamedDecl>(
+        GetDecl(UnusedNamedDeclCandidates[I])))
+      Decls.insert(ND);
   }
-  UnusedLocalTypedefNameCandidates.clear();
+  UnusedNamedDeclCandidates.clear();
 }
 
 void ASTReader::ReadReferencedSelectors(
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -9334,8 +9334,10 @@
     Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
   }
 
-  if (UDir)
+  if (UDir) {
     ProcessDeclAttributeList(S, UDir, AttrList);
+    UnusedNamedDeclCandidates.insert(UDir);
+  }
 
   return UDir;
 }
@@ -9434,8 +9436,11 @@
       BuildUsingDeclaration(S, AS, UsingLoc, TypenameLoc.isValid(), TypenameLoc,
                             SS, TargetNameInfo, EllipsisLoc, AttrList,
                             /*IsInstantiation*/false);
-  if (UD)
+  if (UD) {
     PushOnScopeChains(UD, S, /*AddToContext*/ false);
+    if (isa<UsingDecl>(UD))
+      UnusedNamedDeclCandidates.insert(UD);
+  }
 
   return UD;
 }
@@ -10611,6 +10616,10 @@
     AliasDecl->setPreviousDecl(Prev);
 
   PushOnScopeChains(AliasDecl, S);
+
+  if (AliasDecl)
+    UnusedNamedDeclCandidates.insert(AliasDecl);
+
   return AliasDecl;
 }
 
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -1673,7 +1673,7 @@
   if (!WithinFunction)
     return false;
 
-  if (isa<TypedefNameDecl>(D))
+  if (isa<TypedefNameDecl>(D) || DeclAccessNamespace(D))
     return true;
 
   // White-list anything that isn't a local variable.
@@ -1762,10 +1762,10 @@
   if (!ShouldDiagnoseUnusedDecl(D))
     return;
 
-  if (auto *TD = dyn_cast<TypedefNameDecl>(D)) {
-    // typedefs can be referenced later on, so the diagnostics are emitted
-    // at end-of-translation-unit.
-    UnusedLocalTypedefNameCandidates.insert(TD);
+  if (isa<TypedefNameDecl>(D) || DeclAccessNamespace(D)) {
+    // typedefs and usings can be referenced later on, so the diagnostics are
+    // emitted at end-of-translation-unit.
+    UnusedNamedDeclCandidates.insert(D);
     return;
   }
 
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -807,17 +807,28 @@
   return Complete;
 }
 
-void Sema::emitAndClearUnusedLocalTypedefWarnings() {
+void Sema::emitAndClearUnusedNamedDeclWarnings() {
   if (ExternalSource)
-    ExternalSource->ReadUnusedLocalTypedefNameCandidates(
-        UnusedLocalTypedefNameCandidates);
-  for (const TypedefNameDecl *TD : UnusedLocalTypedefNameCandidates) {
-    if (TD->isReferenced())
+    ExternalSource->ReadUnusedNamedDeclCandidates(
+        UnusedNamedDeclCandidates);
+  for (const NamedDecl *ND : UnusedNamedDeclCandidates) {
+    if (ND->isReferenced())
       continue;
-    Diag(TD->getLocation(), diag::warn_unused_local_typedef)
-        << isa<TypeAliasDecl>(TD) << TD->getDeclName();
+    if (isa<TypedefNameDecl>(ND))
+      Diag(ND->getLocation(), diag::warn_unused_local_typedef)
+          << isa<TypeAliasDecl>(ND) << ND->getDeclName();
+    else if (isa<UsingDecl>(ND))
+      Diag(ND->getLocation(), diag::warn_unused_using_declaration)
+          << ND->getDeclName();
+    else if (isa<UsingDirectiveDecl>(ND)) {
+      auto *UD = dyn_cast<UsingDirectiveDecl>(ND);
+      Diag(ND->getLocation(), diag::warn_unused_using_directive)
+          << UD->getNominatedNamespaceAsWritten()->getDeclName();
+    } else
+      Diag(ND->getLocation(), diag::warn_unused_using_alias)
+          << ND->getDeclName();
   }
-  UnusedLocalTypedefNameCandidates.clear();
+  UnusedNamedDeclCandidates.clear();
 }
 
 /// This is called before the very first declaration in the translation unit
@@ -1007,7 +1018,7 @@
 
     // Warnings emitted in ActOnEndOfTranslationUnit() should be emitted for
     // modules when they are built, not every time they are used.
-    emitAndClearUnusedLocalTypedefWarnings();
+    emitAndClearUnusedNamedDeclWarnings();
 
     // Modules don't need any of the checking below.
     if (!PP.isIncrementalProcessingEnabled())
@@ -1127,7 +1138,7 @@
       }
     }
 
-    emitAndClearUnusedLocalTypedefWarnings();
+    emitAndClearUnusedNamedDeclWarnings();
   }
 
   if (!Diags.isIgnored(diag::warn_unused_private_field, SourceLocation())) {
Index: lib/Sema/MultiplexExternalSemaSource.cpp
===================================================================
--- lib/Sema/MultiplexExternalSemaSource.cpp
+++ lib/Sema/MultiplexExternalSemaSource.cpp
@@ -267,10 +267,10 @@
     Sources[i]->ReadExtVectorDecls(Decls);
 }
 
-void MultiplexExternalSemaSource::ReadUnusedLocalTypedefNameCandidates(
-    llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) {
+void MultiplexExternalSemaSource::ReadUnusedNamedDeclCandidates(
+    llvm::SmallSetVector<const NamedDecl *, 4> &Decls) {
   for(size_t i = 0; i < Sources.size(); ++i)
-    Sources[i]->ReadUnusedLocalTypedefNameCandidates(Decls);
+    Sources[i]->ReadUnusedNamedDeclCandidates(Decls);
 }
 
 void MultiplexExternalSemaSource::ReadReferencedSelectors(
Index: include/clang/Serialization/ASTReader.h
===================================================================
--- include/clang/Serialization/ASTReader.h
+++ include/clang/Serialization/ASTReader.h
@@ -823,10 +823,10 @@
   /// Fields containing data that is used for semantic analysis
   //@{
 
-  /// The IDs of all potentially unused typedef names in the chain.
+  /// The IDs of all potentially unused typedef and using names in the chain.
   ///
   /// Sema tracks these to emit warnings.
-  SmallVector<uint64_t, 16> UnusedLocalTypedefNameCandidates;
+  SmallVector<uint64_t, 16> UnusedNamedDeclCandidates;
 
   /// Our current depth in #pragma cuda force_host_device begin/end
   /// macros.
@@ -1989,8 +1989,8 @@
 
   void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) override;
 
-  void ReadUnusedLocalTypedefNameCandidates(
-      llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) override;
+  void ReadUnusedNamedDeclCandidates(
+      llvm::SmallSetVector<const NamedDecl *, 4> &Decls) override;
 
   void ReadReferencedSelectors(
            SmallVectorImpl<std::pair<Selector, SourceLocation>> &Sels) override;
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -615,8 +615,8 @@
       /// Record code for \#pragma optimize options.
       OPTIMIZE_PRAGMA_OPTIONS = 51,
 
-      /// Record code for potentially unused local typedef names.
-      UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES = 52,
+      /// Record code for potentially unused local typedef and using names.
+      UNUSED_NAMED_DECL_CANDIDATES = 52,
 
       // ID 53 used to be a table of constructor initializer records.
 
Index: include/clang/Sema/SemaInternal.h
===================================================================
--- include/clang/Sema/SemaInternal.h
+++ include/clang/Sema/SemaInternal.h
@@ -60,6 +60,14 @@
   return isDeviceSideDecl == LangOpts.CUDAIsDevice;
 }
 
+// Helper function to check whether D is associated with namespace via one of
+// the variations: using-declaration, using-directive, alias-declaration.
+inline bool DeclAccessNamespace(const Decl *D) {
+  return isa<UsingDecl>(D) ||
+         isa<UsingDirectiveDecl>(D) ||
+         isa<NamespaceAliasDecl>(D);
+}
+
 // Directly mark a variable odr-used. Given a choice, prefer to use 
 // MarkVariableReferenced since it does additional checks and then 
 // calls MarkVarDeclODRUsed.
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -553,9 +553,9 @@
   /// Set containing all declared private fields that are not used.
   NamedDeclSetType UnusedPrivateFields;
 
-  /// Set containing all typedefs that are likely unused.
-  llvm::SmallSetVector<const TypedefNameDecl *, 4>
-      UnusedLocalTypedefNameCandidates;
+  /// Set containing all typedefs and usings that are likely unused.
+  llvm::SmallSetVector<const NamedDecl *, 4>
+      UnusedNamedDeclCandidates;
 
   /// Delete-expressions to be analyzed at the end of translation unit
   ///
@@ -1291,7 +1291,7 @@
   /// Retrieve the module loader associated with the preprocessor.
   ModuleLoader &getModuleLoader() const;
 
-  void emitAndClearUnusedLocalTypedefWarnings();
+  void emitAndClearUnusedNamedDeclWarnings();
 
   void ActOnStartOfTranslationUnit();
   void ActOnEndOfTranslationUnit();
Index: include/clang/Sema/MultiplexExternalSemaSource.h
===================================================================
--- include/clang/Sema/MultiplexExternalSemaSource.h
+++ include/clang/Sema/MultiplexExternalSemaSource.h
@@ -273,14 +273,15 @@
   /// introduce the same declarations repeatedly.
   void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl*> &Decls) override;
 
-  /// Read the set of potentially unused typedefs known to the source.
+  /// Read the set of potentially unused typedefs and usings known to the
+  /// source.
   ///
   /// The external source should append its own potentially unused local
   /// typedefs to the given vector of declarations. Note that this routine may
   /// be invoked multiple times; the external source should take care not to
   /// introduce the same declarations repeatedly.
-  void ReadUnusedLocalTypedefNameCandidates(
-      llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) override;
+  void ReadUnusedNamedDeclCandidates(
+      llvm::SmallSetVector<const NamedDecl *, 4> &Decls) override;
 
   /// Read the set of referenced selectors known to the
   /// external Sema source.
Index: include/clang/Sema/ExternalSemaSource.h
===================================================================
--- include/clang/Sema/ExternalSemaSource.h
+++ include/clang/Sema/ExternalSemaSource.h
@@ -136,14 +136,15 @@
   /// introduce the same declarations repeatedly.
   virtual void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) {}
 
-  /// Read the set of potentially unused typedefs known to the source.
+  /// Read the set of potentially unused typedefs and usings known to the
+  /// source.
   ///
   /// The external source should append its own potentially unused local
   /// typedefs to the given vector of declarations. Note that this routine may
   /// be invoked multiple times; the external source should take care not to
   /// introduce the same declarations repeatedly.
-  virtual void ReadUnusedLocalTypedefNameCandidates(
-      llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) {}
+  virtual void ReadUnusedNamedDeclCandidates(
+      llvm::SmallSetVector<const NamedDecl *, 4> &Decls) {}
 
   /// Read the set of referenced selectors known to the
   /// external Sema source.
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -279,6 +279,15 @@
 def warn_unused_local_typedef : Warning<
   "unused %select{typedef|type alias}0 %1">,
   InGroup<UnusedLocalTypedef>, DefaultIgnore;
+def warn_unused_using_declaration : Warning<
+  "unused using declaration %0">,
+  InGroup<UnusedUsing>, DefaultIgnore;
+def warn_unused_using_directive : Warning<
+  "unused using directive %0">,
+  InGroup<UnusedUsing>, DefaultIgnore;
+def warn_unused_using_alias : Warning<
+  "unused namespace alias %0">,
+  InGroup<UnusedUsing>, DefaultIgnore;
 def warn_unused_property_backing_ivar : 
   Warning<"ivar %0 which backs the property is not "
   "referenced in this property's accessor">,
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -573,6 +573,7 @@
 def UnusedVariable : DiagGroup<"unused-variable",
                                [UnusedConstVariable]>;
 def UnusedLocalTypedef : DiagGroup<"unused-local-typedef">;
+def UnusedUsing : DiagGroup<"unused-using">;
 def UnusedPropertyIvar :  DiagGroup<"unused-property-ivar">;
 def UnusedGetterReturnValue : DiagGroup<"unused-getter-return-value">;
 def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">;
@@ -703,6 +704,7 @@
                         // UnusedMemberFunction, (clean-up llvm before enabling)
                         UnusedPrivateField, UnusedLambdaCapture,
                         UnusedLocalTypedef, UnusedValue, UnusedVariable,
+                        UnusedUsing,
                         UnusedPropertyIvar]>,
                         DiagCategory<"Unused Entity Issue">;
 
Index: docs/ReleaseNotes.rst
===================================================================
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -112,6 +112,34 @@
   'no-strict' option, Clang attempts to match the overflowing behavior of the
   target's native float-to-int conversion instructions.
 
+- :option:`-Wunused-using`.
+
+  ``-Wall`` now includes the new warning flag ``-Wunused-using``, which emits a
+  warning on using statements that are not used. This may result in new
+  warnings in code that compiled cleanly with previous versions.
+
+  Example:
+
+  .. code-block:: c++
+
+    namespace n { class C; }
+    using n::C;  // Never actually used.
+
+  Gives the following warning:
+
+  ::
+
+    ./test.cpp:2:10: warning: unused using declaration 'C' [-Wunused-using]
+      using n::C;
+               ^
+    1 warning generated.
+
+  The warnings will not result in compilation failure, unless ``-Wall`` is
+  used in conjunction with ``-Werror`` and as a result, the new warnings
+  are turned into new errors.
+
+  To fix, simply remove the unused using statement or use ``-Wno-unused-using``.
+
 - ...
 
 Deprecated Compiler Flags
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to