Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -276,6 +276,8 @@ Clang ABI >= 15. (`#62353: `_, fallout from the non-POD packing ABI fix in LLVM 15). +- Clang now warns when any predefined macro is undefined or redefined, instead + of only some of them. Bug Fixes in This Version Index: clang/lib/Lex/PPDirectives.cpp =================================================================== --- clang/lib/Lex/PPDirectives.cpp +++ clang/lib/Lex/PPDirectives.cpp @@ -319,15 +319,6 @@ return Diag(MacroNameTok, diag::err_defined_macro_name); } - if (isDefineUndef == MU_Undef) { - auto *MI = getMacroInfo(II); - if (MI && MI->isBuiltinMacro()) { - // Warn if undefining "__LINE__" and other builtins, per C99 6.10.8/4 - // and C++ [cpp.predefined]p4], but allow it as an extension. - Diag(MacroNameTok, diag::ext_pp_undef_builtin_macro); - } - } - // If defining/undefining reserved identifier or a keyword, we need to issue // a warning. SourceLocation MacroNameLoc = MacroNameTok.getLocation(); @@ -3012,6 +3003,12 @@ MI->setTokens(Tokens, BP); return MI; } + +static bool isObjCProtectedMacro(const IdentifierInfo *II) { + return II->isStr("__strong") || II->isStr("__weak") || + II->isStr("__unsafe_unretained") || II->isStr("__autoreleasing"); +} + /// HandleDefineDirective - Implements \#define. This consumes the entire macro /// line then lets the caller lex the next real token. void Preprocessor::HandleDefineDirective( @@ -3083,15 +3080,9 @@ // In Objective-C, ignore attempts to directly redefine the builtin // definitions of the ownership qualifiers. It's still possible to // #undef them. - auto isObjCProtectedMacro = [](const IdentifierInfo *II) -> bool { - return II->isStr("__strong") || - II->isStr("__weak") || - II->isStr("__unsafe_unretained") || - II->isStr("__autoreleasing"); - }; - if (getLangOpts().ObjC && - SourceMgr.getFileID(OtherMI->getDefinitionLoc()) - == getPredefinesFileID() && + if (getLangOpts().ObjC && + SourceMgr.getFileID(OtherMI->getDefinitionLoc()) == + getPredefinesFileID() && isObjCProtectedMacro(MacroNameTok.getIdentifierInfo())) { // Warn if it changes the tokens. if ((!getDiagnostics().getSuppressSystemWarnings() || @@ -3115,7 +3106,8 @@ // Warn if defining "__LINE__" and other builtins, per C99 6.10.8/4 and // C++ [cpp.predefined]p4, but allow it as an extension. - if (OtherMI->isBuiltinMacro()) + if (OtherMI->isBuiltinMacro() || + SourceMgr.isWrittenInBuiltinFile(OtherMI->getDefinitionLoc())) Diag(MacroNameTok, diag::ext_pp_redef_builtin_macro); // Macros must be identical. This means all tokens and whitespace // separation must be the same. C99 6.10.3p2. @@ -3195,6 +3187,14 @@ if (!MI->isUsed() && MI->isWarnIfUnused()) Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used); + // Warn if undefining "__LINE__" and other builtins, per C99 6.10.8/4 and + // C++ [cpp.predefined]p4, but allow it as an extension. Don't warn if this + // is an Objective-C builtin macro though. + if ((MI->isBuiltinMacro() || + SourceMgr.isWrittenInBuiltinFile(MI->getDefinitionLoc())) && + !(getLangOpts().ObjC && isObjCProtectedMacro(II))) + Diag(MacroNameTok, diag::ext_pp_undef_builtin_macro); + if (MI->isWarnIfUnused()) WarnUnusedMacroLocs.erase(MI->getDefinitionLoc()); Index: clang/test/Lexer/builtin_redef.c =================================================================== --- clang/test/Lexer/builtin_redef.c +++ clang/test/Lexer/builtin_redef.c @@ -1,12 +1,24 @@ -// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 | FileCheck %s --check-prefix=CHECK-OUT -// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 | FileCheck %s --check-prefix=CHECK-WARN -// RUN: not %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 -pedantic-errors | FileCheck %s --check-prefix=CHECK-ERR +// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -D__STDC__=1 -U__STDC_HOSTED__ -E 2>&1 | FileCheck %s --check-prefix=CHECK-OUT +// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -D__STDC__=1 -U__STDC_HOSTED__ -E 2>&1 | FileCheck %s --check-prefix=CHECK-WARN +// RUN: not %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -D__STDC__=1 -U__STDC_HOSTED__ -E 2>&1 -pedantic-errors | FileCheck %s --check-prefix=CHECK-ERR // CHECK-WARN: :{{.*}} warning: redefining builtin macro +// CHECK-WARN-NEXT: #define __TIME__ 1234 // CHECK-WARN: :{{.*}} warning: undefining builtin macro +// CHECK-WARN-NEXT: #undef __DATE__ +// CHECK-WARN: :{{.*}} warning: redefining builtin macro +// CHECK-WARN-NEXT: #define __STDC__ 1 +// CHECK-WARN: :{{.*}} warning: undefining builtin macro +// CHECK-WARN-NEXT: #undef __STDC_HOSTED__ // CHECK-ERR: :{{.*}} error: redefining builtin macro +// CHECK-ERR-NEXT: #define __TIME__ 1234 +// CHECK-ERR: :{{.*}} error: undefining builtin macro +// CHECK-ERR-NEXT: #undef __DATE__ +// CHECK-ERR: :{{.*}} error: redefining builtin macro +// CHECK-ERR-NEXT: #define __STDC__ 1 // CHECK-ERR: :{{.*}} error: undefining builtin macro +// CHECK-ERR-NEXT: #undef __STDC_HOSTED__ int n = __TIME__; __DATE__ Index: clang/test/Preprocessor/macro-reserved.c =================================================================== --- clang/test/Preprocessor/macro-reserved.c +++ clang/test/Preprocessor/macro-reserved.c @@ -6,6 +6,7 @@ #define __cplusplus #define _HAVE_X 0 #define X__Y +#define __STDC__ 1 // expected-warning {{redefining builtin macro}} #undef for #undef final @@ -13,6 +14,7 @@ #undef __cplusplus #undef _HAVE_X #undef X__Y +#undef __STDC_HOSTED__ // expected-warning {{undefining builtin macro}} // allowlisted definitions #define while while Index: clang/test/Preprocessor/macro-reserved.cpp =================================================================== --- clang/test/Preprocessor/macro-reserved.cpp +++ clang/test/Preprocessor/macro-reserved.cpp @@ -12,7 +12,7 @@ #undef _HAVE_X #undef X__Y -#undef __cplusplus +#undef __cplusplus // expected-warning {{undefining builtin macro}} #define __cplusplus // allowlisted definitions