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:
parent
a9ceabab84
commit
22e8c55ccf
29 changed files with 246 additions and 115 deletions
|
|
@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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}}
|
||||
*/
|
||||
)
|
||||
|
||||
|
|
|
|||
7
clang/test/CXX/cpp/cpp.concat/p3.cpp
Normal file
7
clang/test/CXX/cpp/cpp.concat/p3.cpp
Normal 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}}
|
||||
12
clang/test/CXX/cpp/cpp.cond/Inputs/WinBase.h
Normal file
12
clang/test/CXX/cpp/cpp.cond/Inputs/WinBase.h
Normal 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
|
||||
21
clang/test/CXX/cpp/cpp.cond/p9.cpp
Normal file
21
clang/test/CXX/cpp/cpp.cond/p9.cpp
Normal 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
|
||||
7
clang/test/CXX/cpp/cpp.predefined/p4.cpp
Normal file
7
clang/test/CXX/cpp/cpp.predefined/p4.cpp
Normal 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}}
|
||||
24
clang/test/CXX/cpp/cpp.replace.general/p14.cpp
Normal file
24
clang/test/CXX/cpp/cpp.replace.general/p14.cpp
Normal 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
|
||||
44
clang/test/CXX/cpp/cpp.replace.general/p9.cpp
Normal file
44
clang/test/CXX/cpp/cpp.replace.general/p9.cpp
Normal 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)
|
||||
|
|
@ -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 ---
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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}}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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, "");
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue