]> granicus.if.org Git - clang/commitdiff
Support C11 _Atomic type qualifier. This is more-or-less just syntactic sugar for...
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 28 Mar 2013 01:55:44 +0000 (01:55 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 28 Mar 2013 01:55:44 +0000 (01:55 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178210 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Parse/Parser.h
include/clang/Sema/DeclSpec.h
include/clang/Sema/Sema.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseStmt.cpp
lib/Sema/DeclSpec.cpp
lib/Sema/SemaCodeComplete.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaType.cpp
test/Parser/asm.c
test/Parser/atomic.c [new file with mode: 0644]
test/SemaCXX/atomic-type.cxx

index 7e26387cc890a7bed6b9a88b9670185d5bbd8508..2a71b17293b0d3f0aa21fb749028121468930af5 100644 (file)
@@ -1166,8 +1166,7 @@ def warn_cxx98_compat_static_data_member_in_union : Warning<
 def err_union_member_of_reference_type : Error<
   "union member %0 has reference type %1">;
 def ext_anonymous_struct_union_qualified : Extension<
-  "anonymous %select{struct|union}0 cannot be '%select{const|volatile|"
-  "restrict}1'">;
+  "anonymous %select{struct|union}0 cannot be '%1'">;
 def err_different_return_type_for_overriding_virtual_function : Error<
   "virtual function %0 has a different return type "
   "%diff{($) than the function it overrides (which has return type $)|"
index 1ac0f3be5ea2db34e511da60694f91342ab9b4e3..11a3bdbd50d0586b0aca47c1e8d6c898fca55ce4 100644 (file)
@@ -1999,7 +1999,8 @@ private:
                                DirectDeclParseFunction DirectDeclParser);
 
   void ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed = true,
-                                 bool CXX11AttributesAllowed = true);
+                                 bool CXX11AttributesAllowed = true,
+                                 bool AtomicAllowed = true);
   void ParseDirectDeclarator(Declarator &D);
   void ParseParenDeclarator(Declarator &D);
   void ParseFunctionDeclarator(Declarator &D,
index 0c734216b1c8d762c9299d61732aebe395447c8e..48cd4d14f80ab70cf1d07f4382f558affa5f0b84 100644 (file)
@@ -291,7 +291,10 @@ public:
     TQ_unspecified = 0,
     TQ_const       = 1,
     TQ_restrict    = 2,
-    TQ_volatile    = 4
+    TQ_volatile    = 4,
+    // This has no corresponding Qualifiers::TQ value, because it's not treated
+    // as a qualifier in our type system.
+    TQ_atomic      = 8
   };
 
   /// ParsedSpecifiers - Flags to query which specifiers were applied.  This is
@@ -321,7 +324,7 @@ private:
   unsigned TypeSpecOwned : 1;
 
   // type-qualifiers
-  unsigned TypeQualifiers : 3;  // Bitwise OR of TQ.
+  unsigned TypeQualifiers : 4;  // Bitwise OR of TQ.
 
   // function-specifier
   unsigned FS_inline_specified : 1;
@@ -369,7 +372,7 @@ private:
   /// TSTNameLoc provides source range info for tag types.
   SourceLocation TSTNameLoc;
   SourceRange TypeofParensRange;
-  SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc;
+  SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc;
   SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
   SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
 
@@ -503,6 +506,7 @@ public:
   SourceLocation getConstSpecLoc() const { return TQ_constLoc; }
   SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; }
   SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; }
+  SourceLocation getAtomicSpecLoc() const { return TQ_atomicLoc; }
 
   /// \brief Clear out all of the type qualifiers.
   void ClearTypeQualifiers() {
@@ -510,6 +514,7 @@ public:
     TQ_constLoc = SourceLocation();
     TQ_restrictLoc = SourceLocation();
     TQ_volatileLoc = SourceLocation();
+    TQ_atomicLoc = SourceLocation();
   }
 
   // function-specifier
@@ -1025,8 +1030,8 @@ struct DeclaratorChunk {
   };
 
   struct PointerTypeInfo : TypeInfoCommon {
-    /// The type qualifiers: const/volatile/restrict.
-    unsigned TypeQuals : 3;
+    /// The type qualifiers: const/volatile/restrict/atomic.
+    unsigned TypeQuals : 4;
 
     /// The location of the const-qualifier, if any.
     unsigned ConstQualLoc;
@@ -1037,6 +1042,9 @@ struct DeclaratorChunk {
     /// The location of the restrict-qualifier, if any.
     unsigned RestrictQualLoc;
 
+    /// The location of the _Atomic-qualifier, if any.
+    unsigned AtomicQualLoc;
+
     void destroy() {
     }
   };
@@ -1051,8 +1059,8 @@ struct DeclaratorChunk {
   };
 
   struct ArrayTypeInfo : TypeInfoCommon {
-    /// The type qualifiers for the array: const/volatile/restrict.
-    unsigned TypeQuals : 3;
+    /// The type qualifiers for the array: const/volatile/restrict/_Atomic.
+    unsigned TypeQuals : 4;
 
     /// True if this dimension included the 'static' keyword.
     bool hasStatic : 1;
@@ -1274,16 +1282,16 @@ struct DeclaratorChunk {
 
   struct BlockPointerTypeInfo : TypeInfoCommon {
     /// For now, sema will catch these as invalid.
-    /// The type qualifiers: const/volatile/restrict.
-    unsigned TypeQuals : 3;
+    /// The type qualifiers: const/volatile/restrict/_Atomic.
+    unsigned TypeQuals : 4;
 
     void destroy() {
     }
   };
 
   struct MemberPointerTypeInfo : TypeInfoCommon {
-    /// The type qualifiers: const/volatile/restrict.
-    unsigned TypeQuals : 3;
+    /// The type qualifiers: const/volatile/restrict/_Atomic.
+    unsigned TypeQuals : 4;
     // CXXScopeSpec has a constructor, so it can't be a direct member.
     // So we need some pointer-aligned storage and a bit of trickery.
     union {
index 4259bb88ed9126517de2d351da425b7b7ae1e011..049290b5bb1bf011343ab91cc5105bf31400f04d 100644 (file)
@@ -936,10 +936,8 @@ public:
 
   QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs,
                               const DeclSpec *DS = 0);
-  QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVR,
-                              const DeclSpec *DS = 0) {
-    return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR), DS);
-  }
+  QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVRA,
+                              const DeclSpec *DS = 0);
   QualType BuildPointerType(QualType T,
                             SourceLocation Loc, DeclarationName Entity);
   QualType BuildReferenceType(QualType T, bool LValueRef,
index 7dfbf5ff86cd7e424c54c130487eefa25ae97830..03bffde06ea77717edd330b5ae4d8963db44a4da 100644 (file)
@@ -2905,8 +2905,17 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
       continue;
 
     case tok::kw__Atomic:
-      ParseAtomicSpecifier(DS);
-      continue;
+      // C11 6.7.2.4/4:
+      //   If the _Atomic keyword is immediately followed by a left parenthesis,
+      //   it is interpreted as a type specifier (with a type name), not as a
+      //   type qualifier.
+      if (NextToken().is(tok::l_paren)) {
+        ParseAtomicSpecifier(DS);
+        continue;
+      }
+      isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID,
+                                 getLangOpts());
+      break;
 
     // OpenCL qualifiers:
     case tok::kw_private:
@@ -3814,7 +3823,7 @@ bool Parser::isTypeSpecifierQualifier() {
   case tok::kw_private:
     return getLangOpts().OpenCL;
 
-  // C11 _Atomic()
+  // C11 _Atomic
   case tok::kw__Atomic:
     return true;
   }
@@ -3959,7 +3968,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
   case tok::annot_decltype:
   case tok::kw_constexpr:
 
-    // C11 _Atomic()
+    // C11 _Atomic
   case tok::kw__Atomic:
     return true;
 
@@ -4099,7 +4108,8 @@ bool Parser::isConstructorDeclarator() {
 ///
 void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
                                        bool VendorAttributesAllowed,
-                                       bool CXX11AttributesAllowed) {
+                                       bool CXX11AttributesAllowed,
+                                       bool AtomicAllowed) {
   if (getLangOpts().CPlusPlus11 && CXX11AttributesAllowed &&
       isCXX11AttributeSpecifier()) {
     ParsedAttributesWithRange attrs(AttrFactory);
@@ -4132,6 +4142,12 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
       isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
                                  getLangOpts());
       break;
+    case tok::kw__Atomic:
+      if (!AtomicAllowed)
+        goto DoneWithTypeQuals;
+      isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID,
+                                 getLangOpts());
+      break;
 
     // OpenCL qualifiers:
     case tok::kw_private:
@@ -4346,6 +4362,10 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
       if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
         Diag(DS.getVolatileSpecLoc(),
              diag::err_invalid_reference_qualifier_application) << "volatile";
+      // 'restrict' is permitted as an extension.
+      if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+        Diag(DS.getAtomicSpecLoc(),
+             diag::err_invalid_reference_qualifier_application) << "_Atomic";
     }
 
     // Recursively parse the declarator.
@@ -4368,7 +4388,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
       }
     }
 
-    // Remember that we parsed a reference type. It doesn't have type-quals.
+    // Remember that we parsed a reference type.
     D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc,
                                                 Kind == tok::amp),
                   DS.getAttributes(),
@@ -4809,7 +4829,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
       // with the virt-specifier-seq and pure-specifier in the same way.
 
       // Parse cv-qualifier-seq[opt].
-      ParseTypeQualifierListOpt(DS, false /*no attributes*/, false);
+      ParseTypeQualifierListOpt(DS, /*VendorAttributesAllowed*/ false,
+                                /*CXX11AttributesAllowed*/ false,
+                                /*AtomicAllowed*/ false);
       if (!DS.getSourceRange().getEnd().isInvalid()) {
         EndLoc = DS.getSourceRange().getEnd();
         ConstQualifierLoc = DS.getConstSpecLoc();
@@ -5350,14 +5372,13 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
 ///           _Atomic ( type-name )
 ///
 void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
-  assert(Tok.is(tok::kw__Atomic) && "Not an atomic specifier");
+  assert(Tok.is(tok::kw__Atomic) && NextToken().is(tok::l_paren) &&
+         "Not an atomic specifier");
 
   SourceLocation StartLoc = ConsumeToken();
   BalancedDelimiterTracker T(*this, tok::l_paren);
-  if (T.expectAndConsume(diag::err_expected_lparen_after, "_Atomic")) {
-    SkipUntil(tok::r_paren);
+  if (T.consumeOpen())
     return;
-  }
 
   TypeResult Result = ParseTypeName();
   if (Result.isInvalid()) {
index 6db47a01571241b714c33dc05fcc066e47b6e7ac..355f3694bb6cafd66e7ff0c278932cb14868337e 100644 (file)
@@ -1810,6 +1810,9 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
     Diag(Loc, diag::w_asm_qualifier_ignored) << "const";
   if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
     Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict";
+  // FIXME: Once GCC supports _Atomic, check whether it permits it here.
+  if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+    Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic";
 
   // Remember if this was a volatile asm.
   bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
index 569352ecb950a6696e85c74c2b468ad97ac900cd..45f524b97b88cdb0bae2092e4619f4ba49ea4193 100644 (file)
@@ -169,6 +169,9 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
                                              SourceLocation LocalRangeEnd,
                                              Declarator &TheDeclarator,
                                              TypeResult TrailingReturnType) {
+  assert(!(TypeQuals & DeclSpec::TQ_atomic) &&
+         "function cannot have _Atomic qualifier");
+
   DeclaratorChunk I;
   I.Kind                        = Function;
   I.Loc                         = LocalRangeBegin;
@@ -442,6 +445,7 @@ const char *DeclSpec::getSpecifierName(TQ T) {
   case DeclSpec::TQ_const:       return "const";
   case DeclSpec::TQ_restrict:    return "restrict";
   case DeclSpec::TQ_volatile:    return "volatile";
+  case DeclSpec::TQ_atomic:      return "_Atomic";
   }
   llvm_unreachable("Unknown typespec!");
 }
@@ -710,12 +714,14 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
   TypeQualifiers |= T;
 
   switch (T) {
-  default: llvm_unreachable("Unknown type qualifier!");
-  case TQ_const:    TQ_constLoc = Loc; break;
-  case TQ_restrict: TQ_restrictLoc = Loc; break;
-  case TQ_volatile: TQ_volatileLoc = Loc; break;
+  case TQ_unspecified: break;
+  case TQ_const:    TQ_constLoc = Loc; return false;
+  case TQ_restrict: TQ_restrictLoc = Loc; return false;
+  case TQ_volatile: TQ_volatileLoc = Loc; return false;
+  case TQ_atomic:   TQ_atomicLoc = Loc; return false;
   }
-  return false;
+
+  llvm_unreachable("Unknown type qualifier!");
 }
 
 bool DeclSpec::setFunctionSpecInline(SourceLocation Loc) {
index 2fa08fd5e1aa888252e4ab073db43249f82e54a3..9c77e3f154881d457d96b33e54d26062a62cbfe4 100644 (file)
@@ -3729,6 +3729,9 @@ void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) {
   if (getLangOpts().C99 &&
       !(DS.getTypeQualifiers() & DeclSpec::TQ_restrict))
     Results.AddResult("restrict");
+  if (getLangOpts().C11 &&
+      !(DS.getTypeQualifiers() & DeclSpec::TQ_atomic))
+    Results.AddResult("_Atomic");
   Results.ExitScope();
   HandleCodeCompleteResults(this, CodeCompleter, 
                             Results.getCompletionContext(),
index 9261df559e9b5f93fc28350a00defbf45a30d39c..dfa87d314d045e35d4bf69147736eccac4df1a75 100644 (file)
@@ -3175,6 +3175,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
     if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
       Diag(DS.getConstSpecLoc(), DiagID) << "volatile";
     // Restrict is covered above.
+    if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+      Diag(DS.getAtomicSpecLoc(), DiagID) << "_Atomic";
   }
 
   // Warn about ignored type attributes, for example:
@@ -3411,18 +3413,23 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
     if (DS.getTypeQualifiers()) {
       if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
         Diag(DS.getConstSpecLoc(), diag::ext_anonymous_struct_union_qualified)
-          << Record->isUnion() << 
+          << Record->isUnion() << "const"
           << FixItHint::CreateRemoval(DS.getConstSpecLoc());
       if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
-        Diag(DS.getVolatileSpecLoc(), 
+        Diag(DS.getVolatileSpecLoc(),
              diag::ext_anonymous_struct_union_qualified)
-          << Record->isUnion() << 1
+          << Record->isUnion() << "volatile"
           << FixItHint::CreateRemoval(DS.getVolatileSpecLoc());
       if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
-        Diag(DS.getRestrictSpecLoc(), 
+        Diag(DS.getRestrictSpecLoc(),
              diag::ext_anonymous_struct_union_qualified)
-          << Record->isUnion() << 
+          << Record->isUnion() << "restrict"
           << FixItHint::CreateRemoval(DS.getRestrictSpecLoc());
+      if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+        Diag(DS.getAtomicSpecLoc(),
+             diag::ext_anonymous_struct_union_qualified)
+          << Record->isUnion() << "_Atomic"
+          << FixItHint::CreateRemoval(DS.getAtomicSpecLoc());
 
       DS.ClearTypeQualifiers();
     }
index 57f2aae80e0e17ae953605a51422a2589b1e9c82..25112fefe9d84ceb670cbbbf99eb4134c926afd5 100644 (file)
@@ -1089,21 +1089,18 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
     // of a function type includes any type qualifiers, the behavior is
     // undefined."
     if (Result->isFunctionType() && TypeQuals) {
-      // Get some location to point at, either the C or V location.
-      SourceLocation Loc;
       if (TypeQuals & DeclSpec::TQ_const)
-        Loc = DS.getConstSpecLoc();
+        S.Diag(DS.getConstSpecLoc(), diag::warn_typecheck_function_qualifiers)
+          << Result << DS.getSourceRange();
       else if (TypeQuals & DeclSpec::TQ_volatile)
-        Loc = DS.getVolatileSpecLoc();
+        S.Diag(DS.getVolatileSpecLoc(), diag::warn_typecheck_function_qualifiers)
+          << Result << DS.getSourceRange();
       else {
-        assert((TypeQuals & DeclSpec::TQ_restrict) &&
-               "Has CVR quals but not C, V, or R?");
-        // No diagnostic; we'll diagnose 'restrict' applied to a function type
-        // later, in BuildQualifiedType.
+        assert((TypeQuals & (DeclSpec::TQ_restrict | DeclSpec::TQ_atomic)) &&
+               "Has CVRA quals but not C, V, R, or A?");
+        // No diagnostic; we'll diagnose 'restrict' or '_Atomic' applied to a
+        // function type later, in BuildQualifiedType.
       }
-      if (!Loc.isInvalid())
-        S.Diag(Loc, diag::warn_typecheck_function_qualifiers)
-          << Result << DS.getSourceRange();
     }
 
     // C++ [dcl.ref]p1:
@@ -1116,6 +1113,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
         TypeQuals && Result->isReferenceType()) {
       TypeQuals &= ~DeclSpec::TQ_const;
       TypeQuals &= ~DeclSpec::TQ_volatile;
+      TypeQuals &= ~DeclSpec::TQ_atomic;
     }
 
     // C90 6.5.3 constraints: "The same type qualifier shall not appear more
@@ -1133,11 +1131,17 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
           << "volatile";
       }
 
-      // C90 doesn't have restrict, so it doesn't force us to produce a warning
-      // in this case.
+      // C90 doesn't have restrict nor _Atomic, so it doesn't force us to
+      // produce a warning in this case.
     }
 
-    return S.BuildQualifiedType(Result, DeclLoc, TypeQuals, &DS);
+    QualType Qualified = S.BuildQualifiedType(Result, DeclLoc, TypeQuals, &DS);
+
+    // If adding qualifiers fails, just use the unqualified type.
+    if (Qualified.isNull())
+      declarator.setInvalidType(true);
+    else
+      Result = Qualified;
   }
 
   return Result;
@@ -1188,6 +1192,39 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
   return Context.getQualifiedType(T, Qs);
 }
 
+QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
+                                  unsigned CVRA, const DeclSpec *DS) {
+  // Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic.
+  unsigned CVR = CVRA & ~DeclSpec::TQ_atomic;
+
+  // C11 6.7.3/5:
+  //   If the same qualifier appears more than once in the same
+  //   specifier-qualifier-list, either directly or via one or more typedefs,
+  //   the behavior is the same as if it appeared only once.
+  //
+  // It's not specified what happens when the _Atomic qualifier is applied to
+  // a type specified with the _Atomic specifier, but we assume that this
+  // should be treated as if the _Atomic qualifier appeared multiple times.
+  if (CVRA & DeclSpec::TQ_atomic && !T->isAtomicType()) {
+    // C11 6.7.3/5:
+    //   If other qualifiers appear along with the _Atomic qualifier in a
+    //   specifier-qualifier-list, the resulting type is the so-qualified
+    //   atomic type.
+    //
+    // Don't need to worry about array types here, since _Atomic can't be
+    // applied to such types.
+    SplitQualType Split = T.getSplitUnqualifiedType();
+    T = BuildAtomicType(QualType(Split.Ty, 0),
+                        DS ? DS->getAtomicSpecLoc() : Loc);
+    if (T.isNull())
+      return T;
+    Split.Quals.addCVRQualifiers(CVR);
+    return BuildQualifiedType(T, Loc, Split.Quals);
+  }
+
+  return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR), DS);
+}
+
 /// \brief Build a paren type including \p T.
 QualType Sema::BuildParenType(QualType T) {
   return Context.getParenType(T);
@@ -1847,6 +1884,7 @@ static void DiagnoseIgnoredQualifiers(unsigned Quals,
                                       SourceLocation ConstQualLoc,
                                       SourceLocation VolatileQualLoc,
                                       SourceLocation RestrictQualLoc,
+                                      SourceLocation AtomicQualLoc,
                                       Sema& S) {
   std::string QualStr;
   unsigned NumQuals = 0;
@@ -1855,38 +1893,47 @@ static void DiagnoseIgnoredQualifiers(unsigned Quals,
   FixItHint ConstFixIt;
   FixItHint VolatileFixIt;
   FixItHint RestrictFixIt;
+  FixItHint AtomicFixIt;
 
   const SourceManager &SM = S.getSourceManager();
 
   // FIXME: The locations here are set kind of arbitrarily. It'd be nicer to
   // find a range and grow it to encompass all the qualifiers, regardless of
   // the order in which they textually appear.
-  if (Quals & Qualifiers::Const) {
+  if (Quals & DeclSpec::TQ_const) {
     ConstFixIt = FixItHint::CreateRemoval(ConstQualLoc);
     QualStr = "const";
     ++NumQuals;
     if (!Loc.isValid() || SM.isBeforeInTranslationUnit(ConstQualLoc, Loc))
       Loc = ConstQualLoc;
   }
-  if (Quals & Qualifiers::Volatile) {
+  if (Quals & DeclSpec::TQ_volatile) {
     VolatileFixIt = FixItHint::CreateRemoval(VolatileQualLoc);
     QualStr += (NumQuals == 0 ? "volatile" : " volatile");
     ++NumQuals;
     if (!Loc.isValid() || SM.isBeforeInTranslationUnit(VolatileQualLoc, Loc))
       Loc = VolatileQualLoc;
   }
-  if (Quals & Qualifiers::Restrict) {
+  if (Quals & DeclSpec::TQ_restrict) {
     RestrictFixIt = FixItHint::CreateRemoval(RestrictQualLoc);
     QualStr += (NumQuals == 0 ? "restrict" : " restrict");
     ++NumQuals;
     if (!Loc.isValid() || SM.isBeforeInTranslationUnit(RestrictQualLoc, Loc))
       Loc = RestrictQualLoc;
   }
+  if (Quals & DeclSpec::TQ_atomic) {
+    AtomicFixIt = FixItHint::CreateRemoval(AtomicQualLoc);
+    QualStr += (NumQuals == 0 ? "_Atomic" : " _Atomic");
+    ++NumQuals;
+    if (!Loc.isValid() || SM.isBeforeInTranslationUnit(AtomicQualLoc, Loc))
+      Loc = AtomicQualLoc;
+  }
 
   assert(NumQuals > 0 && "No known qualifiers?");
 
   S.Diag(Loc, diag::warn_qual_return_type)
-    << QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt;
+    << QualStr << NumQuals
+    << ConstFixIt << VolatileFixIt << RestrictFixIt << AtomicFixIt;
 }
 
 static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
@@ -2496,16 +2543,18 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
             SourceLocation::getFromRawEncoding(PTI.ConstQualLoc),
             SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc),
             SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc),
+            SourceLocation::getFromRawEncoding(PTI.AtomicQualLoc),
             S);
 
       } else if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() &&
-          (!LangOpts.CPlusPlus ||
-           (!T->isDependentType() && !T->isRecordType()))) {
+                 (!LangOpts.CPlusPlus ||
+                  (!T->isDependentType() && !T->isRecordType()))) {
 
         DiagnoseIgnoredQualifiers(D.getDeclSpec().getTypeQualifiers(),
                                   D.getDeclSpec().getConstSpecLoc(),
                                   D.getDeclSpec().getVolatileSpecLoc(),
                                   D.getDeclSpec().getRestrictSpecLoc(),
+                                  D.getDeclSpec().getAtomicSpecLoc(),
                                   S);
       }
 
@@ -3310,13 +3359,22 @@ namespace {
       TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
     }
     void VisitAtomicTypeLoc(AtomicTypeLoc TL) {
-      TL.setKWLoc(DS.getTypeSpecTypeLoc());
-      TL.setParensRange(DS.getTypeofParensRange());
+      // An AtomicTypeLoc can come from either an _Atomic(...) type specifier
+      // or an _Atomic qualifier.
+      if (DS.getTypeSpecType() == DeclSpec::TST_atomic) {
+        TL.setKWLoc(DS.getTypeSpecTypeLoc());
+        TL.setParensRange(DS.getTypeofParensRange());
 
-      TypeSourceInfo *TInfo = 0;
-      Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
-      assert(TInfo);
-      TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
+        TypeSourceInfo *TInfo = 0;
+        Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
+        assert(TInfo);
+        TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
+      } else {
+        TL.setKWLoc(DS.getAtomicSpecLoc());
+        // No parens, to indicate this was spelled as an _Atomic qualifier.
+        TL.setParensRange(SourceRange());
+        Visit(TL.getValueLoc());
+      }
     }
 
     void VisitTypeLoc(TypeLoc TL) {
@@ -3439,6 +3497,29 @@ namespace {
   };
 }
 
+static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) {
+  SourceLocation Loc;
+  switch (Chunk.Kind) {
+  case DeclaratorChunk::Function:
+  case DeclaratorChunk::Array:
+  case DeclaratorChunk::Paren:
+    llvm_unreachable("cannot be _Atomic qualified");
+
+  case DeclaratorChunk::Pointer:
+    Loc = SourceLocation::getFromRawEncoding(Chunk.Ptr.AtomicQualLoc);
+    break;
+
+  case DeclaratorChunk::BlockPointer:
+  case DeclaratorChunk::Reference:
+  case DeclaratorChunk::MemberPointer:
+    // FIXME: Provide a source location for the _Atomic keyword.
+    break;
+  }
+
+  ATL.setKWLoc(Loc);
+  ATL.setParensRange(SourceRange());
+}
+
 /// \brief Create and instantiate a TypeSourceInfo with type source information.
 ///
 /// \param T QualType referring to the type as written in source code.
@@ -3460,6 +3541,14 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
   }
 
   for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
+    // An AtomicTypeLoc might be produced by an atomic qualifier in this
+    // declarator chunk.
+    // FIXME: Relative order of this and attributed type loc?
+    if (AtomicTypeLoc ATL = CurrTL.getAs<AtomicTypeLoc>()) {
+      fillAtomicQualLoc(ATL, D.getTypeObject(i));
+      CurrTL = ATL.getValueLoc().getUnqualifiedLoc();
+    }
+
     while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
       fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs());
       CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
index 23052c389eb2921347eef116fd6ed919b42f1b34..b95e08bcca10d766e872432868b943c59d94593e 100644 (file)
@@ -8,6 +8,12 @@ void f1() {
 void f2() {
   asm("foo" : "=r" (a)); // expected-error {{use of undeclared identifier 'a'}}
   asm("foo" : : "r" (b)); // expected-error {{use of undeclared identifier 'b'}} 
+
+  asm const (""); // expected-warning {{ignored const qualifier on asm}}
+  asm volatile ("");
+  asm restrict (""); // expected-warning {{ignored restrict qualifier on asm}}
+  // FIXME: Once GCC supports _Atomic, check whether it allows this.
+  asm _Atomic (""); // expected-warning {{ignored _Atomic qualifier on asm}}
 }
 
 
diff --git a/test/Parser/atomic.c b/test/Parser/atomic.c
new file mode 100644 (file)
index 0000000..432deeb
--- /dev/null
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c11 %s -fsyntax-only -verify -pedantic
+
+typedef _Atomic(int) atomic_int;
+typedef _Atomic int atomic_int;
+typedef _Atomic _Atomic _Atomic(int) atomic_int; // expected-warning {{duplicate '_Atomic' declaration specifier}}
+
+typedef const int const_int;
+
+typedef const atomic_int const_atomic_int;
+typedef _Atomic const int const_atomic_int;
+typedef const _Atomic int const_atomic_int;
+typedef const _Atomic(int) const_atomic_int;
+typedef const _Atomic(_Atomic int) const_atomic_int; // expected-error {{_Atomic cannot be applied to atomic type '_Atomic(int)'}}
+typedef _Atomic const_int const_atomic_int;
+typedef _Atomic(const_int) const_atomic_int; // expected-error {{_Atomic cannot be applied to qualified type 'const_int' (aka 'const int')}}
+
+typedef int *_Atomic atomic_int_ptr;
+typedef _Atomic(int *) atomic_int_ptr;
+typedef int (*_Atomic atomic_int_ptr);
+
+typedef int _Atomic *int_atomic_ptr;
+typedef _Atomic(int) *int_atomic_ptr;
+
+typedef int int_fn();
+typedef _Atomic int_fn atomic_int_fn; // expected-error {{_Atomic cannot be applied to function type 'int_fn' (aka 'int ()')}}
+typedef _Atomic int atomic_int_array[3];
+typedef _Atomic atomic_int_array atomic_int_atomic_array; // expected-error {{_Atomic cannot be applied to array type 'atomic_int_array' (aka '_Atomic(int) [3]')}}
+
+_Atomic struct S { int n; }; // expected-warning {{'_Atomic' ignored on this declaration}}
+
+typedef _Atomic int __attribute__((address_space(1))) atomic_addr_space_int;
+typedef _Atomic(int) __attribute__((address_space(1))) atomic_addr_space_int;
+
+typedef _Atomic int __attribute__((vector_size(16))) atomic_vector_int;
+typedef _Atomic(int __attribute__((vector_size(16)))) atomic_vector_int;
index 18707eb8c5ca2376be67734d3827802a08ed4e40..947bb3c5f406dcb44688004ac8a9372879b0faa6 100644 (file)
@@ -1,7 +1,9 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify -pedantic %s
 
 template<typename T> struct atomic {
   _Atomic(T) value;
+
+  void f() _Atomic; // expected-error {{expected ';' at end of declaration list}}
 };
 
 template<typename T> struct user {
@@ -15,9 +17,11 @@ user<int> u;
 struct A { };
 
 int &ovl1(_Atomic(int));
+int &ovl1(_Atomic int); // ok, redeclaration
 long &ovl1(_Atomic(long));
 float &ovl1(_Atomic(float));
 double &ovl1(_Atomic(A const *const *));
+double &ovl1(A const *const *_Atomic);
 short &ovl1(_Atomic(A **));
 
 void test_overloading(int i, float f, _Atomic(int) ai, _Atomic(float) af,
@@ -33,3 +37,22 @@ void test_overloading(int i, float f, _Atomic(int) ai, _Atomic(float) af,
   double &dr2 = ovl1(ac);
   short &sr1 = ovl1(a);
 }
+
+typedef int (A::*fp)() _Atomic; // expected-error {{expected ';' after top level declarator}} expected-warning {{does not declare anything}}
+
+typedef _Atomic(int(A::*)) atomic_mem_ptr_to_int;
+typedef int(A::*_Atomic atomic_mem_ptr_to_int);
+
+typedef _Atomic(int)(A::*mem_ptr_to_atomic_int);
+typedef _Atomic int(A::*mem_ptr_to_atomic_int);
+
+typedef _Atomic(int)&atomic_int_ref;
+typedef _Atomic int &atomic_int_ref;
+typedef _Atomic atomic_int_ref atomic_int_ref; // ok, qualifiers on references ignored in this case.
+
+typedef int &_Atomic atomic_reference_to_int; // expected-error {{'_Atomic' qualifier may not be applied to a reference}}
+typedef _Atomic(int &) atomic_reference_to_int; // expected-error {{_Atomic cannot be applied to reference type 'int &'}}
+
+struct S {
+  _Atomic union { int n; }; // expected-warning {{anonymous union cannot be '_Atomic'}}
+};