[cfe-commits] [PATCH] Add _Atomic specifier for atomic types
Eli Friedman
eli.friedman at gmail.com
Tue Oct 4 18:12:53 PDT 2011
On Tue, Oct 4, 2011 at 12:23 PM, Eli Friedman <eli.friedman at gmail.com> wrote:
>> Also, C1x says that the _Atomic specifier can't be applied to "an
>> array type, a function type, an atomic type, or a qualified type.",
>> while the _Atomic qualifier can't be applied to "an array type or a
>> function type." Are those covered by the trivially-copyable
>> restriction? This probably deserves a comment.
>
> Function types and atomic types are not trivially-copyable; arrays and
> qualified types are. I'll make the necessary adjustments (although
> I'm not entirely comfortable banning arrays in C when they are legal
> in C++; I might mark it an extension for the moment).
I subsequently realized that despite what the C++ standard says, it
would actually be impossible to instantiate std::atomic<int[10]>, and
std::atomic<volatile int> wouldn't make any sense even though it could
in theory be instantiated.
>>> + return QualType();
>>> + }
>>> +
>>> + // FIXME: Do we need any handling for ARC here?
>>> +
>>> + // Build the pointer type.
>>> + return Context.getAtomicType(T);
>>> +}
>>> Index: lib/Sema/SemaExpr.cpp
>>> ===================================================================
>>> --- lib/Sema/SemaExpr.cpp (revision 141016)
>>> +++ lib/Sema/SemaExpr.cpp (working copy)
>>> @@ -342,6 +342,10 @@
>>> QualType T = E->getType();
>>> assert(!T.isNull() && "r-value conversion on typeless expression?");
>>>
>>> + // We can't do lvalue-to-rvalue on atomics yet.
>>
>> According to the C1x draft I have, it's not "yet". The only way to get
>> an rvalue from an atomic lvalue is to call atomic_load().
>
> Okay, cool. :)
Hmm... I just looked, and 6.3.2.1p2 seems to say that you can get an
rvalue from an atomic lvalue.
>>> Index: lib/AST/ItaniumMangle.cpp
>>> ===================================================================
>>> --- lib/AST/ItaniumMangle.cpp (revision 141016)
>>> +++ lib/AST/ItaniumMangle.cpp (working copy)
>>> @@ -2111,6 +2112,11 @@
>>> mangleType(D);
>>> }
>>>
>>> +void CXXNameMangler::mangleType(const AtomicType *T) {
>>
>> The other mangleType definitions have a grammar fragment in a comment.
>> It looks like the official ABI doesn't mention atomics yet, so can
>> you describe where you got the v17 prefix?
>
> It's a vendor-specific prefix, since there isn't any standardized
> mangling at the moment. I'll put in a comment to that effect.
> (Granted, it usually won't matter unless someone tries to use _Atomic
> in C++ directly.)
And... I used the wrong kind of prefix. Now fixed.
New version attached.
-Eli
-------------- next part --------------
Index: test/Sema/atomic-type.c
===================================================================
--- test/Sema/atomic-type.c (revision 0)
+++ test/Sema/atomic-type.c (revision 0)
@@ -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}}
Index: include/clang/Basic/Specifiers.h
===================================================================
--- include/clang/Basic/Specifiers.h (revision 141122)
+++ include/clang/Basic/Specifiers.h (working copy)
@@ -57,6 +57,7 @@
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
};
Index: include/clang/Basic/TokenKinds.def
===================================================================
--- include/clang/Basic/TokenKinds.def (revision 141122)
+++ include/clang/Basic/TokenKinds.def (working copy)
@@ -250,6 +250,7 @@
KEYWORD(volatile , KEYALL)
KEYWORD(while , KEYALL)
KEYWORD(_Alignas , KEYALL)
+KEYWORD(_Atomic , KEYALL)
KEYWORD(_Bool , KEYNOCXX)
KEYWORD(_Complex , KEYALL)
KEYWORD(_Generic , KEYALL)
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td (revision 141122)
+++ include/clang/Basic/DiagnosticSemaKinds.td (working copy)
@@ -3072,6 +3072,10 @@
"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<
Index: include/clang/Sema/DeclSpec.h
===================================================================
--- include/clang/Sema/DeclSpec.h (revision 141122)
+++ include/clang/Sema/DeclSpec.h (working copy)
@@ -259,6 +259,7 @@
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
@@ -355,7 +356,7 @@
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);
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h (revision 141122)
+++ include/clang/Sema/Sema.h (working copy)
@@ -793,6 +793,7 @@
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);
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h (revision 141122)
+++ include/clang/AST/RecursiveASTVisitor.h (working copy)
@@ -813,6 +813,10 @@
TRY_TO(TraverseType(T->getPointeeType()));
})
+DEF_TRAVERSE_TYPE(AtomicType, {
+ TRY_TO(TraverseType(T->getValueType()));
+ })
+
#undef DEF_TRAVERSE_TYPE
// ----------------- TypeLoc traversal -----------------
@@ -1041,6 +1045,10 @@
TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
})
+DEF_TRAVERSE_TYPELOC(AtomicType, {
+ TRY_TO(TraverseTypeLoc(TL.getValueLoc()));
+ })
+
#undef DEF_TRAVERSE_TYPELOC
// ----------------- Decl traversal -----------------
Index: include/clang/AST/TypeNodes.def
===================================================================
--- include/clang/AST/TypeNodes.def (revision 141122)
+++ include/clang/AST/TypeNodes.def (working copy)
@@ -102,9 +102,10 @@
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
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h (revision 141122)
+++ include/clang/AST/ASTContext.h (working copy)
@@ -119,6 +119,7 @@
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;
@@ -594,6 +595,10 @@
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;
Index: include/clang/AST/TypeLoc.h
===================================================================
--- include/clang/AST/TypeLoc.h (revision 141122)
+++ include/clang/AST/TypeLoc.h (working copy)
@@ -1730,6 +1730,62 @@
}
};
+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
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h (revision 141122)
+++ include/clang/AST/Type.h (working copy)
@@ -1449,6 +1449,7 @@
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 @@
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 @@
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>())
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h (revision 141122)
+++ include/clang/Parse/Parser.h (working copy)
@@ -1768,7 +1768,8 @@
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);
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h (revision 141122)
+++ include/clang/Serialization/ASTBitCodes.h (working copy)
@@ -647,7 +647,9 @@
/// \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
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp (revision 141122)
+++ tools/libclang/CIndex.cpp (working copy)
@@ -1561,6 +1561,10 @@
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); \
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp (revision 141122)
+++ lib/Sema/SemaDeclCXX.cpp (working copy)
@@ -3419,6 +3419,7 @@
CheckPolymorphic(ReferenceTypeLoc)
CheckPolymorphic(MemberPointerTypeLoc)
CheckPolymorphic(BlockPointerTypeLoc)
+ CheckPolymorphic(AtomicTypeLoc)
/// Handle all the types we haven't given a more specific
/// implementation for above.
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h (revision 141122)
+++ lib/Sema/TreeTransform.h (working copy)
@@ -905,6 +905,12 @@
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.
@@ -4397,6 +4403,29 @@
return getDerived().TransformTemplateSpecializationType(TLB, TL, Template);
}
+template<typename Derived>
+QualType TreeTransform<Derived>::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<AtomicTypeLoc>(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.
@@ -8274,6 +8303,12 @@
}
template<typename Derived>
+QualType TreeTransform<Derived>::RebuildAtomicType(QualType ValueType,
+ SourceLocation KWLoc) {
+ return SemaRef.BuildAtomicType(ValueType, KWLoc);
+}
+
+template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
bool TemplateKW,
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp (revision 141122)
+++ lib/Sema/SemaDecl.cpp (working copy)
@@ -3011,7 +3011,8 @@
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);
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp (revision 141122)
+++ lib/Sema/SemaTemplateDeduction.cpp (working copy)
@@ -1116,7 +1116,17 @@
Info, Deduced, TDF);
return Sema::TDK_NonDeducedMismatch;
-
+
+ // _Atomic T [extension]
+ case Type::Atomic:
+ if (const AtomicType *AtomicArg = Arg->getAs<AtomicType>())
+ return DeduceTemplateArguments(S, TemplateParams,
+ cast<AtomicType>(Param)->getValueType(),
+ AtomicArg->getValueType(),
+ Info, Deduced, TDF);
+
+ return Sema::TDK_NonDeducedMismatch;
+
// T *
case Type::Pointer: {
QualType PointeeType;
@@ -4126,6 +4136,13 @@
OnlyDeduced, Depth, Used);
break;
+ case Type::Atomic:
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(SemaRef,
+ cast<AtomicType>(T)->getValueType(),
+ OnlyDeduced, Depth, Used);
+ break;
+
case Type::DependentName:
if (!OnlyDeduced)
MarkUsedTemplateParameters(SemaRef,
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp (revision 141122)
+++ lib/Sema/SemaTemplate.cpp (working copy)
@@ -3246,6 +3246,10 @@
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)
Index: lib/Sema/DeclSpec.cpp
===================================================================
--- lib/Sema/DeclSpec.cpp (revision 141122)
+++ lib/Sema/DeclSpec.cpp (working copy)
@@ -242,6 +242,7 @@
}
switch (DS.getTypeSpecType()) {
+ case TST_atomic:
case TST_auto:
case TST_bool:
case TST_char:
@@ -388,6 +389,7 @@
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!");
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp (revision 141122)
+++ lib/Sema/SemaType.cpp (working copy)
@@ -856,6 +856,16 @@
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 @@
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 @@
}
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);
+}
Index: lib/Sema/SemaLookup.cpp
===================================================================
--- lib/Sema/SemaLookup.cpp (revision 141122)
+++ lib/Sema/SemaLookup.cpp (working copy)
@@ -2000,6 +2000,12 @@
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<AtomicType>(T)->getValueType().getTypePtr();
+ continue;
}
if (Queue.empty()) break;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp (revision 141122)
+++ lib/Sema/SemaExpr.cpp (working copy)
@@ -342,6 +342,10 @@
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<AtomicType>())
+ return Owned(E);
+
// Create a load out of an ObjCProperty l-value, if necessary.
if (E->getObjectKind() == OK_ObjCProperty) {
ExprResult Res = ConvertPropertyForRValue(E);
@@ -5388,6 +5392,10 @@
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;
@@ -5707,7 +5715,7 @@
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.
@@ -5727,6 +5735,8 @@
// 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
Index: lib/Sema/SemaTemplateVariadic.cpp
===================================================================
--- lib/Sema/SemaTemplateVariadic.cpp (revision 141122)
+++ lib/Sema/SemaTemplateVariadic.cpp (working copy)
@@ -619,7 +619,8 @@
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;
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp (revision 141122)
+++ lib/AST/ASTImporter.cpp (working copy)
@@ -810,7 +810,15 @@
return false;
break;
}
-
+
+ case Type::Atomic: {
+ if (!IsStructurallyEquivalent(Context,
+ cast<AtomicType>(T1)->getValueType(),
+ cast<AtomicType>(T2)->getValueType()))
+ return false;
+ break;
+ }
+
} // end switch
return true;
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp (revision 141122)
+++ lib/AST/Type.cpp (working copy)
@@ -2113,6 +2113,8 @@
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");
Index: lib/AST/TypePrinter.cpp
===================================================================
--- lib/AST/TypePrinter.cpp (revision 141122)
+++ lib/AST/TypePrinter.cpp (working copy)
@@ -123,6 +123,7 @@
case Type::DependentTemplateSpecialization:
case Type::ObjCObject:
case Type::ObjCInterface:
+ case Type::Atomic:
CanPrefixQualifiers = true;
break;
@@ -581,6 +582,16 @@
}
}
+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;
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp (revision 141122)
+++ lib/AST/MicrosoftMangle.cpp (working copy)
@@ -1113,6 +1113,10 @@
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)) &&
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp (revision 141122)
+++ lib/AST/ItaniumMangle.cpp (working copy)
@@ -788,6 +788,7 @@
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 @@
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
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp (revision 141122)
+++ lib/AST/ASTContext.cpp (working copy)
@@ -1063,8 +1063,13 @@
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");
return std::make_pair(Width, Align);
}
@@ -1707,6 +1712,12 @@
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 @@
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 @@
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);
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp (revision 141122)
+++ lib/CodeGen/CodeGenFunction.cpp (working copy)
@@ -86,6 +86,10 @@
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!");
}
@@ -978,6 +982,10 @@
case Type::FunctionNoProto:
type = cast<FunctionType>(ty)->getResultType();
break;
+
+ case Type::Atomic:
+ type = cast<AtomicType>(ty)->getValueType();
+ break;
}
} while (type->isVariablyModifiedType());
}
Index: lib/CodeGen/CGDebugInfo.h
===================================================================
--- lib/CodeGen/CGDebugInfo.h (revision 141122)
+++ lib/CodeGen/CGDebugInfo.h (working copy)
@@ -96,6 +96,7 @@
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);
Index: lib/CodeGen/CodeGenTypes.cpp
===================================================================
--- lib/CodeGen/CodeGenTypes.cpp (revision 141122)
+++ lib/CodeGen/CodeGenTypes.cpp (working copy)
@@ -548,7 +548,12 @@
getCXXABI().ConvertMemberPointerType(cast<MemberPointerType>(Ty));
break;
}
+
+ case Type::Atomic: {
+ ResultType = ConvertTypeForMem(cast<AtomicType>(Ty)->getValueType());
+ break;
}
+ }
assert(ResultType && "Didn't convert a type?");
Index: lib/CodeGen/CGRTTI.cpp
===================================================================
--- lib/CodeGen/CGRTTI.cpp (revision 141122)
+++ lib/CodeGen/CGRTTI.cpp (working copy)
@@ -404,6 +404,7 @@
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 @@
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);
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp (revision 141122)
+++ lib/CodeGen/CGDebugInfo.cpp (working copy)
@@ -1418,6 +1418,13 @@
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());
@@ -1576,6 +1583,9 @@
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:
Index: lib/Parse/ParseTentative.cpp
===================================================================
--- lib/Parse/ParseTentative.cpp (revision 141122)
+++ lib/Parse/ParseTentative.cpp (working copy)
@@ -719,6 +719,7 @@
case tok::kw___unaligned:
case tok::kw___vector:
case tok::kw___pixel:
+ case tok::kw__Atomic:
return TPResult::False();
default:
@@ -1033,6 +1034,10 @@
case tok::kw___underlying_type:
return TPResult::True();
+ // C1x _Atomic
+ case tok::kw__Atomic:
+ return TPResult::True();
+
default:
return TPResult::False();
}
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp (revision 141122)
+++ lib/Parse/ParseDecl.cpp (working copy)
@@ -2184,7 +2184,12 @@
case tok::kw___underlying_type:
ParseUnderlyingTypeSpecifier(DS);
+ continue;
+ case tok::kw__Atomic:
+ ParseAtomicSpecifier(DS);
+ continue;
+
// OpenCL qualifiers:
case tok::kw_private:
if (!getLang().OpenCL)
@@ -2460,6 +2465,10 @@
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 @@
case tok::kw_private:
return getLang().OpenCL;
+
+ // C1x _Atomic()
+ case tok::kw__Atomic:
+ return true;
}
}
@@ -3338,6 +3351,10 @@
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,7 +4521,48 @@
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.
bool Parser::TryAltiVecVectorTokenOutOfLine() {
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp (revision 141122)
+++ lib/Serialization/ASTReader.cpp (working copy)
@@ -3526,7 +3526,16 @@
const_cast<Type*>(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::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,
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp (revision 141122)
+++ lib/Serialization/ASTWriter.cpp (working copy)
@@ -388,6 +388,12 @@
Code = TYPE_OBJC_OBJECT_POINTER;
}
+void
+ASTTypeWriter::VisitAtomicType(const AtomicType *T) {
+ Writer.AddTypeRef(T->getValueType(), Record);
+ Code = TYPE_ATOMIC;
+}
+
namespace {
class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> {
@@ -596,6 +602,11 @@
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 @@
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);
More information about the cfe-commits
mailing list