[PATCH] Enable checkUndefinedButUsed() unconditionally at end of TU

Alp Toker alp at nuanti.com
Sun Jun 8 07:23:27 PDT 2014


Right now we only emit the "function/variable has internal linkage but 
is not defined" warning at end of TU if no errors were encountered.

However we probably shouldn't skip checkUndefinedButUsed() so liberally. 
It causes lack of test coverage (doesn't appear in any -verify + 
expected-error test) and loss of useful information for users.

Best guess is that it came to be this way back when bodies used to get 
skipped liberally in error recovery. Nowadays we're tracking definitions 
effectively and should be able to enable the checks unconditionally.

Simple enough? Now for the bad news..

There are 26 tests relying on not using undefined inline functions:

Failing Tests (26):
     Clang :: CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
     Clang :: CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
     Clang :: CXX/drs/dr2xx.cpp
     Clang :: CXX/drs/dr3xx.cpp
     Clang :: CXX/drs/dr4xx.cpp
     Clang :: CXX/expr/expr.const/p2-0x.cpp
     Clang :: CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
     Clang :: CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
     Clang :: CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
     Clang :: CXX/temp/temp.arg/temp.arg.type/p2.cpp
     Clang :: CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp
     Clang :: Modules/namespaces.cpp
     Clang :: Modules/redecl-add-after-load.cpp
     Clang :: Parser/cxx-ambig-paren-expr.cpp
     Clang :: Parser/recovery.cpp
     Clang :: Sema/array-init.c
     Clang :: Sema/inline.c
     Clang :: Sema/invalid-decl.c
     Clang :: SemaCXX/anonymous-struct.cpp
     Clang :: SemaCXX/explicit.cpp
     Clang :: SemaCXX/expression-traits.cpp
     Clang :: SemaCXX/lambda-expressions.cpp
     Clang :: SemaCXX/new-delete.cpp
     Clang :: SemaCXX/overload-call.cpp
     Clang :: SemaCXX/typo-correction.cpp
     Clang :: SemaTemplate/deduction.cpp

For each we need to figure out the right fix, which varies case by case:

  a) add a definition body {}
  b) de-inline the declaration
  c) add expected-warning {{}}
  d) or just run -Wno-undefined-internal in tests where it doesn't matter

* (c) and (d) will be problematic when the warning becomes a hard error 
as planned in Sema FIXMEs.

So, if we want to apply the patch fixing the issue we'll need to update 
all those tests to valid syntax.

The attached patch implements the fix and demonstrates each one of the 
strategies to get started. Thoughts/volunteers? :-)

Related to:
   PR19910 - Don't suppress unused/undefined warnings when there are errors
   http://llvm.org/bugs/show_bug.cgi?id=19910

Historical context:
   PR5933 - bogus unused variable warning after error
   http://llvm.org/bugs/show_bug.cgi?id=5933

Alp.

-- 
http://www.nuanti.com
the browser experts

-------------- next part --------------
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index ce0911e..b2e084b 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -468,6 +468,8 @@ void Sema::getUndefinedButUsed(
 /// checkUndefinedButUsed - Check for undefined objects with internal linkage
 /// or that are inline.
 static void checkUndefinedButUsed(Sema &S) {
+  if (auto ES = S.getExternalSource())
+    ES->ReadUndefinedButUsed(S.UndefinedButUsed);
   if (S.UndefinedButUsed.empty()) return;
 
   // Collect all the still-undefined entities with internal linkage.
@@ -817,12 +819,10 @@ void Sema::ActOnEndOfTranslationUnit() {
         }
       }
     }
-
-    if (ExternalSource)
-      ExternalSource->ReadUndefinedButUsed(UndefinedButUsed);
-    checkUndefinedButUsed(*this);
   }
 
+  checkUndefinedButUsed(*this);
+
   if (Diags.getDiagnosticLevel(diag::warn_unused_private_field,
                                SourceLocation())
         != DiagnosticsEngine::Ignored) {
diff --git a/test/CXX/drs/dr4xx.cpp b/test/CXX/drs/dr4xx.cpp
index 815dbfc..39a68dc 100644
--- a/test/CXX/drs/dr4xx.cpp
+++ b/test/CXX/drs/dr4xx.cpp
@@ -1078,7 +1078,7 @@ namespace dr487 { // dr487: yes
 }
 
 namespace dr488 { // dr488: yes c++11
-  template <typename T> void f(T);
+  template <typename T> void f(T); // expected-warning {{has internal linkage but is not defined}}
   void f(int);
   void g() {
     // FIXME: It seems CWG thought this should be a SFINAE failure prior to
@@ -1086,7 +1086,7 @@ namespace dr488 { // dr488: yes c++11
     // allow local types as template arguments or treat this as a SFINAE
     // failure.
     enum E { e };
-    f(e);
+    f(e); // expected-note {{used here}}
 #if __cplusplus < 201103L
     // expected-error at -2 {{local type}}
 #endif
diff --git a/test/Sema/inline.c b/test/Sema/inline.c
index 8a3835b..b7675b2 100644
--- a/test/Sema/inline.c
+++ b/test/Sema/inline.c
@@ -7,7 +7,7 @@
 
 // Check the use of static variables in non-static inline functions.
 static int staticVar; // expected-note + {{'staticVar' declared here}}
-static int staticFunction(); // expected-note + {{'staticFunction' declared here}}
+static int staticFunction() { return 0; }; // expected-note + {{'staticFunction' declared here}}
 static struct { int x; } staticStruct; // expected-note + {{'staticStruct' declared here}}
 
 inline int useStatic () { // expected-note 3 {{use 'static' to give inline function 'useStatic' internal linkage}}
@@ -40,6 +40,8 @@ inline int useConst () {
   return constFunction(); // no-warning
 }
 
+static int constFunction() { return 0; }
+
 #else
 // -------
 // This is the main source file.
diff --git a/test/Sema/invalid-decl.c b/test/Sema/invalid-decl.c
index f0954b0..c06aae1 100644
--- a/test/Sema/invalid-decl.c
+++ b/test/Sema/invalid-decl.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 %s -fsyntax-only -Wno-undefined-internal -verify
 
 void test() {
     char = 4;  // expected-error {{expected identifier}}
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
index da28eef..f040c1c 100644
--- a/test/SemaCXX/overload-call.cpp
+++ b/test/SemaCXX/overload-call.cpp
@@ -346,7 +346,7 @@ namespace test2 {
   class qrgb666 {
     inline operator unsigned int () const;
 
-    inline bool operator==(const qrgb666 &v) const;
+    bool operator==(const qrgb666 &v) const;
     inline bool operator!=(const qrgb666 &v) const { return !(*this == v); }
   };
 }


More information about the cfe-commits mailing list