[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