diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -150,6 +150,30 @@ MacroName); } +static bool isLanguageDefinedBuiltin(const SourceManager &SourceMgr, + const MacroInfo *MI, + const StringRef MacroName) { + // If this is a macro with special handling (like __LINE__) then it's language + // defined. + if (MI->isBuiltinMacro()) + return true; + // Builtin macros are defined in the builtin file + if (!SourceMgr.isWrittenInBuiltinFile(MI->getDefinitionLoc())) + return false; + // C defines macros starting with __STDC, and C++ defines macros starting with + // __STDCPP + if (MacroName.startswith("__STDC")) + return true; + // C++ defines the __cplusplus macro + if (MacroName == "__cplusplus") + return true; + // C++ defines various feature-test macros starting with __cpp + if (MacroName.startswith("__cpp")) + return true; + // Anything else isn't language-defined + return false; +} + static MacroDiag shouldWarnOnMacroDef(Preprocessor &PP, IdentifierInfo *II) { const LangOptions &Lang = PP.getLangOpts(); StringRef Text = II->getName(); @@ -3107,9 +3131,7 @@ // 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() || - (SourceMgr.isWrittenInBuiltinFile(OtherMI->getDefinitionLoc()) && - !isFeatureTestMacro(MacroNameTok.getIdentifierInfo()->getName()))) + if (isLanguageDefinedBuiltin(SourceMgr, OtherMI, II->getName())) 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. @@ -3190,11 +3212,8 @@ 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))) + // C++ [cpp.predefined]p4, but allow it as an extension. + if (isLanguageDefinedBuiltin(SourceMgr, MI, II->getName())) Diag(MacroNameTok, diag::ext_pp_undef_builtin_macro); if (MI->isWarnIfUnused()) diff --git a/clang/test/Preprocessor/macro-reserved.c b/clang/test/Preprocessor/macro-reserved.c --- a/clang/test/Preprocessor/macro-reserved.c +++ b/clang/test/Preprocessor/macro-reserved.c @@ -7,6 +7,7 @@ #define _HAVE_X 0 #define X__Y #define __STDC__ 1 // expected-warning {{redefining builtin macro}} +#define __clang__ 1 #undef for #undef final @@ -15,6 +16,12 @@ #undef _HAVE_X #undef X__Y #undef __STDC_HOSTED__ // expected-warning {{undefining builtin macro}} +#undef __INT32_TYPE__ +#undef __UINT32_TYPE__ +#undef __UINTPTR_TYPE__ +#undef __UINT64_TYPE__ +#undef __INT64_TYPE__ +#undef __OPTIMIZE__ // allowlisted definitions #define while while diff --git a/clang/test/Preprocessor/undef-x86.c b/clang/test/Preprocessor/undef-x86.c new file mode 100644 --- /dev/null +++ b/clang/test/Preprocessor/undef-x86.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple=i386-none-none -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple=x86_64-none-none -fsyntax-only -verify %s + +// Check that we can undefine triple-specific defines without warning +// expected-no-diagnostics +#undef __i386 +#undef __i386__ +#undef i386 +#undef __amd64 +#undef __amd64__ +#undef __x86_64 +#undef __x86_64__