[cfe-commits] [PATCH] Fix broken diagnostic pragmas

Douglas Gregor dgregor at apple.com
Wed Nov 10 22:06:27 PST 2010


On Nov 10, 2010, at 9:34 PM, Argyrios Kyrtzidis wrote:

> Diagnostic pragmas are broken because we don't keep track of the diagnostic state changes and we only check the current/latest state.
> Problems manifest if a diagnostic is emitted for a source line that has different diagnostic state than the current state; this can affect
> a lot of places, like C++ inline methods, template instantiations, the lexer, etc. For example:
> 
> struct S {
> #pragma clang diagnostic push
> #pragma clang diagnostic ignored "-Wtautological-compare"
> 	void m() { int b = b==b; }
> #pragma clang diagnostic pop
> };
> 
> the pragmas do not work for suppressing the warning in the above case.
> 
> The attached patch fixes the issue by having the Diagnostic object keep track of the source location of the pragmas so that it is able to know what is the diagnostic state at any given source location.

This is really cool, Argiris!

@@ -365,33 +376,56 @@ void Diagnostic::ReportDelayed() {
   DelayedDiagArg2.clear();
 }
 
+Diagnostic::DiagStatePointsTy::iterator
+Diagnostic::GetDiagStatePointForLoc(FullSourceLoc Loc) const {
+  assert(!DiagStatePoints.empty());
+  assert(DiagStatePoints.front().Loc.isInvalid() &&
+         "Should have created a DiagStatePoint for command-line");
+
+  if (Loc.isInvalid())
+    return DiagStatePoints.begin();

I guess I was expecting that we would return the last DiagStatePoint for an invalid location (so that we get the most recent state), rather than the first.

diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 4a40405..51b6dae 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -252,12 +252,14 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
 
   // This is the end of the top-level file.  If the diag::pp_macro_not_used
   // diagnostic is enabled, look for macros that have not been used.
-  if (getDiagnostics().getDiagnosticLevel(diag::pp_macro_not_used) !=
-        Diagnostic::Ignored) {
-    for (macro_iterator I = macro_begin(false), E = macro_end(false); 
-         I != E; ++I)
-      if (!I->second->isUsed())
-        Diag(I->second->getDefinitionLoc(), diag::pp_macro_not_used);
+  for (macro_iterator I = macro_begin(false), E = macro_end(false); 
+       I != E; ++I) {
+    if (I->second->isUsed())
+      continue;
+    FullSourceLoc DefLoc(I->second->getDefinitionLoc(), getSourceManager());
+    if (getDiagnostics().getDiagnosticLevel(diag::pp_macro_not_used, DefLoc) !=
+        Diagnostic::Ignored)
+      Diag(DefLoc, diag::pp_macro_not_used);
   }

It's unfortunate this fixing this check means that we always have to iterate over all of the macros. In particular, I wonder if this causes deserialization of macros of a PCH file, which would be a performance killer. Could you check?

> I've also made measurements to see how this fix impacts performance. I basically measured how long it takes to do a -fsyntax-only over the llvm/clang codebase and the results were:
> 
> before the fix: 722.83 sec
> after the fix: 727.24 sec
> 
> So avoiding the fix only provides a 0.6% gain.


Other than the above, I didn't notice any other opportunities for optimization here. I think we have to suck up the cost in the name of correctness.

	- Doug



More information about the cfe-commits mailing list