From: Eli Friedman Date: Thu, 6 Oct 2011 23:00:33 +0000 (+0000) Subject: Support for C1x _Atomic specifier (see testcase). This is primarily being committed... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b001de7458d17c17e6d8b8034c7cfcefd3b70c00;p=clang Support for C1x _Atomic specifier (see testcase). This is primarily being committed at the moment to help support C++0x , but it should be a solid base for implementing the full specification of C1x _Atomic. Thanks to Jeffrey Yasskin for the thorough review! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141330 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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 { mutable llvm::FoldingSet ObjCObjectTypes; mutable llvm::FoldingSet ObjCObjectPointerTypes; mutable llvm::FoldingSet AutoTypes; + mutable llvm::FoldingSet AtomicTypes; llvm::FoldingSet AttributedTypes; mutable llvm::FoldingSet 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(CanonicalType) || isa(CanonicalType); } +inline bool Type::isAtomicType() const { + return isa(CanonicalType); +} inline bool Type::isObjCQualifiedIdType() const { if (const ObjCObjectPointerType *OPT = getAs()) 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 { +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(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(ty); + result = getAtomicType(getVariableArrayDecayedType(at->getValueType())); + break; + } + case Type::ConstantArray: { const ConstantArrayType *cat = cast(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()->getValueType(); + QualType RHSValue = RHS->getAs()->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(T1)->getValueType(), + cast(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) { + // ::= U # 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) { // ::= L 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(D) || isa(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(T)->getBaseType()); case Type::ObjCObjectPointer: return Cache::get(cast(T)->getPointeeType()); + case Type::Atomic: + return Cache::get(cast(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(Ty), Unit); + case Type::Atomic: + return CreateType(cast(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(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()->getValueType()); } llvm_unreachable("unknown type kind!"); } @@ -983,6 +987,10 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { case Type::FunctionNoProto: type = cast(ty)->getResultType(); break; + + case Type::Atomic: + type = cast(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(Ty)); break; } + + case Type::Atomic: { + ResultType = ConvertTypeForMem(cast(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: 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..0e7d288395 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -719,6 +719,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___unaligned: case tok::kw___vector: case tok::kw___pixel: + case tok::kw__Atomic: return TPResult::False(); default: @@ -1033,6 +1034,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw___underlying_type: return TPResult::True(); + // C1x _Atomic + case tok::kw__Atomic: + return TPResult::True(); + default: return TPResult::False(); } diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index d7732c78dd..3564f2657b 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -243,6 +243,7 @@ bool Declarator::isDeclarationOfFunction() const { } switch (DS.getTypeSpecType()) { + case TST_atomic: case TST_auto: case TST_bool: case TST_char: @@ -389,6 +390,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_decltype: return "(decltype)"; case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; + case DeclSpec::TST_atomic: return "_Atomic"; case DeclSpec::TST_error: return "(error)"; } llvm_unreachable("Unknown typespec!"); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 718a19b988..534cd488e7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3011,7 +3011,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: case DeclSpec::TST_decltype: - case DeclSpec::TST_underlyingType: { + case DeclSpec::TST_underlyingType: + case DeclSpec::TST_atomic: { // Grab the type from the parser. TypeSourceInfo *TSI = 0; QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 4df525c6f3..cd57dcfb9a 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -3419,6 +3419,7 @@ struct CheckAbstractUsage { CheckPolymorphic(ReferenceTypeLoc) CheckPolymorphic(MemberPointerTypeLoc) CheckPolymorphic(BlockPointerTypeLoc) + CheckPolymorphic(AtomicTypeLoc) /// Handle all the types we haven't given a more specific /// implementation for above. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 7721caf939..ec71a4e94d 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -342,6 +342,10 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { QualType T = E->getType(); assert(!T.isNull() && "r-value conversion on typeless expression?"); + // We can't do lvalue-to-rvalue on atomics yet. + if (T->getAs()) + return Owned(E); + // Create a load out of an ObjCProperty l-value, if necessary. if (E->getObjectKind() == OK_ObjCProperty) { ExprResult Res = ConvertPropertyForRValue(E); @@ -5393,6 +5397,10 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType(); RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType(); + // We can't do assignment from/to atomics yet. + if (LHSType->isAtomicType()) + return Incompatible; + // Common case: no conversion required. if (LHSType == RHSType) { Kind = CK_NoOp; @@ -5712,7 +5720,7 @@ Sema::AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS, bool Diagnose) { if (getLangOptions().CPlusPlus) { - if (!LHSType->isRecordType()) { + if (!LHSType->isRecordType() && !LHSType->isAtomicType()) { // C++ 5.17p3: If the left operand is not of class type, the // expression is implicitly converted (C++ 4) to the // cv-unqualified type of the left operand. @@ -5732,6 +5740,8 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS, // FIXME: Currently, we fall through and treat C++ classes like C // structures. + // FIXME: We also fall through for atomics; not sure what should + // happen there, though. } // C99 6.5.16.1p1: the left operand is a pointer and the right is diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 84ae42a9b9..75da41dd77 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -2000,6 +2000,12 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { case Type::ObjCObjectPointer: Result.Namespaces.insert(Result.S.Context.getTranslationUnitDecl()); break; + + // Atomic types are just wrappers; use the associations of the + // contained type. + case Type::Atomic: + T = cast(T)->getValueType().getTypePtr(); + continue; } if (Queue.empty()) break; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index c8cf6c4c2c..cd1092a9bc 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3246,6 +3246,10 @@ bool UnnamedLocalNoLinkageFinder::VisitObjCObjectPointerType( return false; } +bool UnnamedLocalNoLinkageFinder::VisitAtomicType(const AtomicType* T) { + return Visit(T->getValueType()); +} + bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) { if (Tag->getDeclContext()->isFunctionOrMethod()) { S.Diag(SR.getBegin(), diag::ext_template_arg_local_type) diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 5d5cdc5233..70fdf64e7c 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1116,7 +1116,17 @@ DeduceTemplateArguments(Sema &S, Info, Deduced, TDF); return Sema::TDK_NonDeducedMismatch; - + + // _Atomic T [extension] + case Type::Atomic: + if (const AtomicType *AtomicArg = Arg->getAs()) + return DeduceTemplateArguments(S, TemplateParams, + cast(Param)->getValueType(), + AtomicArg->getValueType(), + Info, Deduced, TDF); + + return Sema::TDK_NonDeducedMismatch; + // T * case Type::Pointer: { QualType PointeeType; @@ -4126,6 +4136,13 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, OnlyDeduced, Depth, Used); break; + case Type::Atomic: + if (!OnlyDeduced) + MarkUsedTemplateParameters(SemaRef, + cast(T)->getValueType(), + OnlyDeduced, Depth, Used); + break; + case Type::DependentName: if (!OnlyDeduced) MarkUsedTemplateParameters(SemaRef, diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 2b7250f1a2..a2aa1b3026 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -619,7 +619,8 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { switch (DS.getTypeSpecType()) { case TST_typename: case TST_typeofType: - case TST_underlyingType: { + case TST_underlyingType: + case TST_atomic: { QualType T = DS.getRepAsType().get(); if (!T.isNull() && T->containsUnexpandedParameterPack()) return true; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 4a865bf235..995d767e2b 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -856,6 +856,16 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.UnknownAnyTy; break; + case DeclSpec::TST_atomic: + Result = S.GetTypeFromParser(DS.getRepAsType()); + assert(!Result.isNull() && "Didn't get a type for _Atomic?"); + Result = S.BuildAtomicType(Result, DS.getTypeSpecTypeLoc()); + if (Result.isNull()) { + Result = Context.IntTy; + declarator.setInvalidType(true); + } + break; + case DeclSpec::TST_error: Result = Context.IntTy; declarator.setInvalidType(true); @@ -2872,6 +2882,10 @@ namespace { void VisitTagTypeLoc(TagTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); } + void VisitAtomicTypeLoc(AtomicTypeLoc TL) { + TL.setKWLoc(DS.getTypeSpecTypeLoc()); + TL.setParensRange(DS.getTypeofParensRange()); + } void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. @@ -4183,3 +4197,36 @@ QualType Sema::BuildUnaryTransformType(QualType BaseType, } llvm_unreachable("unknown unary transform type"); } + +QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { + if (!T->isDependentType()) { + int DisallowedKind = -1; + if (T->isIncompleteType()) + // FIXME: It isn't entirely clear whether incomplete atomic types + // are allowed or not; for simplicity, ban them for the moment. + DisallowedKind = 0; + else if (T->isArrayType()) + DisallowedKind = 1; + else if (T->isFunctionType()) + DisallowedKind = 2; + else if (T->isReferenceType()) + DisallowedKind = 3; + else if (T->isAtomicType()) + DisallowedKind = 4; + else if (T.hasQualifiers()) + DisallowedKind = 5; + else if (!T.isTriviallyCopyableType(Context)) + // Some other non-trivially-copyable type (probably a C++ class) + DisallowedKind = 6; + + if (DisallowedKind != -1) { + Diag(Loc, diag::err_atomic_specifier_bad_type) << DisallowedKind << T; + return QualType(); + } + + // FIXME: Do we need any handling for ARC here? + } + + // Build the pointer type. + return Context.getAtomicType(T); +} diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 62c6d18b59..33aaf92d81 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -905,6 +905,12 @@ public: NumExpansions); } + /// \brief Build a new atomic type given its value type. + /// + /// By default, performs semantic analysis when building the atomic type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildAtomicType(QualType ValueType, SourceLocation KWLoc); + /// \brief Build a new template name given a nested name specifier, a flag /// indicating whether the "template" keyword was provided, and the template /// that the template name refers to. @@ -4399,6 +4405,29 @@ QualType TreeTransform::TransformTemplateSpecializationType( return getDerived().TransformTemplateSpecializationType(TLB, TL, Template); } +template +QualType TreeTransform::TransformAtomicType(TypeLocBuilder &TLB, + AtomicTypeLoc TL) { + QualType ValueType = getDerived().TransformType(TLB, TL.getValueLoc()); + if (ValueType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ValueType != TL.getValueLoc().getType()) { + Result = getDerived().RebuildAtomicType(ValueType, TL.getKWLoc()); + if (Result.isNull()) + return QualType(); + } + + AtomicTypeLoc NewTL = TLB.push(Result); + NewTL.setKWLoc(TL.getKWLoc()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + + return Result; +} + namespace { /// \brief Simple iterator that traverses the template arguments in a /// container that provides a \c getArgLoc() member function. @@ -8276,6 +8305,12 @@ QualType TreeTransform::RebuildTemplateSpecializationType( return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); } +template +QualType TreeTransform::RebuildAtomicType(QualType ValueType, + SourceLocation KWLoc) { + return SemaRef.BuildAtomicType(ValueType, KWLoc); +} + template TemplateName TreeTransform::RebuildTemplateName(CXXScopeSpec &SS, diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index cda7d2cc2a..361c3b79ca 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -3526,6 +3526,15 @@ QualType ASTReader::readTypeRecord(unsigned Index) { const_cast(T.getTypePtr())->setDependent(IsDependent); return T; } + + case TYPE_ATOMIC: { + if (Record.size() != 1) { + Error("Incorrect encoding of atomic type"); + return QualType(); + } + QualType ValueType = readType(*Loc.F, Record, Idx); + return Context.getAtomicType(ValueType); + } } // Suppress a GCC warning return QualType(); @@ -3760,6 +3769,11 @@ void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { TL.setStarLoc(ReadSourceLocation(Record, Idx)); } +void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) { + TL.setKWLoc(ReadSourceLocation(Record, Idx)); + TL.setLParenLoc(ReadSourceLocation(Record, Idx)); + TL.setRParenLoc(ReadSourceLocation(Record, Idx)); +} TypeSourceInfo *ASTReader::GetTypeSourceInfo(Module &F, const RecordData &Record, diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 9b534c9165..e648c7cd5d 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -388,6 +388,12 @@ ASTTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { Code = TYPE_OBJC_OBJECT_POINTER; } +void +ASTTypeWriter::VisitAtomicType(const AtomicType *T) { + Writer.AddTypeRef(T->getValueType(), Record); + Code = TYPE_ATOMIC; +} + namespace { class TypeLocWriter : public TypeLocVisitor { @@ -596,6 +602,11 @@ void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { Writer.AddSourceLocation(TL.getStarLoc(), Record); } +void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) { + Writer.AddSourceLocation(TL.getKWLoc(), Record); + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); +} //===----------------------------------------------------------------------===// // ASTWriter Implementation @@ -840,6 +851,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(TYPE_PACK_EXPANSION); RECORD(TYPE_ATTRIBUTED); RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK); + RECORD(TYPE_ATOMIC); RECORD(DECL_TYPEDEF); RECORD(DECL_ENUM); RECORD(DECL_RECORD); diff --git a/test/Sema/atomic-type.c b/test/Sema/atomic-type.c new file mode 100644 index 0000000000..8e725403ae --- /dev/null +++ b/test/Sema/atomic-type.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only + +// Basic parsing/Sema tests for _Atomic +// No operations are actually supported on objects of this type yet. +// The qualifier syntax is not supported yet. +_Atomic(int) t1; +_Atomic(int) *t2 = &t1; +void testf(void*); +void f(void) { + _Atomic(_Atomic(int)*) t3; + _Atomic(_Atomic(int)*) *t4[2] = { &t3, 0 }; + testf(t4); +} +extern _Atomic(int (*)(int(*)[], int(*)[10])) mergetest; +extern _Atomic(int (*)(int(*)[10], int(*)[])) mergetest; +extern _Atomic(int (*)(int(*)[10], int(*)[10])) mergetest; + +_Atomic(int()) error1; // expected-error {{_Atomic cannot be applied to function type}} +_Atomic(struct ErrorS) error2; // expected-error {{_Atomic cannot be applied to incomplete type}} +_Atomic(int[10]) error3; // expected-error {{_Atomic cannot be applied to array type}} +_Atomic(const int) error4; // expected-error {{_Atomic cannot be applied to qualified type}} +_Atomic(_Atomic(int)) error5; // expected-error {{_Atomic cannot be applied to atomic type}} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 71d5ea858b..8c2776d9f8 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1561,6 +1561,10 @@ bool CursorVisitor::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); } +bool CursorVisitor::VisitAtomicTypeLoc(AtomicTypeLoc TL) { + return Visit(TL.getValueLoc()); +} + #define DEFAULT_TYPELOC_IMPL(CLASS, PARENT) \ bool CursorVisitor::Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ return Visit##PARENT##Loc(TL); \