]> granicus.if.org Git - clang/commitdiff
Emit an extension warning when changing system header tokens
authorAlp Toker <alp@nuanti.com>
Tue, 3 Dec 2013 06:13:01 +0000 (06:13 +0000)
committerAlp Toker <alp@nuanti.com>
Tue, 3 Dec 2013 06:13:01 +0000 (06:13 +0000)
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;

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196212 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Parse/Parser.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/Parser.cpp
test/PCH/cxx-traits.cpp
test/PCH/cxx-traits.h
test/Sema/Inputs/ms-keyword-system-header.h
test/Sema/ms-keyword-system-header.c

index 6de1a48d9f9dbd9f62e0acf8ee2b4ef8a214f5c6..ec1eb1a8b59daf37a168f55ed38752f3961a98b7 100644 (file)
@@ -50,6 +50,7 @@ def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">;
 def C99Compat : DiagGroup<"c99-compat">;
 def CXXCompat: DiagGroup<"c++-compat">;
 def ExternCCompat : DiagGroup<"extern-c-compat">;
+def KeywordCompat : DiagGroup<"keyword-compat">;
 def GNUCaseRange : DiagGroup<"gnu-case-range">;
 def CastAlign : DiagGroup<"cast-align">;
 def : DiagGroup<"cast-qual">;
index 4d0641de5493412852001c38c370ce8169a6caec..2feab52ef4d1887dd7af3c38173c56c4fe4cc1ca 100644 (file)
@@ -58,6 +58,9 @@ def ext_plain_complex : ExtWarn<
 def ext_integer_complex : Extension<
   "complex integer types are a GNU extension">, InGroup<GNUComplexInteger>;
 def ext_thread_before : Extension<"'__thread' before '%0'">;
+def ext_keyword_as_ident : ExtWarn<
+  "keyword '%0' will be treated as an identifier %select{here|for the remainder of the translation unit}1">,
+  InGroup<KeywordCompat>;
 
 def error_empty_enum : Error<"use of empty enum">;
 def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">;
index 8807e3b47b7616cbcfa8572e1a129ed1b1bb7675..81ba5e1882ee217546ace55fec8a95af36e6f2a7 100644 (file)
@@ -563,6 +563,13 @@ private:
                                 const char *&PrevSpec, unsigned &DiagID,
                                 bool &isInvalid);
 
+  /// TryKeywordIdentFallback - For compatibility with system headers using
+  /// keywords as identifiers, attempt to convert the current token to an
+  /// identifier and optionally disable the keyword for the remainder of the
+  /// translation unit. This returns false if the token was not replaced,
+  /// otherwise emits a diagnostic and returns true.
+  bool TryKeywordIdentFallback(bool DisableKeyword);
+
   /// \brief Get the TemplateIdAnnotation from the token.
   TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok);
 
index 881e2252fd41356a0a31e2654ec4082a9b205d03..4fce10fc32fc235ebb1c8e0fed78050debc8a296 100644 (file)
@@ -2739,10 +2739,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
       // then treat __is_signed as an identifier rather than as a keyword.
       if (DS.getTypeSpecType() == TST_bool &&
           DS.getTypeQualifiers() == DeclSpec::TQ_const &&
-          DS.getStorageClassSpec() == DeclSpec::SCS_static) {
-        Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
-        Tok.setKind(tok::identifier);
-      }
+          DS.getStorageClassSpec() == DeclSpec::SCS_static)
+        TryKeywordIdentFallback(true);
 
       // We're done with the declaration-specifiers.
       goto DoneWithDeclSpec;
@@ -4488,10 +4486,9 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
       // GNU libc headers in C mode use '__uptr' as an identifer which conflicts
       // with the MS modifier keyword.
       if (VendorAttributesAllowed && !getLangOpts().CPlusPlus &&
-          IdentifierRequired && DS.isEmpty() && NextToken().is(tok::semi) &&
-          PP.getSourceManager().isInSystemHeader(Loc)) {
-        Tok.setKind(tok::identifier);
-        continue;
+          IdentifierRequired && DS.isEmpty() && NextToken().is(tok::semi)) {
+        if (TryKeywordIdentFallback(false))
+          continue;
       }
     case tok::kw___sptr:
     case tok::kw___w64:
index 32e151cf2c29eb240a33040cad920b3407c9d8d4..d4a4ded252bd647a92af9f591148e4b4984c71c4 100644 (file)
@@ -1198,15 +1198,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
        Tok.is(tok::kw___is_scalar) ||
        Tok.is(tok::kw___is_signed) ||
        Tok.is(tok::kw___is_unsigned) ||
-       Tok.is(tok::kw___is_void))) {
+       Tok.is(tok::kw___is_void)))
     // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
     // name of struct templates, but some are keywords in GCC >= 4.3
     // and Clang. Therefore, when we see the token sequence "struct
     // X", make X into a normal identifier rather than a keyword, to
     // allow libstdc++ 4.2 and libc++ to work properly.
-    Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
-    Tok.setKind(tok::identifier);
-  }
+    TryKeywordIdentFallback(true);
 
   // Parse the (optional) nested-name-specifier.
   CXXScopeSpec &SS = DS.getTypeSpecScope();
index 0f950ceabc556901a113a76cc840679584cb6205..59ffc0562aac52bbad382d1f24fd4d362ec43900 100644 (file)
@@ -1517,6 +1517,17 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
   return ANK_Unresolved;
 }
 
+bool Parser::TryKeywordIdentFallback(bool DisableKeyword) {
+  assert(Tok.isNot(tok::identifier));
+  Diag(Tok, diag::ext_keyword_as_ident)
+    << PP.getSpelling(Tok)
+    << DisableKeyword;
+  if (DisableKeyword)
+    Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
+  Tok.setKind(tok::identifier);
+  return true;
+}
+
 /// TryAnnotateTypeOrScopeToken - If the current token position is on a
 /// typename (possibly qualified in C++) or a C++ scope specifier not followed
 /// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
index 938f36f2c2791dfacdf3b8ce011f620c3ed31485..ffdfccc6f47f47254a3419b69b8bc10014346fe7 100644 (file)
@@ -2,9 +2,11 @@
 // RUN: %clang_cc1 -include %S/cxx-traits.h -std=c++11 -fsyntax-only -verify %s
 
 // RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -o %t %S/cxx-traits.h
-// RUN: %clang_cc1 -std=c++11 -include-pch %t -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -DPCH -fsyntax-only -verify %s
 
+#ifdef PCH
 // expected-no-diagnostics
+#endif
 
 bool _Is_pod_comparator = __is_pod<int>::__value;
 bool _Is_empty_check = __is_empty<int>::__value;
index 8b62002789d6f829294534f14ad2ded9c97c1b69..836804ef2c88f2011bce4dfa684fe7d94076039b 100644 (file)
@@ -1,12 +1,12 @@
 // Header for PCH test cxx-traits.cpp
 
 template<typename _Tp>
-struct __is_pod {
+struct __is_pod { // expected-warning {{keyword '__is_pod' will be treated as an identifier for the remainder of the translation unit}}
   enum { __value };
 };
 
 template<typename _Tp>
-struct __is_empty {
+struct __is_empty { // expected-warning {{keyword '__is_empty' will be treated as an identifier for the remainder of the translation unit}}
   enum { __value };
 };
 
index 13cfe3a6ea326dc9740c1e0fc9fd0f73e8604afd..43a3db7a12ba470dd1c186388c0777de02afdc35 100644 (file)
@@ -2,5 +2,8 @@
 
 typedef union {
   union w *__uptr;
+#if defined(MS) && defined(NOT_SYSTEM)
+  // expected-warning@-2 {{keyword '__uptr' will be treated as an identifier here}}
+#endif
   int *__iptr;
 } WS __attribute__((__transparent_union__));
index bf7a9f4c8e4b3fed95ce5ef63a0172e5200b8a4b..b4ff5683cdfd297295ceb4cf6d38c0a18891693d 100644 (file)
@@ -1,4 +1,6 @@
 // RUN: %clang_cc1 -fms-extensions -D MS -isystem %S/Inputs %s -fsyntax-only -verify
+// RUN: %clang_cc1 -fms-extensions -D MS -Wno-keyword-compat -I %S/Inputs %s -fsyntax-only -verify
+// RUN: %clang_cc1 -fms-extensions -D MS -D NOT_SYSTEM -I %S/Inputs %s -fsyntax-only -verify
 // RUN: %clang_cc1 -isystem %S/Inputs %s -fsyntax-only -verify
 
 // PR17824: GNU libc uses MS keyword __uptr as an identifier in C mode