majnemer created this revision.
majnemer added reviewers: rsmith, rnk.
majnemer added a subscriber: cfe-commits.

MSVC 2013 ships, as part of its STL implementation, a class named
'_Atomic'.  This is unfortunate because this keyword is in conflict with
the C11 keyword with the same name.  Our solution was to disable this
keyword when targeting MSVC 2013 and reenable it for 2015.

However, this makes it impossible for clang's headers to make use of
_Atomic.  This is problematic in the case of libc++ as it makes heavy
use of this keyword.

Let the keywordness of _Atomic float under certain circumstances:
the body of a class named _Atomic, or a class with a base specifier
named _Atomic, will not have the keyword variant of _Atomic for the
duration of the class body.  This is sufficient to allow us to correctly
handle _Atomic in the STL while permitting us to use _Atomic as a
keyword everywhere else.

http://reviews.llvm.org/D11233

Files:
  include/clang/Basic/IdentifierTable.h
  include/clang/Basic/TokenKinds.def
  include/clang/Parse/Parser.h
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/Parser.cpp
  test/SemaCXX/MicrosoftCompatibility.cpp

Index: test/SemaCXX/MicrosoftCompatibility.cpp
===================================================================
--- test/SemaCXX/MicrosoftCompatibility.cpp
+++ test/SemaCXX/MicrosoftCompatibility.cpp
@@ -9,11 +9,8 @@
 typedef unsigned int char32_t;
 #endif
 
-#if _MSC_VER >= 1900
 _Atomic(int) z;
-#else
 struct _Atomic {};
-#endif
 
 typename decltype(3) a; // expected-warning {{expected a qualified name after 'typename'}}
 
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -517,6 +517,8 @@
     PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block);
   }
 
+  Ident__Atomic = nullptr;
+
   Actions.Initialize();
 
   // Prime the lexer look-ahead.
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -1307,6 +1307,37 @@
     // allow libstdc++ 4.2 and libc++ to work properly.
     TryKeywordIdentFallback(true);
 
+  struct PreserveIdentifierInfoRAII {
+    void set(IdentifierInfo *ToPreserve) {
+      II = ToPreserve;
+      TK = II->getTokenID();
+    }
+    ~PreserveIdentifierInfoRAII() {
+      if (II) {
+        if (TK == tok::identifier && II->getTokenID() != tok::identifier)
+          II->RevertTokenIDToIdentifier();
+        else if (TK != tok::identifier && II->getTokenID() == tok::identifier)
+          II->RevertIdentifierToTokenID(TK);
+      }
+    }
+    IdentifierInfo *II = nullptr;
+    tok::TokenKind TK;
+  };
+
+  PreserveIdentifierInfoRAII AtomicTokenGuard;
+  if (getLangOpts().MSVCCompat) {
+    if (!Ident__Atomic)
+      Ident__Atomic = &PP.getIdentifierTable().get("_Atomic");
+    AtomicTokenGuard.set(Ident__Atomic);
+  }
+
+  if (getLangOpts().MSVCCompat && TagType == DeclSpec::TST_struct &&
+      Tok.isNot(tok::identifier) && !Tok.isAnnotation() &&
+      Tok.getIdentifierInfo() && Tok.is(tok::kw__Atomic)) {
+    Ident__Atomic->RevertTokenIDToIdentifier();
+    Tok.setKind(tok::identifier);
+  }
+
   // Parse the (optional) nested-name-specifier.
   CXXScopeSpec &SS = DS.getTypeSpecScope();
   if (getLangOpts().CPlusPlus) {
@@ -1858,6 +1889,12 @@
   CheckMisplacedCXX11Attribute(Attributes, StartLoc);
 
   // Parse the class-name.
+  if (getLangOpts().MSVCCompat && Tok.isNot(tok::identifier) &&
+      !Tok.isAnnotation() && Tok.getIdentifierInfo() &&
+      Tok.is(tok::kw__Atomic)) {
+    Ident__Atomic->RevertTokenIDToIdentifier();
+    Tok.setKind(tok::identifier);
+  }
   SourceLocation EndLocation;
   SourceLocation BaseLoc;
   TypeResult BaseType = ParseBaseTypeSpecifier(BaseLoc, EndLocation);
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -137,6 +137,9 @@
   mutable IdentifierInfo *Ident_final;
   mutable IdentifierInfo *Ident_override;
 
+  /// \brief Identifier for "_Atomic".
+  IdentifierInfo *Ident__Atomic;
+
   // C++ type trait keywords that can be reverted to identifiers and still be
   // used as type traits.
   llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind> RevertibleTypeTraits;
Index: include/clang/Basic/TokenKinds.def
===================================================================
--- include/clang/Basic/TokenKinds.def
+++ include/clang/Basic/TokenKinds.def
@@ -280,7 +280,7 @@
 KEYWORD(while                       , KEYALL)
 KEYWORD(_Alignas                    , KEYALL)
 KEYWORD(_Alignof                    , KEYALL)
-KEYWORD(_Atomic                     , KEYALL|KEYNOMS18|KEYNOOPENCL)
+KEYWORD(_Atomic                     , KEYALL|KEYNOOPENCL)
 KEYWORD(_Bool                       , KEYNOCXX)
 KEYWORD(_Complex                    , KEYALL)
 KEYWORD(_Generic                    , KEYALL)
Index: include/clang/Basic/IdentifierTable.h
===================================================================
--- include/clang/Basic/IdentifierTable.h
+++ include/clang/Basic/IdentifierTable.h
@@ -166,6 +166,11 @@
     TokenID = tok::identifier;
     RevertedTokenID = true;
   }
+  void RevertIdentifierToTokenID(tok::TokenKind TK) {
+    assert(TokenID == tok::identifier && "Should be at tok::identifier");
+    TokenID = TK;
+    RevertedTokenID = false;
+  }
 
   /// \brief Return the preprocessor keyword ID for this identifier.
   ///
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to