Reapply [Clang] Implement P2843R3 - Preprocessing is never undefined (#196989)

This PR reapply https://github.com/llvm/llvm-project/pull/192073, and
make most `-pedantic` warnings default on.

---
This PR marks [P2843R3 - Preprocessing is never
undefined](https://wg21.link/P2843) as implemented and add tests.

Fixes https://github.com/llvm/llvm-project/issues/145658

---------

Signed-off-by: yronglin <yronglin777@gmail.com>
This commit is contained in:
Yihan Wang 2026-05-20 01:06:02 +08:00 committed by GitHub
parent a9ceabab84
commit 22e8c55ccf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 246 additions and 115 deletions

View file

@ -152,6 +152,12 @@ C++ Language Changes
C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Implemented `P2843R3 <https://wg21.link/P2843R3>`_ Preprocessing is never
undefined. Clang now diagnoses a macro expansion producing ``defined`` in a
conditional expression, an embedded directive within macro arguments, macro
names reserved for keywords, special identifiers, or standard attribute
tokens by default.
C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^

View file

@ -421,13 +421,16 @@ def note_pp_ambiguous_macro_chosen : Note<
"expanding this definition of %0">;
def note_pp_ambiguous_macro_other : Note<
"other definition of %0">;
def warn_pp_macro_hides_keyword : Extension<
def warn_pp_macro_hides_keyword : ExtWarn<
"keyword is hidden by macro definition">, InGroup<KeywordAsMacro>;
def warn_pp_macro_name_is_keyword : ExtWarn<
"keyword or identifier with special meaning is used as a macro name">,
InGroup<KeywordAsMacro>;
def warn_pp_macro_is_reserved_id : Warning<
"macro name is a reserved identifier">, DefaultIgnore,
InGroup<ReservedIdAsMacro>;
def warn_pp_macro_is_reserved_attribute_id : Warning<
"%0 is a reserved attribute identifier">, DefaultIgnore,
"%0 is a reserved attribute identifier">,
InGroup<ReservedAttributeIdentifier>;
def warn_pp_objc_macro_redef_ignored : Warning<
"ignoring redefinition of Objective-C qualifier macro">,
@ -506,10 +509,10 @@ def warn_cxx98_compat_variadic_macro : Warning<
InGroup<CXX98CompatPedantic>, DefaultIgnore;
def ext_named_variadic_macro : Extension<
"named variadic macros are a GNU extension">, InGroup<VariadicMacros>;
def err_embedded_directive : Error<"embedding a %select{|#}0%1 directive "
def err_embedded_directive : Error<"embedding a%select{ #| @|}0%1 directive "
"within macro arguments is not supported">;
def ext_embedded_directive : Extension<
"embedding a directive within macro arguments has undefined behavior">,
def warn_embedded_directive : ExtWarn<
"embedding a%select{ #| @|}0%1 directive within macro arguments has undefined behavior">,
InGroup<DiagGroup<"embedded-directive">>;
def ext_c_missing_varargs_arg : Extension<
"passing no argument for the '...' parameter of a variadic macro is "
@ -1056,10 +1059,7 @@ def warn_header_guard : Warning<
def note_header_guard : Note<
"%0 is defined here; did you mean %1?">;
def warn_defined_in_object_type_macro : Warning<
"macro expansion producing 'defined' has undefined behavior">,
InGroup<ExpansionToDefined>;
def warn_defined_in_function_type_macro : Extension<
def warn_defined_in_macro : Warning<
"macro expansion producing 'defined' has undefined behavior">,
InGroup<ExpansionToDefined>;

View file

@ -186,13 +186,9 @@ static bool isReservedCXXAttributeName(Preprocessor &PP, IdentifierInfo *II) {
if (Lang.CPlusPlus &&
hasAttribute(AttributeCommonInfo::AS_CXX11, /* Scope*/ nullptr, II,
PP.getTargetInfo(), Lang, /*CheckPlugins*/ false) > 0) {
AttributeCommonInfo::AttrArgsInfo AttrArgsInfo =
AttributeCommonInfo::getCXX11AttrArgsInfo(II);
if (AttrArgsInfo == AttributeCommonInfo::AttrArgsInfo::Required)
return PP.isNextPPTokenOneOf(tok::l_paren);
StringRef Name = II->getName();
return !PP.isNextPPTokenOneOf(tok::l_paren) ||
AttrArgsInfo == AttributeCommonInfo::AttrArgsInfo::Optional;
(Name != "likely" && Name != "unlikely");
}
return false;
}
@ -213,7 +209,11 @@ static MacroDiag shouldWarnOnMacroDef(Preprocessor &PP, IdentifierInfo *II) {
static MacroDiag shouldWarnOnMacroUndef(Preprocessor &PP, IdentifierInfo *II) {
const LangOptions &Lang = PP.getLangOpts();
// Do not warn on keyword undef. It is generally harmless and widely used.
StringRef Text = II->getName();
if (II->isKeyword(Lang))
return MD_KeywordDef;
if (Lang.CPlusPlus11 && (Text == "override" || Text == "final"))
return MD_KeywordDef;
if (isReservedInAllContexts(II->isReserved(Lang)))
return MD_ReservedMacro;
if (isReservedCXXAttributeName(PP, II))
@ -410,8 +410,10 @@ bool Preprocessor::CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
// We do not want to warn on some patterns widely used in configuration
// scripts. This requires analyzing next tokens, so do not issue warnings
// now, only inform caller.
if (ShadowFlag)
if (isDefineUndef == MU_Define && ShadowFlag)
*ShadowFlag = true;
else
Diag(MacroNameTok, diag::warn_pp_macro_name_is_keyword);
}
if (D == MD_ReservedMacro)
Diag(MacroNameTok, diag::warn_pp_macro_is_reserved_id);
@ -1351,7 +1353,27 @@ void Preprocessor::HandleDirective(Token &Result) {
// not support this for #include-like directives, since that can result in
// terrible diagnostics, and does not work in GCC.
if (InMacroArgs) {
enum IntroduceKind {
IK_HASH = 0,
IK_AT = 1,
IK_KEYWORD = 2,
};
IntroduceKind IK = IK_HASH;
switch (Introducer.getKind()) {
case tok::hash:
IK = IK_HASH;
break;
case tok::at:
IK = IK_AT;
break;
default:
IK = IK_KEYWORD;
break;
}
SmallString<16> DirectiveSpelling;
if (IdentifierInfo *II = Result.getIdentifierInfo()) {
DirectiveSpelling.append(II->getName());
switch (II->getPPKeywordID()) {
case tok::pp_include:
case tok::pp_import:
@ -1361,18 +1383,19 @@ void Preprocessor::HandleDirective(Token &Result) {
case tok::pp_embed:
case tok::pp_module:
case tok::pp___preprocessed_module:
case tok::pp___preprocessed_import:
Diag(Result, diag::err_embedded_directive)
<< Introducer.is(tok::hash) << II->getName();
case tok::pp___preprocessed_import: {
Diag(Result, diag::err_embedded_directive) << IK << DirectiveSpelling;
Diag(*ArgMacro, diag::note_macro_expansion_here)
<< ArgMacro->getIdentifierInfo();
DiscardUntilEndOfDirective();
return;
}
default:
break;
}
}
Diag(Result, diag::ext_embedded_directive);
Diag(Result, diag::warn_embedded_directive) << IK << DirectiveSpelling;
}
// Temporarily enable macro expansion if set so
@ -3329,9 +3352,8 @@ void Preprocessor::HandleDefineDirective(
if (!MI) return;
if (MacroShadowsKeyword &&
!isConfigurationPattern(MacroNameTok, MI, getLangOpts())) {
!isConfigurationPattern(MacroNameTok, MI, getLangOpts()))
Diag(MacroNameTok, diag::warn_pp_macro_hides_keyword);
}
// Check that there is no paste (##) operator at the beginning or end of the
// replacement list.
unsigned NumTokens = MI->getNumTokens();

View file

@ -184,11 +184,6 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// clang and gcc will pick the #if branch while Visual Studio will take the
// #else branch. Emit a warning about this undefined behavior.
if (beginLoc.isMacroID()) {
bool IsFunctionTypeMacro =
PP.getSourceManager()
.getSLocEntry(PP.getSourceManager().getFileID(beginLoc))
.getExpansion()
.isFunctionMacroExpansion();
// For object-type macros, it's easy to replace
// #define FOO defined(BAR)
// with
@ -204,10 +199,7 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// in a different way, and compilers seem to agree on how to behave here.
// So warn by default on object-type macros, but only warn in -pedantic
// mode on function-type macros.
if (IsFunctionTypeMacro)
PP.Diag(beginLoc, diag::warn_defined_in_function_type_macro);
else
PP.Diag(beginLoc, diag::warn_defined_in_object_type_macro);
PP.Diag(beginLoc, diag::warn_defined_in_macro);
}
// Invoke the 'defined' callback.

View file

@ -160,7 +160,7 @@ void dr106(void *p, int i) {
void dr108(void) {
#define const
const int i = 12;
#undef const
#undef const /* expected-warning {{keyword or identifier with special meaning is used as a macro name}} */
const int j = 12; /* expected-note {{variable 'j' declared const here}} */
i = 100; /* Okay, the keyword was hidden by the macro. */

View file

@ -216,7 +216,7 @@ void dr250(void) {
dr250_nothing(
#nondirective /* expected-error {{invalid preprocessing directive}}
expected-warning {{embedding a directive within macro arguments has undefined behavior}}
expected-warning {{embedding a #nondirective directive within macro arguments has undefined behavior}}
*/
)

View file

@ -0,0 +1,7 @@
// RUN: %clang_cc1 -std=c++26 -Wno-invalid-pp-token %s -fsyntax-only -verify
// [cpp.concat]/p3: If the result is not a valid
// preprocessing token, the program is ill-formed.
#define CONCAT(A, B) A ## B
CONCAT(=, >) // expected-error {{pasting formed '=>', an invalid preprocessing token}}
// expected-error@-1 {{expected unqualified-id}}

View file

@ -0,0 +1,12 @@
#ifndef WINBASE_H
#define WINBASE_H
#pragma clang system_header
#define MICROSOFT_WINDOWS_WINBASE_H_DEFINE_INTERLOCKED_CPLUSPLUS_OVERLOADS \
(_WIN32_WINNT >= 0x0502 || !defined(_WINBASE_))
#if MICROSOFT_WINDOWS_WINBASE_H_DEFINE_INTERLOCKED_CPLUSPLUS_OVERLOADS /* { */
#endif /* } */
#endif // WINBASE_H

View file

@ -0,0 +1,21 @@
// RUN: %clang_cc1 -std=c++26 %s -fsyntax-only -verify
// [cpp.cond]/p9: If the preprocessing token defined is generated as a result
// of this replacement process, the program is ill-formed, no diagnostic
// required.
#define DEFINED defined
#if DEFINED(bar) // expected-warning {{macro expansion producing 'defined' has undefined behavior}}
#endif
// Check that a real-world system header pattern remains accepted.
#include "Inputs/WinBase.h"
// [cpp.cond]/p9: If use of the defined unary operator does not match one of
// the two specified forms prior to macro replacement, the program is
// ill-formed, no diagnostic required.
#if defined() // expected-error {{macro name must be an identifier}}
#endif
#if defined(a b) // expected-error {{missing ')' after 'defined'}} expected-note {{to match this '('}}
#endif
#if defined(a, b) // expected-error {{missing ')' after 'defined'}} expected-note {{to match this '('}}
#endif

View file

@ -0,0 +1,7 @@
// RUN: %clang_cc1 -std=c++26 %s -fsyntax-only -verify
// [cpp.predefined]/p4: If any of the pre-defined macro names in this
// subclause, or the identifier defined, is the subject of a #define or a
// #undef preprocessing directive, the program is ill-formed.
#undef defined // expected-error {{'defined' cannot be used as a macro name}}
#undef __DATE__ // expected-warning {{undefining builtin macro}}

View file

@ -0,0 +1,24 @@
// RUN: %clang_cc1 -std=c++26 %s -fsyntax-only -verify
// RUN: %clang_cc1 -std=c++26 -pedantic-errors -DPEDANTIC_ERROR %s -fsyntax-only -verify
// [cpp.replace.general]/p14: If there are sequences of preprocessing tokens
// within the list of arguments that would otherwise act as preprocessing
// directives, the program is ill-formed.
#define FUNCTION_MACRO(...)
#if defined(PEDANTIC_ERROR)
FUNCTION_MACRO(
#if 0 // expected-error {{embedding a #if directive within macro arguments has undefined behavior}}
#endif
)
FUNCTION_MACRO(
# // expected-error {{embedding a # directive within macro arguments has undefined behavior}}
)
#else
FUNCTION_MACRO(
#if 0 // expected-warning {{embedding a #if directive within macro arguments has undefined behavior}}
#endif
)
FUNCTION_MACRO(
# // expected-warning {{embedding a # directive within macro arguments has undefined behavior}}
)
#endif

View file

@ -0,0 +1,44 @@
// RUN: %clang_cc1 -std=c++26 %s -fsyntax-only -verify
// RUN: %clang_cc1 -std=c++26 -pedantic-errors -DPEDANTIC_ERROR %s -fsyntax-only -verify
// [cpp.replace.general]/p9: A translation unit shall not #define or #undef
// macro names lexically identical to keywords ([lex.key]), to the identifiers
// listed in Table 4, or to the attribute-tokens described in [dcl.attr], except
// that the macro names likely and unlikely may be defined as function-like
// macros and may be undefined.
#if defined(PEDANTIC_ERROR)
#define for 0 // expected-error {{keyword is hidden by macro definition}}
#undef for // expected-error {{keyword or identifier with special meaning is used as a macro name}}
#define final 1 // expected-error {{keyword is hidden by macro definition}}
#undef final // expected-error {{keyword or identifier with special meaning is used as a macro name}}
#define override // expected-error {{keyword is hidden by macro definition}}
#undef override // expected-error {{keyword or identifier with special meaning is used as a macro name}}
#define const
#undef const // expected-error {{keyword or identifier with special meaning is used as a macro name}}
#else
#define for 0 // expected-warning {{keyword is hidden by macro definition}}
#undef for // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define final 1 // expected-warning {{keyword is hidden by macro definition}}
#undef final // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define override // expected-warning {{keyword is hidden by macro definition}}
#undef override // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define const
#undef const // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#endif
#define assume // expected-warning {{assume is a reserved attribute identifier}}
#undef assume // expected-warning {{assume is a reserved attribute identifier}}
#define nodiscard // expected-warning {{nodiscard is a reserved attribute identifier}}
#undef nodiscard // expected-warning {{nodiscard is a reserved attribute identifier}}
#define deprecated // expected-warning {{deprecated is a reserved attribute identifier}}
#undef deprecated // expected-warning {{deprecated is a reserved attribute identifier}}
#define likely // expected-warning {{likely is a reserved attribute identifier}}
#undef likely // expected-warning {{likely is a reserved attribute identifier}}
#define unlikely // expected-warning {{unlikely is a reserved attribute identifier}}
#undef unlikely // expected-warning {{unlikely is a reserved attribute identifier}}
#define likely(x) (x)
#define unlikely(x) (x)

View file

@ -19,21 +19,25 @@
// expected-no-diagnostics
// FIXME using `defined` in a macro has undefined behavior.
// An undefined feature-test macro evaluates to 0 in an #if expression, so
// `__cpp_##macro != N` tests the feature is defined with the exact value N
// when N is nonzero, and tests the feature is not defined (or is defined to 0,
// which feature-test macros never are) when N is 0. Avoiding `defined` inside
// a macro expansion is required for conformance with [cpp.cond].
#if __cplusplus < 201103L
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx98 == 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx98)
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (__cpp_##macro != cxx98)
#elif __cplusplus < 201402L
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx11 == 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx11)
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (__cpp_##macro != cxx11)
#elif __cplusplus < 201703L
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx14 == 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx14)
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (__cpp_##macro != cxx14)
#elif __cplusplus < 202002L
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx17 == 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx17)
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (__cpp_##macro != cxx17)
#elif __cplusplus < 202302L
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx20 == 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx20)
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (__cpp_##macro != cxx20)
#elif __cplusplus == 202302L
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx23 == 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx23)
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (__cpp_##macro != cxx23)
#else
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx26 == 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx26)
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (__cpp_##macro != cxx26)
#endif
// --- C++26 features ---

View file

@ -3,6 +3,7 @@
M1( // expected-error{{unterminated function-like macro invocation}}
// expected-warning@+1 {{embedding a #if directive within macro arguments has undefined behavior}}
#if M1() // expected-error{{expected value in expression}}
#endif
#pragma pack()

View file

@ -13,12 +13,8 @@
#define m_foo
#define TEST(a) (defined(m_##a) && a)
#if defined(PEDANTIC)
// expected-warning@+4{{macro expansion producing 'defined' has undefined behavior}}
#endif
// This shouldn't warn by default, only with pedantic:
#if TEST(foo)
// A function-like macro expansion producing 'defined' warns by default.
#if TEST(foo) // expected-warning {{macro expansion producing 'defined' has undefined behavior}}
#endif

View file

@ -5,8 +5,8 @@
#ifdef TEST1
#define assume
#undef assume
#define assume // expected-warning {{assume is a reserved attribute identifier}}
#undef assume // expected-warning {{assume is a reserved attribute identifier}}
#define noreturn // expected-warning {{noreturn is a reserved attribute identifier}}
#undef noreturn // expected-warning {{noreturn is a reserved attribute identifier}}
@ -37,8 +37,8 @@
#elif TEST2
#define assume "test"
#undef assume
#define assume "test" // expected-warning {{assume is a reserved attribute identifier}}
#undef assume // expected-warning {{assume is a reserved attribute identifier}}
#define noreturn "test" // expected-warning {{noreturn is a reserved attribute identifier}}
#undef noreturn // expected-warning {{noreturn is a reserved attribute identifier}}
@ -72,26 +72,26 @@
#define assume() "test" // expected-warning {{assume is a reserved attribute identifier}}
#define deprecated() "test" // expected-warning {{deprecated is a reserved attribute identifier}}
#define nodiscard() "test" // expected-warning {{nodiscard is a reserved attribute identifier}}
#define noreturn() "test"
#define carries_dependency() "test"
#define fallthrough() "test"
#define noreturn() "test" // expected-warning {{noreturn is a reserved attribute identifier}}
#define carries_dependency() "test" // expected-warning {{carries_dependency is a reserved attribute identifier}}
#define fallthrough() "test" // expected-warning {{fallthrough is a reserved attribute identifier}}
#define likely() "test"
#define no_unique_address() "test"
#define no_unique_address() "test" // expected-warning {{no_unique_address is a reserved attribute identifier}}
#define unlikely() "test"
#define maybe_unused() "test"
#define maybe_unused() "test" // expected-warning {{maybe_unused is a reserved attribute identifier}}
#elif TEST4
#define assume() // expected-warning {{assume is a reserved attribute identifier}}
#define deprecated() // expected-warning {{deprecated is a reserved attribute identifier}}
#define nodiscard() // expected-warning {{nodiscard is a reserved attribute identifier}}
#define noreturn()
#define carries_dependency()
#define fallthrough()
#define noreturn() // expected-warning {{noreturn is a reserved attribute identifier}}
#define carries_dependency() // expected-warning {{carries_dependency is a reserved attribute identifier}}
#define fallthrough() // expected-warning {{fallthrough is a reserved attribute identifier}}
#define likely()
#define no_unique_address()
#define no_unique_address() // expected-warning {{no_unique_address is a reserved attribute identifier}}
#define unlikely()
#define maybe_unused()
#define maybe_unused() // expected-warning {{maybe_unused is a reserved attribute identifier}}
#else

View file

@ -1,7 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -fms-extensions -verify %s
// expected-no-diagnostics
#define inline _inline
#undef inline
#undef inline // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
int x;

View file

@ -9,7 +9,7 @@
#define __STDC__ 1 // expected-warning {{redefining builtin macro}}
#define __clang__ 1
#undef for
#undef for // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#undef final
#undef __HAVE_X
#undef __cplusplus
@ -30,30 +30,30 @@
#define extern
#define inline
#undef while
#undef const
#undef static
#undef extern
#undef inline
#undef while // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#undef const // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#undef static // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#undef extern // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#undef inline // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define inline __inline
#undef inline
#undef inline // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define inline __inline__
#undef inline
#undef inline // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define inline inline__ // expected-warning {{keyword is hidden by macro definition}}
#undef inline
#undef inline // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define extern __inline // expected-warning {{keyword is hidden by macro definition}}
#undef extern
#undef extern // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define extern __extern // expected-warning {{keyword is hidden by macro definition}}
#undef extern
#undef extern // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define extern __extern__ // expected-warning {{keyword is hidden by macro definition}}
#undef extern
#undef extern // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define inline _inline // expected-warning {{keyword is hidden by macro definition}}
#undef inline
#undef inline // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define volatile // expected-warning {{keyword is hidden by macro definition}}
#undef volatile
#undef volatile // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#pragma clang diagnostic warning "-Wreserved-macro-identifier"
@ -64,7 +64,7 @@
#define _HAVE_X 0 // expected-warning {{macro name is a reserved identifier}}
#define X__Y
#undef switch
#undef switch // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#undef final
#undef __cplusplus // expected-warning {{macro name is a reserved identifier}}
#undef _HAVE_X // expected-warning {{macro name is a reserved identifier}}

View file

@ -6,7 +6,7 @@
#define _HAVE_X 0
#define X__Y
#undef for
#undef for // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#undef final
#undef __HAVE_X
#undef _HAVE_X
@ -22,30 +22,30 @@
#define extern
#define inline
#undef while
#undef const
#undef static
#undef extern
#undef inline
#undef while // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#undef const // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#undef static // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#undef extern // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#undef inline // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define inline __inline
#undef inline
#undef inline // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define inline __inline__
#undef inline
#undef inline // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define inline inline__ // expected-warning {{keyword is hidden by macro definition}}
#undef inline
#undef inline // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define extern __inline // expected-warning {{keyword is hidden by macro definition}}
#undef extern
#undef extern // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define extern __extern // expected-warning {{keyword is hidden by macro definition}}
#undef extern
#undef extern // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define extern __extern__ // expected-warning {{keyword is hidden by macro definition}}
#undef extern
#undef extern // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define inline _inline // expected-warning {{keyword is hidden by macro definition}}
#undef inline
#undef inline // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#define volatile // expected-warning {{keyword is hidden by macro definition}}
#undef volatile
#undef volatile // expected-warning {{keyword or identifier with special meaning is used as a macro name}}
#pragma clang diagnostic warning "-Wreserved-macro-identifier"

View file

@ -2,8 +2,8 @@
#define a(x) enum { x }
a(n =
#undef a
#define a 5
#undef a // expected-warning {{embedding a #undef directive within macro arguments has undefined behavior}}
#define a 5 // expected-warning {{embedding a #define directive within macro arguments has undefined behavior}}
a);
_Static_assert(n == 5, "");

View file

@ -2,11 +2,7 @@
// RUN: %clang_cc1 %s -Eonly -std=c99 -verify=undef-true
// RUN: %clang_cc1 %s -Eonly -std=c11 -verify=undef-true
// RUN: %clang_cc1 %s -Eonly -std=c17 -verify=undef-true
// RUN: %clang_cc1 %s -Eonly -std=c23 -verify=undef-true
#if __STDC_VERSION__ >= 202311L
/* undef-true-no-diagnostics */
#endif
// RUN: %clang_cc1 %s -Eonly -std=c23 -verify=undef-true,c23-keyword
#define FOO true
#if FOO /* #1 */
@ -27,7 +23,7 @@
/* undef-true-warning@#3 {{'true' is not defined, evaluates to 0}} */
#endif
#define true 1
#define true 1 /* c23-keyword-warning {{keyword is hidden by macro definition}} */
#define FOO true
#if FOO
@ -39,7 +35,7 @@
#if false || true
#endif
#undef true
#undef true /* c23-keyword-warning {{keyword or identifier with special meaning is used as a macro name}} */
#define FOO true
#if FOO /* #4 */
@ -66,7 +62,7 @@
#if __STDC_VERSION__ < 202311L
/* undef-true-warning@#7 {{'true' is not defined, evaluates to 0}} */
#endif
#undef true
#undef true /* c23-keyword-warning {{keyword or identifier with special meaning is used as a macro name}} */
/* Test that #pragma-enabled 'Wundef' can override 'Wundef-true' */
#pragma clang diagnostic warning "-Wundef"

View file

@ -200,10 +200,10 @@ int import;
int override;
int final;
// We do not diagnose use of C++ keywords when used as a macro name because
// that does not conflict with C++ (the macros will be replaced before the
// keyword is seen by the parser).
#define this 12
// In C mode, we do not diagnose use of C++ keywords when used as a macro name
// because that does not conflict with C++ (the macros will be replaced before
// the keyword is seen by the parser).
#define this 12 // cxx-warning {{keyword is hidden by macro definition}}
// FIXME: These tests are disabled for C++ because it causes a crash.
// See GH114815.

View file

@ -84,7 +84,7 @@ static_assert(0, "0 is nonzero"); // ms-error {{static assertion failed: 0 is no
#define assert(expr)
static_assert(1, "1 is nonzero"); // ok
#undef static_assert
#undef static_assert // ms-warning {{keyword or identifier with special meaning is used as a macro name}}
static_assert(1, "1 is nonzero"); // yes, still ok.
#endif

View file

@ -2,8 +2,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify=pedantic -pedantic %s
// RUN: %clang_cc1 -fsyntax-only -verify=cpp -x c++ %s
// cuda-no-diagnostics
__noinline__ void fun1() { } // cpp-error {{unknown type name '__noinline__'}}
__attribute__((noinline)) void fun2() { }
@ -13,7 +11,8 @@ __attribute__((__noinline__)) void fun3() { }
#define __noinline__ __attribute__((__noinline__))
__noinline__ void fun5() {}
#undef __noinline__
#undef __noinline__ // cuda-warning {{keyword or identifier with special meaning is used as a macro name}} \
// pedantic-warning {{keyword or identifier with special meaning is used as a macro name}}
#10 "cuda.h" 3 // pedantic-warning {{this style of line directive is a GNU extension}}
#define __noinline__ __attribute__((__noinline__))
__noinline__ void fun6() {}

View file

@ -4,6 +4,7 @@
#define __CONCAT(__X, __Y) __CONCAT1(__X, __Y)
#define __CONCAT1(__X, __Y) __X ## __Y
// expected-warning@+1 {{keyword is hidden by macro definition}}
#define static_assert(__b, __m) \
typedef int __CONCAT(__sa, __LINE__)[__b ? 1 : -1]
#endif

View file

@ -26,7 +26,7 @@
// c-error@-4 {{does not have the constexpr builtin}}
#if __cplusplus < 201103L
#define static_assert __extension__ _Static_assert
#define static_assert __extension__ _Static_assert // c-warning {{keyword is hidden by macro definition}}
#define CONSTEXPR11
#else
#define CONSTEXPR11 constexpr

View file

@ -2,7 +2,7 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++1y -DCXX1Y -Wc++98-compat -Werror %s -DCXX1Y2
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -verify %s
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -Werror %s
// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror %s -DCXX98
// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror -Wno-gnu-zero-line-directive %s -DCXX98
// RUN: %clang_cc1 -fsyntax-only -std=c++1y -Wc++98-compat-pedantic -verify %s -Wno-pre-c++14-compat-pedantic -DCXX1Y2

View file

@ -1,10 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
// expected-no-diagnostics
#ifndef __GXX_EXPERIMENTAL_CXX0X__
#define __CONCAT(__X, __Y) __CONCAT1(__X, __Y)
#define __CONCAT1(__X, __Y) __X ## __Y
// expected-warning@+1 {{keyword is hidden by macro definition}}
#define static_assert(__b, __m) \
typedef int __CONCAT(__sa, __LINE__)[__b ? 1 : -1]
#endif

View file

@ -330,7 +330,7 @@ C++23, informally referred to as C++26.</p>
<tr>
<td>Preprocessing is never undefined</td>
<td><a href="https://wg21.link/P2843">P2843R3</a></td>
<td class="none" align="center">No</td>
<td class="full" align="center">Yes</td>
</tr>
<!-- Kona, Fall 2025-->
<tr>