urnathan updated this revision to Diff 465007.
urnathan marked an inline comment as done.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D134654/new/

https://reviews.llvm.org/D134654

Files:
  clang/include/clang/Basic/DiagnosticLexKinds.td
  clang/include/clang/Lex/Preprocessor.h
  clang/include/clang/Lex/PreprocessorLexer.h
  clang/lib/Lex/PPDirectives.cpp
  clang/lib/Lex/PPLexerChange.cpp
  clang/test/Preprocessor/warn-loop-import-1.h
  clang/test/Preprocessor/warn-loop-macro-1.h
  clang/test/Preprocessor/warn-loop-macro-2.h
  clang/test/Preprocessor/warn-loop-macro-2a.h
  clang/test/Preprocessor/warn-loop-main.c
  clang/test/Preprocessor/warn-loop-pragma-1.h

Index: clang/test/Preprocessor/warn-loop-pragma-1.h
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/warn-loop-pragma-1.h
@@ -0,0 +1,3 @@
+#pragma once
+// expected-warning@+1 {{#include cycle}}
+#include "warn-loop-pragma-1.h"
Index: clang/test/Preprocessor/warn-loop-main.c
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/warn-loop-main.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -Winclude-cycle -fsyntax-only -verify %s
+
+#include "warn-loop-macro-1.h"
+#include "warn-loop-macro-2.h"
+#include "warn-loop-macro-1.h"
+#include "warn-loop-import-1.h"
+#include "warn-loop-pragma-1.h"
Index: clang/test/Preprocessor/warn-loop-macro-2a.h
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/warn-loop-macro-2a.h
@@ -0,0 +1,5 @@
+#ifndef LOOP_MACRO_2a
+#define LOOP_MACRO_2a
+// expected-warning@+1 {{#include cycle}}
+#include "warn-loop-macro-2.h"
+#endif
Index: clang/test/Preprocessor/warn-loop-macro-2.h
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/warn-loop-macro-2.h
@@ -0,0 +1,6 @@
+#ifndef LOOP_MACRO_2
+#define LOOP_MACRO_2
+#include "warn-loop-macro-2a.h"
+// expected-warning@+1 {{#include cycle}}
+#include "warn-loop-macro-2.h"
+#endif
Index: clang/test/Preprocessor/warn-loop-macro-1.h
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/warn-loop-macro-1.h
@@ -0,0 +1,5 @@
+#ifndef LOOP_MACRO_1
+#define LOOP_MACRO_1
+// expected-warning@+1 {{#include cycle}}
+#include "warn-loop-macro-1.h"
+#endif
Index: clang/test/Preprocessor/warn-loop-import-1.h
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/warn-loop-import-1.h
@@ -0,0 +1,2 @@
+// expected-warning@+1 {{#include cycle}}
+#import "warn-loop-import-1.h"
Index: clang/lib/Lex/PPLexerChange.cpp
===================================================================
--- clang/lib/Lex/PPLexerChange.cpp
+++ clang/lib/Lex/PPLexerChange.cpp
@@ -103,6 +103,12 @@
     }
   }
 
+  if (const FileEntry *FE = SourceMgr.getFileEntryForID(FID)) {
+    const auto &[I, Added] = ActiveIncludedFiles.insert(FE);
+    if (!Added)
+      TheLexer->setCircularInclude();
+  }
+
   EnterSourceFileWithLexer(TheLexer, CurDir);
   return false;
 }
@@ -432,6 +438,11 @@
   // lexing the #includer file.
   if (!IncludeMacroStack.empty()) {
 
+    if (CurPPLexer && !CurPPLexer->isCircularInclude())
+      if (const FileEntry *FE =
+              SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))
+        ActiveIncludedFiles.erase(FE);
+
     // If we lexed the code-completion file, act as if we reached EOF.
     if (isCodeCompletionEnabled() && CurPPLexer &&
         SourceMgr.getLocForStartOfFile(CurPPLexer->getFileID()) ==
Index: clang/lib/Lex/PPDirectives.cpp
===================================================================
--- clang/lib/Lex/PPDirectives.cpp
+++ clang/lib/Lex/PPDirectives.cpp
@@ -2318,6 +2318,13 @@
     FileCharacter = std::max(HeaderInfo.getFileDirFlavor(&File->getFileEntry()),
                              FileCharacter);
 
+  // Check if we're considering entering a file that is already active in the
+  // include stack.  Even if File is idempotent, these cycles are problematic
+  // for modularization.
+  if (Action == Enter && File &&
+      ActiveIncludedFiles.contains(&File->getFileEntry()))
+    Diag(FilenameTok.getLocation(), diag::warn_include_cycle);
+
   // If this is a '#import' or an import-declaration, don't re-enter the file.
   //
   // FIXME: If we have a suggested module for a '#include', and we've already
Index: clang/include/clang/Lex/PreprocessorLexer.h
===================================================================
--- clang/include/clang/Lex/PreprocessorLexer.h
+++ clang/include/clang/Lex/PreprocessorLexer.h
@@ -67,6 +67,9 @@
   /// Note that in raw mode that the PP pointer may be null.
   bool LexingRawMode = false;
 
+  /// Record whether this lexer is for a recursive include.
+  bool IsCircularInclude = false;
+
   /// A state machine that detects the \#ifndef-wrapping a file
   /// idiom for the multiple-include optimization.
   MultipleIncludeOpt MIOpt;
@@ -141,6 +144,11 @@
   /// Return true if this lexer is in raw mode or not.
   bool isLexingRawMode() const { return LexingRawMode; }
 
+  void setCircularInclude() { IsCircularInclude = true; }
+
+  /// Retur true iff this lexer is a circular include.
+  bool isCircularInclude() const { return IsCircularInclude; }
+
   /// Return the preprocessor object for this lexer.
   Preprocessor *getPP() const { return PP; }
 
Index: clang/include/clang/Lex/Preprocessor.h
===================================================================
--- clang/include/clang/Lex/Preprocessor.h
+++ clang/include/clang/Lex/Preprocessor.h
@@ -862,6 +862,9 @@
   /// The files that have been included.
   IncludedFilesSet IncludedFiles;
 
+  /// The currently being lexed included files
+  IncludedFilesSet ActiveIncludedFiles;
+
   /// The set of top-level modules that affected preprocessing, but were not
   /// imported.
   llvm::SmallSetVector<Module *, 2> AffectingModules;
Index: clang/include/clang/Basic/DiagnosticLexKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticLexKinds.td
+++ clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -320,6 +320,8 @@
   "whitespace required after macro name">;
 def warn_missing_whitespace_after_macro_name : Warning<
   "whitespace recommended after macro name">;
+def warn_include_cycle : Warning<"#include cycle">,
+   InGroup<DiagGroup<"include-cycle">>, DefaultIgnore;
 
 class NonportablePath  : Warning<
   "non-portable path to file '%0'; specified path differs in case from file"
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to