diff options
39 files changed, 483 insertions, 9 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index a18a45eb40..09defdb31e 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -120,6 +120,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> { mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes; mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes; mutable llvm::FoldingSet<AutoType> AutoTypes; + mutable llvm::FoldingSet<AtomicType> AtomicTypes; llvm::FoldingSet<AttributedType> AttributedTypes; mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; @@ -601,6 +602,10 @@ public: return CanQualType::CreateUnsafe(getPointerType((QualType) T)); } + /// getAtomicType - Return the uniqued reference to the atomic type for + /// the specified type. + QualType getAtomicType(QualType T) const; + /// getBlockPointerType - Return the uniqued reference to the type for a block /// of the specified type. QualType getBlockPointerType(QualType T) const; diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 36add6c457..a224bb0a40 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -813,6 +813,10 @@ DEF_TRAVERSE_TYPE(ObjCObjectPointerType, { TRY_TO(TraverseType(T->getPointeeType())); }) +DEF_TRAVERSE_TYPE(AtomicType, { + TRY_TO(TraverseType(T->getValueType())); + }) + #undef DEF_TRAVERSE_TYPE // ----------------- TypeLoc traversal ----------------- @@ -1041,6 +1045,10 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) +DEF_TRAVERSE_TYPELOC(AtomicType, { + TRY_TO(TraverseTypeLoc(TL.getValueLoc())); + }) + #undef DEF_TRAVERSE_TYPELOC // ----------------- Decl traversal ----------------- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 0b4c8f715d..4a44710938 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1449,6 +1449,7 @@ public: bool isCARCBridgableType() const; bool isTemplateTypeParmType() const; // C++ template type parameter bool isNullPtrType() const; // C++0x nullptr_t + bool isAtomicType() const; // C1X _Atomic() /// Determines if this type, which must satisfy /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather @@ -4352,6 +4353,37 @@ public: static bool classof(const ObjCObjectPointerType *) { return true; } }; +class AtomicType : public Type, public llvm::FoldingSetNode { + QualType ValueType; + + AtomicType(QualType ValTy, QualType Canonical) + : Type(Atomic, Canonical, ValTy->isDependentType(), + ValTy->isInstantiationDependentType(), + ValTy->isVariablyModifiedType(), + ValTy->containsUnexpandedParameterPack()), + ValueType(ValTy) {} + friend class ASTContext; // ASTContext creates these. + + public: + /// getValueType - Gets the type contained by this atomic type, i.e. + /// the type returned by performing an atomic load of this atomic type. + QualType getValueType() const { return ValueType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getValueType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { + ID.AddPointer(T.getAsOpaquePtr()); + } + static bool classof(const Type *T) { + return T->getTypeClass() == Atomic; + } + static bool classof(const AtomicType *) { return true; } +}; + /// A qualifier set is used to build a set of qualifiers. class QualifierCollector : public Qualifiers { public: @@ -4677,6 +4709,9 @@ inline bool Type::isObjCObjectOrInterfaceType() const { return isa<ObjCInterfaceType>(CanonicalType) || isa<ObjCObjectType>(CanonicalType); } +inline bool Type::isAtomicType() const { + return isa<AtomicType>(CanonicalType); +} inline bool Type::isObjCQualifiedIdType() const { if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 8e3e8d37c8..02ced65e5c 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -1730,6 +1730,62 @@ public: } }; +struct AtomicTypeLocInfo { + SourceLocation KWLoc, LParenLoc, RParenLoc; +}; + +class AtomicTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, AtomicTypeLoc, + AtomicType, AtomicTypeLocInfo> { +public: + TypeLoc getValueLoc() const { + return this->getInnerTypeLoc(); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getKWLoc(), getRParenLoc()); + } + + SourceLocation getKWLoc() const { + return this->getLocalData()->KWLoc; + } + void setKWLoc(SourceLocation Loc) { + this->getLocalData()->KWLoc = Loc; + } + + SourceLocation getLParenLoc() const { + return this->getLocalData()->LParenLoc; + } + void setLParenLoc(SourceLocation Loc) { + this->getLocalData()->LParenLoc = Loc; + } + + SourceLocation getRParenLoc() const { + return this->getLocalData()->RParenLoc; + } + void setRParenLoc(SourceLocation Loc) { + this->getLocalData()->RParenLoc = Loc; + } + + SourceRange getParensRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + void setParensRange(SourceRange Range) { + setLParenLoc(Range.getBegin()); + setRParenLoc(Range.getEnd()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setKWLoc(Loc); + setLParenLoc(Loc); + setRParenLoc(Loc); + } + + QualType getInnerType() const { + return this->getTypePtr()->getValueType(); + } +}; + + } #endif diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 0792d0d9b3..d5c485f8a3 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -102,9 +102,10 @@ DEPENDENT_TYPE(PackExpansion, Type) TYPE(ObjCObject, Type) TYPE(ObjCInterface, ObjCObjectType) TYPE(ObjCObjectPointer, Type) +TYPE(Atomic, Type) #ifdef LAST_TYPE -LAST_TYPE(ObjCObjectPointer) +LAST_TYPE(Atomic) #undef LAST_TYPE #endif diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index d4c118b447..411d49c912 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3073,6 +3073,10 @@ def err_block_with_return_type_requires_args : Error< "block with explicit return type requires argument list">; def err_func_def_incomplete_result : Error< "incomplete result type %0 in function definition">; +def err_atomic_specifier_bad_type : Error< + "_Atomic cannot be applied to " + "%select{incomplete |array |function |reference |atomic |qualified |}0type " + "%1 %select{||||||which is not trivially copyable}0">; // Expressions. def ext_sizeof_function_type : Extension< diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index be59ec5a56..1e89a8c817 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -57,6 +57,7 @@ namespace clang { TST_underlyingType, // __underlying_type for C++0x TST_auto, // C++0x auto TST_unknown_anytype, // __unknown_anytype extension + TST_atomic, // C1X _Atomic TST_error // erroneous type }; diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 1256caabec..151a75d1e7 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -250,6 +250,7 @@ KEYWORD(void , KEYALL) KEYWORD(volatile , KEYALL) KEYWORD(while , KEYALL) KEYWORD(_Alignas , KEYALL) +KEYWORD(_Atomic , KEYALL) KEYWORD(_Bool , KEYNOCXX) KEYWORD(_Complex , KEYALL) KEYWORD(_Generic , KEYALL) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index e8494767b5..cf9bbbe9dd 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1768,7 +1768,8 @@ private: void ParseTypeofSpecifier(DeclSpec &DS); void ParseDecltypeSpecifier(DeclSpec &DS); void ParseUnderlyingTypeSpecifier(DeclSpec &DS); - + void ParseAtomicSpecifier(DeclSpec &DS); + ExprResult ParseAlignArgument(SourceLocation Start); void ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation *endLoc = 0); diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 645ddcb468..3f11ee4f55 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -260,6 +260,7 @@ public: static const TST TST_underlyingType = clang::TST_underlyingType; static const TST TST_auto = clang::TST_auto; static const TST TST_unknown_anytype = clang::TST_unknown_anytype; + static const TST TST_atomic = clang::TST_atomic; static const TST TST_error = clang::TST_error; // type-qualifiers @@ -356,7 +357,7 @@ private: static bool isTypeRep(TST T) { return (T == TST_typename || T == TST_typeofType || - T == TST_underlyingType); + T == TST_underlyingType || T == TST_atomic); } static bool isExprRep(TST T) { return (T == TST_typeofExpr || T == TST_decltype); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index aad52fcab8..4b8bbdc6ea 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -793,6 +793,7 @@ public: QualType BuildBlockPointerType(QualType T, SourceLocation Loc, DeclarationName Entity); QualType BuildParenType(QualType T); + QualType BuildAtomicType(QualType T, SourceLocation Loc); TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index b8db49e76a..9a8eba2427 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -647,7 +647,9 @@ namespace clang { /// \brief A AutoType record. TYPE_AUTO = 38, /// \brief A UnaryTransformType record. - TYPE_UNARY_TRANSFORM = 39 + TYPE_UNARY_TRANSFORM = 39, + /// \brief An AtomicType record. + TYPE_ATOMIC = 40 }; /// \brief The type IDs for special types constructed by semantic diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 055ed7c08c..3377799e3d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1063,6 +1063,11 @@ ASTContext::getTypeInfo(const Type *T) const { return getTypeInfo(getCanonicalType(T)); } + case Type::Atomic: { + // FIXME: The alignment needs to be "fixed". + return getTypeInfo(cast<AtomicType>(T)->getValueType()); + } + } assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); @@ -1707,6 +1712,12 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { break; } + case Type::Atomic: { + const AtomicType *at = cast<AtomicType>(ty); + result = getAtomicType(getVariableArrayDecayedType(at->getValueType())); + break; + } + case Type::ConstantArray: { const ConstantArrayType *cat = cast<ConstantArrayType>(ty); result = getConstantArrayType( @@ -2904,6 +2915,34 @@ QualType ASTContext::getAutoType(QualType DeducedType) const { return QualType(AT, 0); } +/// getAtomicType - Return the uniqued reference to the atomic type for +/// the given value type. +QualType ASTContext::getAtomicType(QualType T) const { + // Unique pointers, to guarantee there is only one pointer of a particular + // structure. + llvm::FoldingSetNodeID ID; + AtomicType::Profile(ID, T); + + void *InsertPos = 0; + if (AtomicType *AT = AtomicTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(AT, 0); + + // If the atomic value type isn't canonical, this won't be a canonical type + // either, so fill in the canonical type field. + QualType Canonical; + if (!T.isCanonical()) { + Canonical = getAtomicType(getCanonicalType(T)); + + // Get the new insert position for the node we care about. + AtomicType *NewIP = AtomicTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; + } + AtomicType *New = new (*this, TypeAlignment) AtomicType(T, Canonical); + Types.push_back(New); + AtomicTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + /// getAutoDeductType - Get type pattern for deducing against 'auto'. QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) @@ -5802,6 +5841,24 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, return RHS; return getBlockPointerType(ResultType); } + case Type::Atomic: + { + // Merge two pointer types, while trying to preserve typedef info + QualType LHSValue = LHS->getAs<AtomicType>()->getValueType(); + QualType RHSValue = RHS->getAs<AtomicType>()->getValueType(); + if (Unqualified) { + LHSValue = LHSValue.getUnqualifiedType(); + RHSValue = RHSValue.getUnqualifiedType(); + } + QualType ResultType = mergeTypes(LHSValue, RHSValue, false, + Unqualified); + if (ResultType.isNull()) return QualType(); + if (getCanonicalType(LHSValue) == getCanonicalType(ResultType)) + return LHS; + if (getCanonicalType(RHSValue) == getCanonicalType(ResultType)) + return RHS; + return getAtomicType(ResultType); + } case Type::ConstantArray: { const ConstantArrayType* LCAT = getAsConstantArrayType(LHS); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index e50dcbe4b0..e95d01a98f 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -810,7 +810,15 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; } - + + case Type::Atomic: { + if (!IsStructurallyEquivalent(Context, + cast<AtomicType>(T1)->getValueType(), + cast<AtomicType>(T2)->getValueType())) + return false; + break; + } + } // end switch return true; diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index e94cb2d54b..41cfa6ad01 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -788,6 +788,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: + case Type::Atomic: llvm_unreachable("type is illegal as a nested name specifier"); case Type::SubstTemplateTypeParmPack: @@ -2111,6 +2112,13 @@ void CXXNameMangler::mangleType(const AutoType *T) { mangleType(D); } +void CXXNameMangler::mangleType(const AtomicType *T) { + // <type> ::= U <source-name> <type> # vendor extended type qualifier + // (Until there's a standardized mangling...) + Out << "U7_Atomic"; + mangleType(T->getValueType()); +} + void CXXNameMangler::mangleIntegerLiteral(QualType T, const llvm::APSInt &Value) { // <expr-primary> ::= L <type> <value number> E # integer literal diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index a5bfd7d318..e327d8b180 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -1113,6 +1113,10 @@ void MicrosoftCXXNameMangler::mangleType(const AutoType *T) { llvm_unreachable("Don't know how to mangle AutoTypes yet!"); } +void MicrosoftCXXNameMangler::mangleType(const AtomicType *T) { + llvm_unreachable("Don't know how to mangle AtomicTypes yet!"); +} + void MicrosoftMangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) { assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) && diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index a2c6954d75..60cb3fa33e 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2113,6 +2113,8 @@ static CachedProperties computeCachedProperties(const Type *T) { return Cache::get(cast<ObjCObjectType>(T)->getBaseType()); case Type::ObjCObjectPointer: return Cache::get(cast<ObjCObjectPointerType>(T)->getPointeeType()); + case Type::Atomic: + return Cache::get(cast<AtomicType>(T)->getValueType()); } llvm_unreachable("unhandled type class"); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 855cc02d9e..fb7b918ca2 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -123,6 +123,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { case Type::DependentTemplateSpecialization: case Type::ObjCObject: case Type::ObjCInterface: + case Type::Atomic: CanPrefixQualifiers = true; break; @@ -581,6 +582,16 @@ void TypePrinter::printAuto(const AutoType *T, std::string &S) { } } +void TypePrinter::printAtomic(const AtomicType *T, std::string &S) { + if (!S.empty()) + S = ' ' + S; + std::string Str; + IncludeStrongLifetimeRAII Strong(Policy); + print(T->getValueType(), Str); + + S = "_Atomic(" + Str + ")" + S; +} + /// Appends the given scope to the end of a string. void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) { if (DC->isTranslationUnit()) return; diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 7bd6fc2fb0..eda73253b5 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1423,6 +1423,13 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty, 0, 0, Elements); } +llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty, + llvm::DIFile U) { + // Ignore the atomic wrapping + // FIXME: What is the correct representation? + return getOrCreateType(Ty->getValueType(), U); +} + /// CreateEnumType - get enumeration type. llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) { llvm::DIFile Unit = getOrCreateFile(ED->getLocation()); @@ -1581,6 +1588,9 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::MemberPointer: return CreateType(cast<MemberPointerType>(Ty), Unit); + case Type::Atomic: + return CreateType(cast<AtomicType>(Ty), Unit); + case Type::Attributed: case Type::TemplateSpecialization: case Type::Elaborated: diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 19d1ff388c..68b3985961 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -96,6 +96,7 @@ class CGDebugInfo { llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DIFile F); llvm::DIType CreateType(const RValueReferenceType *Ty, llvm::DIFile Unit); llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F); llvm::DIType CreateEnumType(const EnumDecl *ED); llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method, llvm::DIFile F); diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index a1105d2894..2ad1ed3930 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -404,6 +404,7 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) { case Type::Vector: case Type::ExtVector: case Type::Complex: + case Type::Atomic: // FIXME: GCC treats block pointers as fundamental types?! case Type::BlockPointer: // abi::__fundamental_type_info. @@ -656,6 +657,10 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { case Type::MemberPointer: BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty)); break; + + case Type::Atomic: + // No fields, at least for the moment. + break; } llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 12def6728f..2c6e7b0acd 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -87,6 +87,10 @@ bool CodeGenFunction::hasAggregateLLVMType(QualType type) { case Type::ObjCObject: case Type::ObjCInterface: return true; + + // In IRGen, atomic types are just the underlying type + case Type::Atomic: + return hasAggregateLLVMType(type->getAs<AtomicType>()->getValueType()); } llvm_unreachable("unknown type kind!"); } @@ -983,6 +987,10 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { case Type::FunctionNoProto: type = cast<FunctionType>(ty)->getResultType(); break; + + case Type::Atomic: + type = cast<AtomicType>(ty)->getValueType(); + break; } } while (type->isVariablyModifiedType()); } diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 3032f820c6..61c1581798 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -548,6 +548,11 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { getCXXABI().ConvertMemberPointerType(cast<MemberPointerType>(Ty)); break; } + + case Type::Atomic: { + ResultType = ConvertTypeForMem(cast<AtomicType>(Ty)->getValueType()); + break; + } } assert(ResultType && "Didn't convert a type?"); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 5e1a42dc07..82155e44fd 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2184,6 +2184,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___underlying_type: ParseUnderlyingTypeSpecifier(DS); + continue; + + case tok::kw__Atomic: + ParseAtomicSpecifier(DS); + continue; // OpenCL qualifiers: case tok::kw_private: @@ -2460,6 +2465,10 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, ParseUnderlyingTypeSpecifier(DS); return true; + case tok::kw__Atomic: + ParseAtomicSpecifier(DS); + return true; + // OpenCL qualifiers: case tok::kw_private: if (!getLang().OpenCL) @@ -3219,6 +3228,10 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw_private: return getLang().OpenCL; + + // C1x _Atomic() + case tok::kw__Atomic: + return true; } } @@ -3338,6 +3351,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_decltype: return true; + // C1x _Atomic() + case tok::kw__Atomic: + return true; + // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'. case tok::less: return getLang().ObjC1; @@ -4504,6 +4521,47 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { Diag(StartLoc, DiagID) << PrevSpec; } +/// [C1X] atomic-specifier: +/// _Atomic ( type-name ) +/// +void Parser::ParseAtomicSpecifier(DeclSpec &DS) { + assert(Tok.is(tok::kw__Atomic) && "Not an atomic specifier"); + + SourceLocation StartLoc = ConsumeToken(); + SourceLocation LParenLoc = Tok.getLocation(); + + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + "_Atomic")) { + SkipUntil(tok::r_paren); + return; + } + + TypeResult Result = ParseTypeName(); + if (Result.isInvalid()) { + SkipUntil(tok::r_paren); + return; + } + + // Match the ')' + SourceLocation RParenLoc; + if (Tok.is(tok::r_paren)) + RParenLoc = ConsumeParen(); + else + MatchRHSPunctuation(tok::r_paren, LParenLoc); + + if (RParenLoc.isInvalid()) + return; + + DS.setTypeofParensRange(SourceRange(LParenLoc, RParenLoc)); + DS.SetRangeEnd(RParenLoc); + + const char *PrevSpec = 0; + unsigned DiagID; + if (DS.SetTypeSpecType(DeclSpec::TST_atomic, StartLoc, PrevSpec, + DiagID, Result.release())) + Diag(StartLoc, DiagID) << PrevSpec; +} + /// TryAltiVecVectorTokenOutOfLine - Out of line body that should only be called /// from TryAltiVecVectorToken. diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 210d179db1..0e7d |