Index: include/clang/Basic/DiagnosticLexKinds.td =================================================================== --- include/clang/Basic/DiagnosticLexKinds.td +++ include/clang/Basic/DiagnosticLexKinds.td @@ -771,6 +771,11 @@ "macro expansion producing 'defined' has undefined behavior">, InGroup; +def warn_has_include_in_macro_expansion : Warning< + "macro expansion producing %0 has undefined behavior">, +InGroup>; + + let CategoryName = "Nullability Issue" in { def err_pp_assume_nonnull_syntax : Error<"expected 'begin' or 'end'">; Index: lib/Lex/PPMacroExpansion.cpp =================================================================== --- lib/Lex/PPMacroExpansion.cpp +++ lib/Lex/PPMacroExpansion.cpp @@ -1182,6 +1182,12 @@ } } + if (LParenLoc.isMacroID()) + // The characters after '__has_include(' have special lexing rules that + // can't possibly be applied when __has_include is generated by a macro. + // Diagnose this to avoid problems such as https://llvm.org/pr37990 + PP.Diag(LParenLoc, diag::warn_has_include_in_macro_expansion) << II; + // Reserve a buffer to get the spelling. SmallString<128> FilenameBuffer; StringRef Filename; Index: test/Preprocessor/expr_has_include_expansion.c =================================================================== --- /dev/null +++ test/Preprocessor/expr_has_include_expansion.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 %s -E -verify -o /dev/null + +#define __libcpp_has_include(x) __has_include(x) +#if __libcpp_has_include() // expected-warning{{macro expansion producing '__has_include' has undefined behavior}} +#endif + +#define QT_HAS_INCLUDE_NEXT(x) __has_include_next(x) +#if QT_HAS_INCLUDE_NEXT() // expected-warning{{macro expansion producing '__has_include_next' has undefined behavior}} expected-warning{{#include_next in primary source file}} +#endif + +#define HAS_CHRONO __has_include() +#if HAS_CHRONO // expected-warning{{macro expansion producing '__has_include' has undefined behavior}} +#endif + +#define HAS_QUOTED_NEXT __has_include_next("foo.h") +#if HAS_QUOTED_NEXT // expected-warning{{macro expansion producing '__has_include_next' has undefined behavior}} expected-warning{{#include_next in primary source file}} +#endif + +// check that this diagnostic doesn't warn on normal __has_include() usage +#if __has_include("foo.h") || __has_include_next("bar.h") // expected-warning{{#include_next in primary source file}} +#endif