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>, DefaultIgnore; class NonportablePath : Warning< "non-portable path to file '%0'; specified path differs in case from file" Index: clang/include/clang/Basic/FileEntry.h =================================================================== --- clang/include/clang/Basic/FileEntry.h +++ clang/include/clang/Basic/FileEntry.h @@ -359,6 +359,9 @@ const DirectoryEntry *Dir = nullptr; // Directory file lives in. llvm::sys::fs::UniqueID UniqueID; unsigned UID = 0; // A unique (small) ID for the file. + // Bitfieldiness vvvvv, mutabley? + // Maybe the including machinery should use a map?? + mutable unsigned Includedness = 0; // FIXME:DOCUMENT bool IsNamedPipe = false; /// The open file, if it is owned by the \p FileEntry. @@ -393,6 +396,12 @@ /// the native FileManager methods). bool isNamedPipe() const { return IsNamedPipe; } + bool isEntered() const { return Includedness != 0; } + void EnterOrLeave(bool Enter) const { + assert(Enter || Includedness); + Includedness += Enter ? +1 : -1; + } + void closeFile() const; }; Index: clang/lib/Headers/emmintrin.h =================================================================== --- clang/lib/Headers/emmintrin.h +++ clang/lib/Headers/emmintrin.h @@ -14,7 +14,11 @@ #error "This header is only meant to be used on x86 and x64 architecture" #endif +#ifndef __XMMINTRIN_H +/* xmmintrin can #include this file under certain cirumstances, prevent a loop + that is problematic for clang modules and C++ header-units. */ #include +#endif typedef double __m128d __attribute__((__vector_size__(16), __aligned__(16))); typedef long long __m128i __attribute__((__vector_size__(16), __aligned__(16))); Index: clang/lib/Headers/xmmintrin.h =================================================================== --- clang/lib/Headers/xmmintrin.h +++ clang/lib/Headers/xmmintrin.h @@ -3010,7 +3010,8 @@ #undef __DEFAULT_FN_ATTRS_MMX /* Ugly hack for backwards-compatibility (compatible with gcc) */ -#if defined(__SSE2__) && !__building_module(_Builtin_intrinsics) +#if !defined(__EMMINTRIN_H) && defined(__SSE2__) && \ + !__building_module(_Builtin_intrinsics) #include #endif Index: clang/lib/Lex/PPDirectives.cpp =================================================================== --- clang/lib/Lex/PPDirectives.cpp +++ clang/lib/Lex/PPDirectives.cpp @@ -2329,6 +2329,9 @@ bool IsFirstIncludeOfFile = false; + if (Action == Enter && File && File->getFileEntry().isEntered()) + Diag(FilenameTok.getLocation(), diag::warn_include_cycle); + // Ask HeaderInfo if we should enter this #include file. If not, #including // this file will have no effect. if (Action == Enter && File && Index: clang/lib/Lex/PPLexerChange.cpp =================================================================== --- clang/lib/Lex/PPLexerChange.cpp +++ clang/lib/Lex/PPLexerChange.cpp @@ -103,6 +103,10 @@ } } + if (TheLexer->getPP()) + if (auto *FE = SourceMgr.getFileEntryForID(FID)) + FE->EnterOrLeave(true); + EnterSourceFileWithLexer(TheLexer, CurDir); return false; } @@ -432,6 +436,10 @@ // lexing the #includer file. if (!IncludeMacroStack.empty()) { + if (CurPPLexer) + if (auto *FE = SourceMgr.getFileEntryForID(CurPPLexer->getFileID())) + FE->EnterOrLeave(false); + // If we lexed the code-completion file, act as if we reached EOF. if (isCodeCompletionEnabled() && CurPPLexer && SourceMgr.getLocForStartOfFile(CurPPLexer->getFileID()) == 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/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-macro-2.h =================================================================== --- /dev/null +++ clang/test/Preprocessor/warn-loop-macro-2.h @@ -0,0 +1,4 @@ +#ifndef LOOP_MACRO_2 +#define LOOP_MACRO_2 +#include "warn-loop-macro-2a.h" +#endif 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-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-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"