arichardson created this revision. arichardson added a reviewer: rsmith. Herald added a subscriber: cfe-commits.
The characters after '__has_include(' have special lexing rules that can't possibly be applied when __has_include is generated by a macro. Instead of wrapping __has_include in another macro the following should be used instead: #ifndef __has_include #define __has_include(...) 0 #endif This warning should fix the underlying issue for https://llvm.org/pr37990 Repository: rC Clang https://reviews.llvm.org/D49091 Files: include/clang/Basic/DiagnosticLexKinds.td lib/Lex/PPMacroExpansion.cpp test/Preprocessor/expr_has_include_expansion.c 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(<chrono>) // 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(<sys/foo.h>) // 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(<chrono>) +#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 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: 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<ExpansionToDefined>; +def warn_has_include_in_macro_expansion : Warning< + "macro expansion producing %0 has undefined behavior">, +InGroup<DiagGroup<"expansion-to-has-include">>; + + let CategoryName = "Nullability Issue" in { def err_pp_assume_nonnull_syntax : Error<"expected 'begin' or 'end'">;
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(<chrono>) // 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(<sys/foo.h>) // 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(<chrono>) +#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 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: 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<ExpansionToDefined>; +def warn_has_include_in_macro_expansion : Warning< + "macro expansion producing %0 has undefined behavior">, +InGroup<DiagGroup<"expansion-to-has-include">>; + + let CategoryName = "Nullability Issue" in { def err_pp_assume_nonnull_syntax : Error<"expected 'begin' or 'end'">;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits