Skip to content

Commit 47642d2

Browse files
committed
Emit an extension warning when changing system header tokens
clang converts keywords to identifiers for compatibility with various system headers such as GNU libc. Implement a -Wkeyword-compat extension warning to diagnose those cases. The warning is on by default but will generally be ignored in system headers. It can however be enabled globally to aid standards conformance testing. This also changes the __uptr keyword avoidance from r195710 to no longer special-case system headers, bringing it in line with other similar workarounds in clang. Implementation returns bool for symmetry with token annotation functions. Some examples: warning: keyword '__is_pod' will be treated as an identifier for the remainder of the translation unit [-Wkeyword-compat] struct __is_pod warning: keyword '__uptr' will be treated as an identifier here [-Wkeyword-compat] union w *__uptr; llvm-svn: 196212
1 parent a5246fd commit 47642d2

File tree

10 files changed

+39
-15
lines changed

10 files changed

+39
-15
lines changed

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">;
5050
def C99Compat : DiagGroup<"c99-compat">;
5151
def CXXCompat: DiagGroup<"c++-compat">;
5252
def ExternCCompat : DiagGroup<"extern-c-compat">;
53+
def KeywordCompat : DiagGroup<"keyword-compat">;
5354
def GNUCaseRange : DiagGroup<"gnu-case-range">;
5455
def CastAlign : DiagGroup<"cast-align">;
5556
def : DiagGroup<"cast-qual">;

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ def ext_plain_complex : ExtWarn<
5858
def ext_integer_complex : Extension<
5959
"complex integer types are a GNU extension">, InGroup<GNUComplexInteger>;
6060
def ext_thread_before : Extension<"'__thread' before '%0'">;
61+
def ext_keyword_as_ident : ExtWarn<
62+
"keyword '%0' will be treated as an identifier %select{here|for the remainder of the translation unit}1">,
63+
InGroup<KeywordCompat>;
6164

6265
def error_empty_enum : Error<"use of empty enum">;
6366
def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">;

clang/include/clang/Parse/Parser.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,13 @@ class Parser : public CodeCompletionHandler {
563563
const char *&PrevSpec, unsigned &DiagID,
564564
bool &isInvalid);
565565

566+
/// TryKeywordIdentFallback - For compatibility with system headers using
567+
/// keywords as identifiers, attempt to convert the current token to an
568+
/// identifier and optionally disable the keyword for the remainder of the
569+
/// translation unit. This returns false if the token was not replaced,
570+
/// otherwise emits a diagnostic and returns true.
571+
bool TryKeywordIdentFallback(bool DisableKeyword);
572+
566573
/// \brief Get the TemplateIdAnnotation from the token.
567574
TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok);
568575

clang/lib/Parse/ParseDecl.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2739,10 +2739,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
27392739
// then treat __is_signed as an identifier rather than as a keyword.
27402740
if (DS.getTypeSpecType() == TST_bool &&
27412741
DS.getTypeQualifiers() == DeclSpec::TQ_const &&
2742-
DS.getStorageClassSpec() == DeclSpec::SCS_static) {
2743-
Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
2744-
Tok.setKind(tok::identifier);
2745-
}
2742+
DS.getStorageClassSpec() == DeclSpec::SCS_static)
2743+
TryKeywordIdentFallback(true);
27462744

27472745
// We're done with the declaration-specifiers.
27482746
goto DoneWithDeclSpec;
@@ -4488,10 +4486,9 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
44884486
// GNU libc headers in C mode use '__uptr' as an identifer which conflicts
44894487
// with the MS modifier keyword.
44904488
if (VendorAttributesAllowed && !getLangOpts().CPlusPlus &&
4491-
IdentifierRequired && DS.isEmpty() && NextToken().is(tok::semi) &&
4492-
PP.getSourceManager().isInSystemHeader(Loc)) {
4493-
Tok.setKind(tok::identifier);
4494-
continue;
4489+
IdentifierRequired && DS.isEmpty() && NextToken().is(tok::semi)) {
4490+
if (TryKeywordIdentFallback(false))
4491+
continue;
44954492
}
44964493
case tok::kw___sptr:
44974494
case tok::kw___w64:

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,15 +1198,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
11981198
Tok.is(tok::kw___is_scalar) ||
11991199
Tok.is(tok::kw___is_signed) ||
12001200
Tok.is(tok::kw___is_unsigned) ||
1201-
Tok.is(tok::kw___is_void))) {
1201+
Tok.is(tok::kw___is_void)))
12021202
// GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
12031203
// name of struct templates, but some are keywords in GCC >= 4.3
12041204
// and Clang. Therefore, when we see the token sequence "struct
12051205
// X", make X into a normal identifier rather than a keyword, to
12061206
// allow libstdc++ 4.2 and libc++ to work properly.
1207-
Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
1208-
Tok.setKind(tok::identifier);
1209-
}
1207+
TryKeywordIdentFallback(true);
12101208

12111209
// Parse the (optional) nested-name-specifier.
12121210
CXXScopeSpec &SS = DS.getTypeSpecScope();

clang/lib/Parse/Parser.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,6 +1517,17 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
15171517
return ANK_Unresolved;
15181518
}
15191519

1520+
bool Parser::TryKeywordIdentFallback(bool DisableKeyword) {
1521+
assert(Tok.isNot(tok::identifier));
1522+
Diag(Tok, diag::ext_keyword_as_ident)
1523+
<< PP.getSpelling(Tok)
1524+
<< DisableKeyword;
1525+
if (DisableKeyword)
1526+
Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
1527+
Tok.setKind(tok::identifier);
1528+
return true;
1529+
}
1530+
15201531
/// TryAnnotateTypeOrScopeToken - If the current token position is on a
15211532
/// typename (possibly qualified in C++) or a C++ scope specifier not followed
15221533
/// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens

clang/test/PCH/cxx-traits.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
// RUN: %clang_cc1 -include %S/cxx-traits.h -std=c++11 -fsyntax-only -verify %s
33

44
// RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -o %t %S/cxx-traits.h
5-
// RUN: %clang_cc1 -std=c++11 -include-pch %t -fsyntax-only -verify %s
5+
// RUN: %clang_cc1 -std=c++11 -include-pch %t -DPCH -fsyntax-only -verify %s
66

7+
#ifdef PCH
78
// expected-no-diagnostics
9+
#endif
810

911
bool _Is_pod_comparator = __is_pod<int>::__value;
1012
bool _Is_empty_check = __is_empty<int>::__value;

clang/test/PCH/cxx-traits.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Header for PCH test cxx-traits.cpp
22

33
template<typename _Tp>
4-
struct __is_pod {
4+
struct __is_pod { // expected-warning {{keyword '__is_pod' will be treated as an identifier for the remainder of the translation unit}}
55
enum { __value };
66
};
77

88
template<typename _Tp>
9-
struct __is_empty {
9+
struct __is_empty { // expected-warning {{keyword '__is_empty' will be treated as an identifier for the remainder of the translation unit}}
1010
enum { __value };
1111
};
1212

clang/test/Sema/Inputs/ms-keyword-system-header.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@
22

33
typedef union {
44
union w *__uptr;
5+
#if defined(MS) && defined(NOT_SYSTEM)
6+
// expected-warning@-2 {{keyword '__uptr' will be treated as an identifier here}}
7+
#endif
58
int *__iptr;
69
} WS __attribute__((__transparent_union__));

clang/test/Sema/ms-keyword-system-header.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
// RUN: %clang_cc1 -fms-extensions -D MS -isystem %S/Inputs %s -fsyntax-only -verify
2+
// RUN: %clang_cc1 -fms-extensions -D MS -Wno-keyword-compat -I %S/Inputs %s -fsyntax-only -verify
3+
// RUN: %clang_cc1 -fms-extensions -D MS -D NOT_SYSTEM -I %S/Inputs %s -fsyntax-only -verify
24
// RUN: %clang_cc1 -isystem %S/Inputs %s -fsyntax-only -verify
35

46
// PR17824: GNU libc uses MS keyword __uptr as an identifier in C mode

0 commit comments

Comments
 (0)