Index: cfe/trunk/include/clang/Basic/IdentifierTable.h =================================================================== --- cfe/trunk/include/clang/Basic/IdentifierTable.h +++ cfe/trunk/include/clang/Basic/IdentifierTable.h @@ -62,7 +62,7 @@ // partially) from an AST file. bool ChangedAfterLoad : 1; // True if identifier has changed from the // definition loaded from an AST file. - bool RevertedTokenID : 1; // True if RevertTokenIDToIdentifier was + bool RevertedTokenID : 1; // True if revertTokenIDToIdentifier was // called. bool OutOfDate : 1; // True if there may be additional // information about this identifier @@ -152,7 +152,7 @@ /// tokens. tok::TokenKind getTokenID() const { return (tok::TokenKind)TokenID; } - /// \brief True if RevertTokenIDToIdentifier() was called. + /// \brief True if revertTokenIDToIdentifier() was called. bool hasRevertedTokenIDToIdentifier() const { return RevertedTokenID; } /// \brief Revert TokenID to tok::identifier; used for GNU libstdc++ 4.2 @@ -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. /// Index: cfe/trunk/include/clang/Basic/TokenKinds.def =================================================================== --- cfe/trunk/include/clang/Basic/TokenKinds.def +++ cfe/trunk/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: cfe/trunk/lib/Parse/ParseDecl.cpp =================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp +++ cfe/trunk/lib/Parse/ParseDecl.cpp @@ -2647,6 +2647,18 @@ const char *PrevSpec = nullptr; unsigned DiagID = 0; + // HACK: MSVC doesn't consider _Atomic to be a keyword and its STL + // implementation for VS2013 uses _Atomic as an identifier for one of the + // classes in . + // + // A typedef declaration containing _Atomic<...> is among the places where + // the class is used. If we are currently parsing such a declaration, treat + // the token as an identifier. + if (getLangOpts().MSVCCompat && Tok.is(tok::kw__Atomic) && + DS.getStorageClassSpec() == clang::DeclSpec::SCS_typedef && + !DS.hasTypeSpecifier() && GetLookAheadToken(1).is(tok::less)) + Tok.setKind(tok::identifier); + SourceLocation Loc = Tok.getLocation(); switch (Tok.getKind()) { Index: cfe/trunk/lib/Parse/ParseDeclCXX.cpp =================================================================== --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp @@ -1308,6 +1308,35 @@ // allow libstdc++ 4.2 and libc++ to work properly. TryKeywordIdentFallback(true); + struct PreserveAtomicIdentifierInfoRAII { + PreserveAtomicIdentifierInfoRAII(Token &Tok, bool Enabled) + : AtomicII(nullptr) { + if (!Enabled) + return; + assert(Tok.is(tok::kw__Atomic)); + AtomicII = Tok.getIdentifierInfo(); + AtomicII->revertTokenIDToIdentifier(); + Tok.setKind(tok::identifier); + } + ~PreserveAtomicIdentifierInfoRAII() { + if (!AtomicII) + return; + AtomicII->revertIdentifierToTokenID(tok::kw__Atomic); + } + IdentifierInfo *AtomicII; + }; + + // HACK: MSVC doesn't consider _Atomic to be a keyword and its STL + // implementation for VS2013 uses _Atomic as an identifier for one of the + // classes in . When we are parsing 'struct _Atomic', don't consider + // '_Atomic' to be a keyword. We are careful to undo this so that clang can + // use '_Atomic' in its own header files. + bool ShouldChangeAtomicToIdentifier = getLangOpts().MSVCCompat && + Tok.is(tok::kw__Atomic) && + TagType == DeclSpec::TST_struct; + PreserveAtomicIdentifierInfoRAII AtomicTokenGuard( + Tok, ShouldChangeAtomicToIdentifier); + // Parse the (optional) nested-name-specifier. CXXScopeSpec &SS = DS.getTypeSpecScope(); if (getLangOpts().CPlusPlus) { @@ -1859,6 +1888,15 @@ CheckMisplacedCXX11Attribute(Attributes, StartLoc); // Parse the class-name. + + // HACK: MSVC doesn't consider _Atomic to be a keyword and its STL + // implementation for VS2013 uses _Atomic as an identifier for one of the + // classes in . Treat '_Atomic' to be an identifier when we are + // parsing the class-name for a base specifier. + if (getLangOpts().MSVCCompat && Tok.is(tok::kw__Atomic) && + NextToken().is(tok::less)) + Tok.setKind(tok::identifier); + SourceLocation EndLocation; SourceLocation BaseLoc; TypeResult BaseType = ParseBaseTypeSpecifier(BaseLoc, EndLocation); Index: cfe/trunk/test/SemaCXX/MicrosoftCompatibility.cpp =================================================================== --- cfe/trunk/test/SemaCXX/MicrosoftCompatibility.cpp +++ cfe/trunk/test/SemaCXX/MicrosoftCompatibility.cpp @@ -9,11 +9,18 @@ typedef unsigned int char32_t; #endif -#if _MSC_VER >= 1900 _Atomic(int) z; -#else -struct _Atomic {}; -#endif +template +struct _Atomic { + _Atomic() {} + ~_Atomic() {} +}; +template +struct atomic : _Atomic { + typedef _Atomic TheBase; + TheBase field; +}; +_Atomic(int) alpha; typename decltype(3) a; // expected-warning {{expected a qualified name after 'typename'}}