[llvm-branch-commits] [clang] [Clang] define memory scopes as a builtin enum (PR #185408)

Sameer Sahasrabuddhe via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Mar 9 05:39:15 PDT 2026


https://github.com/ssahasra created https://github.com/llvm/llvm-project/pull/185408

Clang currently represents memory scopes as pre-defined preprocessor macros that evaluate to integers. But so far, there are three sets of conflicting scopes: "common" clang scopes, HIP scopes and OpenCL scopes. These sets use the same integers in different orders, making it impossible to validate their use. A better approach is to represent these scopes as enum types, so that the integer values become less significant. Sema can now validate the scope argument by its type instead.

Both C and C++ define an enum for memory_order, but there is no standard enum for memory_scope. This change introduces a Clang-specific enum "memory_scope". The pre-defined macros are now mapped to this enum. Later changes can add similar enums for other languages.

enum __memory_scope {
  __memory_scope_system,
  __memory_scope_device,
  __memory_scope_workgroup,
  __memory_scope_wavefront,
  __memory_scope_singlethread,
  __memory_scope_cluster
};

Note that since this is not a standard enum, it cannot be introduced via stdatomic.h or other headers. Instead Sema builds this enum on demand when it sees an identifier that matches one of the enumerators. This ensures that the enum is injected in the AST only if it is used. Otherwise, it will show up in every program being compiled, which is noticeable in a number of test failures that were not expecting this enum.

For a gradual transition, Sema will continue to accept integer values for the "__scoped_atomic_*" builtins, but issue a warning in favour of the new enums. This change will only be visible to clients that use PCH files or clients like hip-rtc that store pre-processed files that are then passed to a newer compiler in the application's environment.

Assisted-By: Claude Sonnet 4.5

>From d5194b55562690d9f426c0746b2730e67e8ce333 Mon Sep 17 00:00:00 2001
From: Sameer Sahasrabuddhe <sameer.sahasrabuddhe at amd.com>
Date: Tue, 3 Mar 2026 11:16:51 +0530
Subject: [PATCH] [Clang] define memory scopes as a builtin enum

Clang currently represents memory scopes as pre-defined preprocessor macros that
evaluate to integers. But so far, there are three sets of conflicting scopes:
"common" clang scopes, HIP scopes and OpenCL scopes. These sets use the same
integers in different orders, making it impossible to validate their use. A
better approach is to represent these scopes as enum types, so that the integer
values become less significant. Sema can now validate the scope argument by its
type instead.

Both C and C++ define an enum for memory_order, but there is no standard enum
for memory_scope. This change introduces a Clang-specific enum "memory_scope".
The pre-defined macros are now mapped to this enum. Later changes can add
similar enums for other languages.

enum __memory_scope {
  __memory_scope_system,
  __memory_scope_device,
  __memory_scope_workgroup,
  __memory_scope_wavefront,
  __memory_scope_singlethread,
  __memory_scope_cluster
};

Note that since this is not a standard enum, it cannot be introduced via
stdatomic.h or other headers. Instead Sema builds this enum on demand when it
sees an identifier that matches one of the enumerators. This ensures that the
enum is injected in the AST only if it is used. Otherwise, it will show up in
every program being compiled, which is noticeable in a number of test failures
that were not expecting this enum.

For a gradual transition, Sema will continue to accept integer values for the
"__scoped_atomic_*" builtins, but issue a warning in favour of the new enums.
This change will only be visible to clients that use PCH files or clients like
hip-rtc that store pre-processed files that are then passed to a newer compiler
in the application's environment.

Assisted-By: Claude Sonnet 4.5
---
 clang/include/clang/AST/ASTContext.h          |   6 +
 clang/include/clang/AST/DeclID.h              |   3 +
 .../clang/Basic/DiagnosticSemaKinds.td        |   3 +
 clang/lib/AST/ASTContext.cpp                  |  88 +++++++++++++++
 clang/lib/Frontend/InitPreprocessor.cpp       |  12 +-
 clang/lib/Sema/SemaChecking.cpp               |  42 +++++++
 clang/lib/Sema/SemaLookup.cpp                 |  53 +++++++++
 clang/lib/Serialization/ASTReader.cpp         |   6 +
 clang/lib/Serialization/ASTWriter.cpp         |   1 +
 clang/test/Preprocessor/init-aarch64.c        |  24 ++--
 clang/test/Preprocessor/init-loongarch.c      |  24 ++--
 clang/test/Preprocessor/init.c                |  60 +++++-----
 .../test/Sema/builtin-memory-scope-conflict.c |  14 +++
 .../Sema/builtin-memory-scope-shadowing.c     |  52 +++++++++
 clang/test/Sema/builtin-memory-scope.c        |  56 +++++++++
 clang/test/Sema/scoped-atomic-ops.c           |  28 ++---
 .../Sema/scoped-atomic-scope-deprecation.c    | 106 ++++++++++++++++++
 clang/test/SemaOpenCL/atomic-ops.cl           |   4 +-
 18 files changed, 506 insertions(+), 76 deletions(-)
 create mode 100644 clang/test/Sema/builtin-memory-scope-conflict.c
 create mode 100644 clang/test/Sema/builtin-memory-scope-shadowing.c
 create mode 100644 clang/test/Sema/builtin-memory-scope.c
 create mode 100644 clang/test/Sema/scoped-atomic-scope-deprecation.c

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 05302c30d18d1..189c58a8f9e5b 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -515,6 +515,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// Declaration for the CUDA cudaLaunchDevice function.
   FunctionDecl *cudaLaunchDeviceDecl = nullptr;
 
+  /// The typedef for the __memory_scope enum type.
+  mutable TypedefDecl *MemoryScopeDecl = nullptr;
+
   /// Keeps track of all declaration attributes.
   ///
   /// Since so few decls have attrs, we keep them in a hash map instead of
@@ -1448,6 +1451,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// Retrieve the declaration for the 128-bit unsigned integer type.
   TypedefDecl *getUInt128Decl() const;
 
+  /// Retrieve the declaration for the __memory_scope enum type.
+  TypedefDecl *getMemoryScopeDecl() const;
+
   //===--------------------------------------------------------------------===//
   //                           Type Constructors
   //===--------------------------------------------------------------------===//
diff --git a/clang/include/clang/AST/DeclID.h b/clang/include/clang/AST/DeclID.h
index 47ae05b2747ae..c77ec3d8c8aab 100644
--- a/clang/include/clang/AST/DeclID.h
+++ b/clang/include/clang/AST/DeclID.h
@@ -65,6 +65,9 @@ enum PredefinedDeclIDs {
   /// The internal '__builtin_ms_va_list' typedef.
   PREDEF_DECL_BUILTIN_MS_VA_LIST_ID,
 
+  /// The internal '__memory_scope' typedef.
+  PREDEF_DECL_MEMORY_SCOPE_ID,
+
   /// The predeclared '_GUID' struct.
   PREDEF_DECL_BUILTIN_MS_GUID_ID,
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0e6b3f51a5231..9fbe0c9084936 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9636,6 +9636,9 @@ def warn_atomic_op_has_invalid_memory_order : Warning<
   InGroup<DiagGroup<"atomic-memory-ordering">>;
 def err_atomic_op_has_invalid_sync_scope : Error<
   "synchronization scope argument to atomic operation is invalid">;
+def warn_atomic_op_scope_should_be_enum : Warning<
+  "synchronization scope should be of type __memory_scope">,
+  InGroup<DiagGroup<"atomic-memory-scope">>;
 def warn_atomic_implicit_seq_cst : Warning<
   "implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary">,
   InGroup<DiagGroup<"atomic-implicit-seq-cst">>, DefaultIgnore;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index d9e9ae062e8d7..fcc2f6f4a41e5 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1215,6 +1215,94 @@ TypedefDecl *ASTContext::getUInt128Decl() const {
   return UInt128Decl;
 }
 
+TypedefDecl *ASTContext::getMemoryScopeDecl() const {
+  // Return cached value if already created
+  if (MemoryScopeDecl)
+    return MemoryScopeDecl;
+
+    // Create the enum
+#define MEMORY_SCOPE_ENUMERATORS(ENUM)                                         \
+  ENUM(__memory_scope_system, 0)                                               \
+  ENUM(__memory_scope_device, 1)                                               \
+  ENUM(__memory_scope_workgroup, 2)                                            \
+  ENUM(__memory_scope_wavefront, 3)                                            \
+  ENUM(__memory_scope_singlethread, 4)                                         \
+  ENUM(__memory_scope_cluster, 5)
+
+  const char *EnumName = "__memory_scope";
+
+  // Check if user has already declared enum __memory_scope
+  // If so, we cannot create our builtin - return nullptr to signal error
+  IdentifierInfo &II = Idents.get(EnumName);
+  DeclContext::lookup_result Existing =
+      getTranslationUnitDecl()->lookup(DeclarationName(&II));
+  if (!Existing.empty()) {
+    // User declared __memory_scope before we could create the builtin
+    // Return nullptr - caller will diagnose this error
+    return nullptr;
+  }
+
+  // Create enum (unscoped, works in both C and C++)
+  EnumDecl *MemoryScopeEnum = EnumDecl::Create(
+      *this, getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
+      &Idents.get(EnumName), nullptr, false, false, true);
+
+  MemoryScopeEnum->setIntegerType(IntTy);
+  MemoryScopeEnum->setImplicit();
+  MemoryScopeEnum->startDefinition();
+
+  // Track max value for bit calculation
+  int MaxValue = 0;
+
+  // Create enumerators
+  llvm::APSInt Val(getIntWidth(IntTy), false);
+
+#define ADD_ENUMERATOR(Name, Value)                                            \
+  Val = Value;                                                                 \
+  if ((Value) > MaxValue)                                                      \
+    MaxValue = (Value);                                                        \
+  {                                                                            \
+    EnumConstantDecl *Constant =                                               \
+        EnumConstantDecl::Create(*this, MemoryScopeEnum, SourceLocation(),     \
+                                 &Idents.get(#Name), IntTy, nullptr, Val);     \
+    Constant->setImplicit();                                                   \
+    MemoryScopeEnum->addDecl(Constant);                                        \
+  }
+
+  MEMORY_SCOPE_ENUMERATORS(ADD_ENUMERATOR)
+#undef ADD_ENUMERATOR
+
+  // Calculate bits needed for max value
+  unsigned NumPositiveBits =
+      MaxValue > 0 ? llvm::APInt(32, MaxValue).getActiveBits() : 0;
+
+  // Complete definition
+  MemoryScopeEnum->completeDefinition(IntTy, IntTy, NumPositiveBits, 0);
+
+  // Set enumerator types to the enum type (for C++)
+  QualType EnumType = getCanonicalTagType(MemoryScopeEnum);
+  for (EnumConstantDecl *Constant : MemoryScopeEnum->enumerators()) {
+    Constant->setType(EnumType);
+  }
+
+  // Add enum to TranslationUnit
+  getTranslationUnitDecl()->addDecl(MemoryScopeEnum);
+
+  // Create a typedef so we can use it without 'enum' keyword in C
+  TypedefDecl *TypedefD = TypedefDecl::Create(
+      *this, getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
+      &Idents.get(EnumName), getTrivialTypeSourceInfo(EnumType));
+  TypedefD->setImplicit();
+  getTranslationUnitDecl()->addDecl(TypedefD);
+
+  // Cache the typedef (mutable field allows modification in const method)
+  MemoryScopeDecl = TypedefD;
+
+#undef MEMORY_SCOPE_ENUMERATORS
+
+  return TypedefD;
+}
+
 void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) {
   auto *Ty = new (*this, alignof(BuiltinType)) BuiltinType(K);
   R = CanQualType::CreateUnsafe(QualType(Ty, 0));
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 1ccd74314f373..338320f6401b3 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -874,12 +874,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
   Builder.defineMacro("__ATOMIC_SEQ_CST", "5");
 
   // Define macros for the clang atomic scopes.
-  Builder.defineMacro("__MEMORY_SCOPE_SYSTEM", "0");
-  Builder.defineMacro("__MEMORY_SCOPE_DEVICE", "1");
-  Builder.defineMacro("__MEMORY_SCOPE_WRKGRP", "2");
-  Builder.defineMacro("__MEMORY_SCOPE_WVFRNT", "3");
-  Builder.defineMacro("__MEMORY_SCOPE_SINGLE", "4");
-  Builder.defineMacro("__MEMORY_SCOPE_CLUSTR", "5");
+  Builder.defineMacro("__MEMORY_SCOPE_SYSTEM", "__memory_scope_system");
+  Builder.defineMacro("__MEMORY_SCOPE_DEVICE", "__memory_scope_device");
+  Builder.defineMacro("__MEMORY_SCOPE_WRKGRP", "__memory_scope_workgroup");
+  Builder.defineMacro("__MEMORY_SCOPE_WVFRNT", "__memory_scope_wavefront");
+  Builder.defineMacro("__MEMORY_SCOPE_SINGLE", "__memory_scope_singlethread");
+  Builder.defineMacro("__MEMORY_SCOPE_CLUSTR", "__memory_scope_cluster");
 
   // Define macros for the OpenCL memory scope.
   // The values should match AtomicScopeOpenCLModel::ID enum.
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ba9890296ef96..a80aa60784c1d 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2099,6 +2099,27 @@ CheckBuiltinTargetInSupported(Sema &S, CallExpr *TheCall,
   return true;
 }
 
+/// CheckScopedAtomicScopeArgument - Check the scope argument for scoped atomic
+/// operations and fences. Emits a deprecation warning if an integer type is
+/// used instead of the __memory_scope enum.
+static void CheckScopedAtomicScopeArgument(Sema &S, Expr *Scope) {
+  assert(Scope->getType()->isIntegerType() &&
+         "Non-integer type should have emitted an error before reaching here");
+  // Strip implicit casts to get the original expression type
+  Expr *OrigScope = Scope->IgnoreParenImpCasts();
+
+  // Check if it's the __memory_scope enum type
+  if (const auto *EnumTy = OrigScope->getType()->getAs<EnumType>()) {
+    if (EnumTy->getDecl()->getName() == "__memory_scope") {
+      return;
+    }
+  }
+
+  // Use of any other integer type gets a warning
+  S.Diag(Scope->getBeginLoc(), diag::warn_atomic_op_scope_should_be_enum)
+      << Scope->getSourceRange();
+}
+
 static void CheckNonNullArgument(Sema &S, const Expr *ArgExpr,
                                  SourceLocation CallSiteLoc);
 
@@ -3181,6 +3202,14 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
     Diag(TheCall->getBeginLoc(), diag::warn_atomic_implicit_seq_cst)
         << TheCall->getCallee()->getSourceRange();
     break;
+  case Builtin::BI__scoped_atomic_thread_fence: {
+    // Validate the scope argument (second argument)
+    if (TheCall->getNumArgs() >= 2) {
+      Expr *Scope = TheCall->getArg(1);
+      CheckScopedAtomicScopeArgument(*this, Scope);
+    }
+    break;
+  }
   case Builtin::BI__builtin_nontemporal_load:
   case Builtin::BI__builtin_nontemporal_store:
     return BuiltinNontemporalOverloaded(TheCallResult);
@@ -5157,12 +5186,25 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
 
   if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) {
     auto *Scope = Args[Args.size() - 1];
+
+    // If the scope is an integer constant, validate its value
     if (std::optional<llvm::APSInt> Result =
             Scope->getIntegerConstantExpr(Context)) {
       if (!ScopeModel->isValid(Result->getZExtValue()))
         Diag(Scope->getBeginLoc(), diag::err_atomic_op_has_invalid_sync_scope)
             << Scope->getSourceRange();
     }
+
+    if (!Scope->getType()->isIntegerType()) {
+      // Ensure that it is an integer.
+      Diag(Scope->getBeginLoc(), diag::err_atomic_op_has_invalid_sync_scope)
+          << Scope->getSourceRange();
+    } else if (BuiltinInfo && BuiltinInfo->Langs == ALL_LANGUAGES) {
+      // In the case of language-agnostic builtins, also check if it uses the
+      // builtin enum type "__memory_scope".
+      CheckScopedAtomicScopeArgument(*this, Scope);
+    }
+
     SubExprs.push_back(Scope);
   }
 
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index a983a4a9a3378..c881e71da1fa4 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2211,6 +2211,52 @@ bool LookupResult::isAvailableForLookup(Sema &SemaRef, NamedDecl *ND) {
   return false;
 }
 
+/// Try to create a builtin __memory_scope typedef or enumerator.
+/// Returns true if a declaration was added to R.
+static bool TryCreateMemoryScopeBuiltin(Sema &S, LookupResult &R,
+                                        const IdentifierInfo &II) {
+  // Don't create builtins during redeclaration lookup - this would conflict
+  // with user declarations of the same name
+  if (R.isForRedeclaration())
+    return false;
+
+  if (II.getName() == "__memory_scope") {
+    // Looking up __memory_scope typedef itself
+    if (TypedefDecl *TD = S.Context.getMemoryScopeDecl()) {
+      R.addDecl(TD);
+      R.resolveKind();
+      return true;
+    }
+    return false;
+  }
+
+  if (II.getName().starts_with("__memory_scope_")) {
+    // Looking up a __memory_scope enumerator
+    TypedefDecl *TD = S.Context.getMemoryScopeDecl();
+    if (!TD) {
+      // getMemoryScopeDecl() returned nullptr - user declared __memory_scope
+      // The enumerator won't be found, resulting in an "undeclared identifier"
+      // error
+      return false;
+    }
+
+    // Find the specific enumerator
+    if (const EnumType *ET = TD->getUnderlyingType()->getAs<EnumType>()) {
+      if (EnumDecl *ED = ET->getDecl()) {
+        for (auto *Enumerator : ED->enumerators()) {
+          if (Enumerator->getName() == II.getName()) {
+            R.addDecl(Enumerator);
+            R.resolveKind();
+            return true;
+          }
+        }
+      }
+    }
+  }
+
+  return false;
+}
+
 bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation,
                       bool ForceNoCPlusPlus) {
   DeclarationName Name = R.getLookupName();
@@ -2309,6 +2355,13 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation,
       return true;
   }
 
+  // Check for __memory_scope builtins even when AllowBuiltinCreation is false,
+  // because we want to support __memory_scope as a builtin type name.
+  if (IdentifierInfo *II = Name.getAsIdentifierInfo()) {
+    if (TryCreateMemoryScopeBuiltin(*this, R, *II))
+      return true;
+  }
+
   // If we didn't find a use of this identifier, and if the identifier
   // corresponds to a compiler builtin, create the decl object for the builtin
   // now, injecting it into translation unit scope, and return it.
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index b82ae971bc84d..ccd99802085cf 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -8421,6 +8421,12 @@ Decl *ASTReader::getPredefinedDecl(PredefinedDeclIDs ID) {
     NewLoaded = Context.getBuiltinVaListDecl();
     break;
 
+  case PREDEF_DECL_MEMORY_SCOPE_ID:
+    if (Context.MemoryScopeDecl)
+      return Context.MemoryScopeDecl;
+    NewLoaded = Context.getMemoryScopeDecl();
+    break;
+
   case PREDEF_DECL_VA_LIST_TAG:
     if (Context.VaListTagDecl)
       return Context.VaListTagDecl;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index ec718169550aa..b562d8aad929c 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5647,6 +5647,7 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) {
   RegisterPredefDecl(Context.VaListTagDecl, PREDEF_DECL_VA_LIST_TAG);
   RegisterPredefDecl(Context.BuiltinMSVaListDecl,
                      PREDEF_DECL_BUILTIN_MS_VA_LIST_ID);
+  RegisterPredefDecl(Context.MemoryScopeDecl, PREDEF_DECL_MEMORY_SCOPE_ID);
   RegisterPredefDecl(Context.MSGuidTagDecl,
                      PREDEF_DECL_BUILTIN_MS_GUID_ID);
   RegisterPredefDecl(Context.MSTypeInfoTagDecl,
diff --git a/clang/test/Preprocessor/init-aarch64.c b/clang/test/Preprocessor/init-aarch64.c
index 09e3fc926a309..4d4bb419b6f5b 100644
--- a/clang/test/Preprocessor/init-aarch64.c
+++ b/clang/test/Preprocessor/init-aarch64.c
@@ -235,12 +235,12 @@
 // AARCH64-NEXT: #define __LONG_MAX__ 9223372036854775807L
 // AARCH64-NEXT: #define __LONG_WIDTH__ 64
 // AARCH64-NEXT: #define __LP64__ 1
-// AARCH64-NEXT: #define __MEMORY_SCOPE_CLUSTR 5
-// AARCH64-NEXT: #define __MEMORY_SCOPE_DEVICE 1
-// AARCH64-NEXT: #define __MEMORY_SCOPE_SINGLE 4
-// AARCH64-NEXT: #define __MEMORY_SCOPE_SYSTEM 0
-// AARCH64-NEXT: #define __MEMORY_SCOPE_WRKGRP 2
-// AARCH64-NEXT: #define __MEMORY_SCOPE_WVFRNT 3
+// AARCH64-NEXT: #define __MEMORY_SCOPE_CLUSTR __memory_scope_cluster
+// AARCH64-NEXT: #define __MEMORY_SCOPE_DEVICE __memory_scope_device
+// AARCH64-NEXT: #define __MEMORY_SCOPE_SINGLE __memory_scope_singlethread
+// AARCH64-NEXT: #define __MEMORY_SCOPE_SYSTEM __memory_scope_system
+// AARCH64-NEXT: #define __MEMORY_SCOPE_WRKGRP __memory_scope_workgroup
+// AARCH64-NEXT: #define __MEMORY_SCOPE_WVFRNT __memory_scope_wavefront
 // AARCH64-NEXT: #define __NO_INLINE__ 1
 // AARCH64-NEXT: #define __NO_MATH_ERRNO__ 1
 // AARCH64-NEXT: #define __OBJC_BOOL_IS_BOOL 0
@@ -991,12 +991,12 @@
 // ARM64EC-MSVC: #define __LONG_LONG_MAX__ 9223372036854775807LL
 // ARM64EC-MSVC: #define __LONG_MAX__ 2147483647L
 // ARM64EC-MSVC: #define __LONG_WIDTH__ 32
-// ARM64EC-MSVC: #define __MEMORY_SCOPE_CLUSTR 5
-// ARM64EC-MSVC: #define __MEMORY_SCOPE_DEVICE 1
-// ARM64EC-MSVC: #define __MEMORY_SCOPE_SINGLE 4
-// ARM64EC-MSVC: #define __MEMORY_SCOPE_SYSTEM 0
-// ARM64EC-MSVC: #define __MEMORY_SCOPE_WRKGRP 2
-// ARM64EC-MSVC: #define __MEMORY_SCOPE_WVFRNT 3
+// ARM64EC-MSVC: #define __MEMORY_SCOPE_CLUSTR __memory_scope_cluster
+// ARM64EC-MSVC: #define __MEMORY_SCOPE_DEVICE __memory_scope_device
+// ARM64EC-MSVC: #define __MEMORY_SCOPE_SINGLE __memory_scope_singlethread
+// ARM64EC-MSVC: #define __MEMORY_SCOPE_SYSTEM __memory_scope_system
+// ARM64EC-MSVC: #define __MEMORY_SCOPE_WRKGRP __memory_scope_workgroup
+// ARM64EC-MSVC: #define __MEMORY_SCOPE_WVFRNT __memory_scope_wavefront
 // ARM64EC-MSVC: #define __NO_INLINE__ 1
 // ARM64EC-MSVC: #define __NO_MATH_ERRNO__ 1
 // ARM64EC-MSVC: #define __OBJC_BOOL_IS_BOOL 0
diff --git a/clang/test/Preprocessor/init-loongarch.c b/clang/test/Preprocessor/init-loongarch.c
index ef9a043a8ddde..51c2449c32948 100644
--- a/clang/test/Preprocessor/init-loongarch.c
+++ b/clang/test/Preprocessor/init-loongarch.c
@@ -182,12 +182,12 @@
 // LA32: #define __LONG_LONG_MAX__ 9223372036854775807LL
 // LA32: #define __LONG_MAX__ 2147483647L
 // LA32: #define __LONG_WIDTH__ 32
-// LA32: #define __MEMORY_SCOPE_CLUSTR 5
-// LA32: #define __MEMORY_SCOPE_DEVICE 1
-// LA32: #define __MEMORY_SCOPE_SINGLE 4
-// LA32: #define __MEMORY_SCOPE_SYSTEM 0
-// LA32: #define __MEMORY_SCOPE_WRKGRP 2
-// LA32: #define __MEMORY_SCOPE_WVFRNT 3
+// LA32: #define __MEMORY_SCOPE_CLUSTR __memory_scope_cluster
+// LA32: #define __MEMORY_SCOPE_DEVICE __memory_scope_device
+// LA32: #define __MEMORY_SCOPE_SINGLE __memory_scope_singlethread
+// LA32: #define __MEMORY_SCOPE_SYSTEM __memory_scope_system
+// LA32: #define __MEMORY_SCOPE_WRKGRP __memory_scope_workgroup
+// LA32: #define __MEMORY_SCOPE_WVFRNT __memory_scope_wavefront
 // LA32: #define __NO_INLINE__ 1
 // LA32: #define __NO_MATH_ERRNO__ 1
 // LA32: #define __OBJC_BOOL_IS_BOOL 0
@@ -515,12 +515,12 @@
 // LA64: #define __LONG_MAX__ 9223372036854775807L
 // LA64: #define __LONG_WIDTH__ 64
 // LA64: #define __LP64__ 1
-// LA64: #define __MEMORY_SCOPE_CLUSTR 5
-// LA64: #define __MEMORY_SCOPE_DEVICE 1
-// LA64: #define __MEMORY_SCOPE_SINGLE 4
-// LA64: #define __MEMORY_SCOPE_SYSTEM 0
-// LA64: #define __MEMORY_SCOPE_WRKGRP 2
-// LA64: #define __MEMORY_SCOPE_WVFRNT 3
+// LA64: #define __MEMORY_SCOPE_CLUSTR __memory_scope_cluster
+// LA64: #define __MEMORY_SCOPE_DEVICE __memory_scope_device
+// LA64: #define __MEMORY_SCOPE_SINGLE __memory_scope_singlethread
+// LA64: #define __MEMORY_SCOPE_SYSTEM __memory_scope_system
+// LA64: #define __MEMORY_SCOPE_WRKGRP __memory_scope_workgroup
+// LA64: #define __MEMORY_SCOPE_WVFRNT __memory_scope_wavefront
 // LA64: #define __NO_INLINE__ 1
 // LA64: #define __NO_MATH_ERRNO__ 1
 // LA64: #define __OBJC_BOOL_IS_BOOL 0
diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c
index 80b7a6399e5f4..387bc728cd213 100644
--- a/clang/test/Preprocessor/init.c
+++ b/clang/test/Preprocessor/init.c
@@ -1901,12 +1901,12 @@
 // WEBASSEMBLY64-NEXT:#define __LONG_MAX__ 9223372036854775807L
 // WEBASSEMBLY64-NEXT:#define __LONG_WIDTH__ 64
 // WEBASSEMBLY64-NEXT:#define __LP64__ 1
-// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_CLUSTR 5
-// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_DEVICE 1
-// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_SINGLE 4
-// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_SYSTEM 0
-// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_WRKGRP 2
-// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_WVFRNT 3
+// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_CLUSTR __memory_scope_cluster
+// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_DEVICE __memory_scope_device
+// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_SINGLE __memory_scope_singlethread
+// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_SYSTEM __memory_scope_system
+// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_WRKGRP __memory_scope_workgroup
+// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_WVFRNT __memory_scope_wavefront
 // WEBASSEMBLY-NEXT:#define __NO_INLINE__ 1
 // WEBASSEMBLY-NEXT:#define __NO_MATH_ERRNO__ 1
 // WEBASSEMBLY-NEXT:#define __OBJC_BOOL_IS_BOOL 0
@@ -2232,12 +2232,12 @@
 // AVR:#define __LDBL_MIN__ 1.17549435e-38L
 // AVR:#define __LONG_LONG_MAX__ 9223372036854775807LL
 // AVR:#define __LONG_MAX__ 2147483647L
-// AVR:#define __MEMORY_SCOPE_CLUSTR 5
-// AVR:#define __MEMORY_SCOPE_DEVICE 1
-// AVR:#define __MEMORY_SCOPE_SINGLE 4
-// AVR:#define __MEMORY_SCOPE_SYSTEM 0
-// AVR:#define __MEMORY_SCOPE_WRKGRP 2
-// AVR:#define __MEMORY_SCOPE_WVFRNT 3
+// AVR:#define __MEMORY_SCOPE_CLUSTR __memory_scope_cluster
+// AVR:#define __MEMORY_SCOPE_DEVICE __memory_scope_device
+// AVR:#define __MEMORY_SCOPE_SINGLE __memory_scope_singlethread
+// AVR:#define __MEMORY_SCOPE_SYSTEM __memory_scope_system
+// AVR:#define __MEMORY_SCOPE_WRKGRP __memory_scope_workgroup
+// AVR:#define __MEMORY_SCOPE_WVFRNT __memory_scope_wavefront
 // AVR:#define __NO_INLINE__ 1
 // AVR:#define __ORDER_BIG_ENDIAN__ 4321
 // AVR:#define __ORDER_LITTLE_ENDIAN__ 1234
@@ -2538,12 +2538,12 @@
 // RISCV32: #define __LITTLE_ENDIAN__ 1
 // RISCV32: #define __LONG_LONG_MAX__ 9223372036854775807LL
 // RISCV32: #define __LONG_MAX__ 2147483647L
-// RISCV32: #define __MEMORY_SCOPE_CLUSTR 5
-// RISCV32: #define __MEMORY_SCOPE_DEVICE 1
-// RISCV32: #define __MEMORY_SCOPE_SINGLE 4
-// RISCV32: #define __MEMORY_SCOPE_SYSTEM 0
-// RISCV32: #define __MEMORY_SCOPE_WRKGRP 2
-// RISCV32: #define __MEMORY_SCOPE_WVFRNT 3
+// RISCV32: #define __MEMORY_SCOPE_CLUSTR __memory_scope_cluster
+// RISCV32: #define __MEMORY_SCOPE_DEVICE __memory_scope_device
+// RISCV32: #define __MEMORY_SCOPE_SINGLE __memory_scope_singlethread
+// RISCV32: #define __MEMORY_SCOPE_SYSTEM __memory_scope_system
+// RISCV32: #define __MEMORY_SCOPE_WRKGRP __memory_scope_workgroup
+// RISCV32: #define __MEMORY_SCOPE_WVFRNT __memory_scope_wavefront
 // RISCV32: #define __NO_INLINE__ 1
 // RISCV32: #define __POINTER_WIDTH__ 32
 // RISCV32: #define __PRAGMA_REDEFINE_EXTNAME 1
@@ -2763,12 +2763,12 @@
 // RISCV64: #define __LONG_LONG_MAX__ 9223372036854775807LL
 // RISCV64: #define __LONG_MAX__ 9223372036854775807L
 // RISCV64: #define __LP64__ 1
-// RISCV64: #define __MEMORY_SCOPE_CLUSTR 5
-// RISCV64: #define __MEMORY_SCOPE_DEVICE 1
-// RISCV64: #define __MEMORY_SCOPE_SINGLE 4
-// RISCV64: #define __MEMORY_SCOPE_SYSTEM 0
-// RISCV64: #define __MEMORY_SCOPE_WRKGRP 2
-// RISCV64: #define __MEMORY_SCOPE_WVFRNT 3
+// RISCV64: #define __MEMORY_SCOPE_CLUSTR __memory_scope_cluster
+// RISCV64: #define __MEMORY_SCOPE_DEVICE __memory_scope_device
+// RISCV64: #define __MEMORY_SCOPE_SINGLE __memory_scope_singlethread
+// RISCV64: #define __MEMORY_SCOPE_SYSTEM __memory_scope_system
+// RISCV64: #define __MEMORY_SCOPE_WRKGRP __memory_scope_workgroup
+// RISCV64: #define __MEMORY_SCOPE_WVFRNT __memory_scope_wavefront
 // RISCV64: #define __NO_INLINE__ 1
 // RISCV64: #define __POINTER_WIDTH__ 64
 // RISCV64: #define __PRAGMA_REDEFINE_EXTNAME 1
@@ -3027,12 +3027,12 @@
 // XTENSA: #define __LONG_LONG_MAX__ 9223372036854775807LL
 // XTENSA: #define __LONG_MAX__ 2147483647L
 // XTENSA: #define __LONG_WIDTH__ 32
-// XTENSA: #define __MEMORY_SCOPE_CLUSTR 5
-// XTENSA: #define __MEMORY_SCOPE_DEVICE 1
-// XTENSA: #define __MEMORY_SCOPE_SINGLE 4
-// XTENSA: #define __MEMORY_SCOPE_SYSTEM 0
-// XTENSA: #define __MEMORY_SCOPE_WRKGRP 2
-// XTENSA: #define __MEMORY_SCOPE_WVFRNT 3
+// XTENSA: #define __MEMORY_SCOPE_CLUSTR __memory_scope_cluster
+// XTENSA: #define __MEMORY_SCOPE_DEVICE __memory_scope_device
+// XTENSA: #define __MEMORY_SCOPE_SINGLE __memory_scope_singlethread
+// XTENSA: #define __MEMORY_SCOPE_SYSTEM __memory_scope_system
+// XTENSA: #define __MEMORY_SCOPE_WRKGRP __memory_scope_workgroup
+// XTENSA: #define __MEMORY_SCOPE_WVFRNT __memory_scope_wavefront
 // XTENSA: #define __NO_INLINE__ 1
 // XTENSA: #define __NO_MATH_ERRNO__ 1
 // XTENSA: #define __OBJC_BOOL_IS_BOOL 0
diff --git a/clang/test/Sema/builtin-memory-scope-conflict.c b/clang/test/Sema/builtin-memory-scope-conflict.c
new file mode 100644
index 0000000000000..32e57b4570784
--- /dev/null
+++ b/clang/test/Sema/builtin-memory-scope-conflict.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c11 -verify %s
+
+// Test that declaring __memory_scope conflicts with the builtin enum
+
+// User declares their own enum first
+enum __memory_scope {
+  my_value = 0
+};
+
+// Trying to use builtin identifier will find the user's enum
+// but the builtin enumerators won't be available
+void test(void) {
+  __memory_scope x = __memory_scope_system; // expected-error {{must use 'enum' tag}} expected-error {{use of undeclared identifier '__memory_scope_system'}}
+}
diff --git a/clang/test/Sema/builtin-memory-scope-shadowing.c b/clang/test/Sema/builtin-memory-scope-shadowing.c
new file mode 100644
index 0000000000000..fc12952f8a287
--- /dev/null
+++ b/clang/test/Sema/builtin-memory-scope-shadowing.c
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c11 -verify -triple=amdgcn-amd-amdhsa %s
+
+// Test that user enumerators shadowing builtin __memory_scope_* names
+// are caught by type checking when passed to scoped atomic operations.
+
+// User declares an enumerator that shadows a builtin name
+enum __foo {
+  __memory_scope_system = 999
+};
+
+void test_shadowing_rejected(int *ptr) {
+  int val;
+
+  // Using the user's enumerator (which has type 'enum __foo' not '__memory_scope')
+  // triggers a warning, plus an error for the invalid scope value
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, __memory_scope_system); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+
+  val = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, __memory_scope_system); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+
+  __scoped_atomic_store_n(ptr, 42, __ATOMIC_RELAXED, __memory_scope_system); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+}
+
+void test_builtin_still_works(int *ptr) {
+  int val;
+
+  // The real builtin __memory_scope_device should still work
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, __memory_scope_device); // no warning - correct type
+
+  val = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, __memory_scope_device); // no warning
+}
+
+void test_integer_literal_deprecated(int *ptr) {
+  int val;
+
+  // Integer literals should get deprecation warning (not error)
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, 0); // expected-warning {{synchronization scope should be of type __memory_scope}}
+
+  val = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, 1); // expected-warning {{synchronization scope should be of type __memory_scope}}
+
+  // Integer variables should also get deprecation warning
+  int scope = 2;
+  __scoped_atomic_store_n(ptr, 42, __ATOMIC_RELAXED, scope); // expected-warning {{synchronization scope should be of type __memory_scope}}
+}
+
+// Test shadowing with anonymous enum
+enum {
+  __memory_scope_device = 888
+};
+
+void test_anonymous_enum_shadowing(int *ptr) {
+  int val = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, __memory_scope_device); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+}
diff --git a/clang/test/Sema/builtin-memory-scope.c b/clang/test/Sema/builtin-memory-scope.c
new file mode 100644
index 0000000000000..f75551280f26f
--- /dev/null
+++ b/clang/test/Sema/builtin-memory-scope.c
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c11 -verify %s
+// expected-no-diagnostics
+
+// Test that __memory_scope enum is available without any includes
+
+void test_basic_usage(void) {
+  __memory_scope scope1 = __memory_scope_singlethread;
+  __memory_scope scope2 = __memory_scope_wavefront;
+  __memory_scope scope3 = __memory_scope_workgroup;
+  __memory_scope scope4 = __memory_scope_cluster;
+  __memory_scope scope5 = __memory_scope_device;
+  __memory_scope scope6 = __memory_scope_system;
+}
+
+void test_assignment(void) {
+  __memory_scope scope = __memory_scope_wavefront;
+  scope = __memory_scope_device;
+  scope = __memory_scope_system;
+}
+
+void test_comparison(void) {
+  __memory_scope scope = __memory_scope_wavefront;
+
+  if (scope == __memory_scope_wavefront) {
+    // ok
+  }
+
+  if (scope != __memory_scope_device) {
+    // ok
+  }
+}
+
+void test_switch(__memory_scope scope) {
+  switch (scope) {
+    case __memory_scope_singlethread:
+      break;
+    case __memory_scope_wavefront:
+      break;
+    case __memory_scope_workgroup:
+      break;
+    case __memory_scope_cluster:
+      break;
+    case __memory_scope_device:
+      break;
+    case __memory_scope_system:
+      break;
+  }
+}
+
+void test_function_param(__memory_scope scope) {
+  // ok
+}
+
+__memory_scope test_function_return(void) {
+  return __memory_scope_device;
+}
diff --git a/clang/test/Sema/scoped-atomic-ops.c b/clang/test/Sema/scoped-atomic-ops.c
index ab89f0738d0b5..a8f68c3ed25ec 100644
--- a/clang/test/Sema/scoped-atomic-ops.c
+++ b/clang/test/Sema/scoped-atomic-ops.c
@@ -5,14 +5,14 @@
 int fi1a(int *i) {
   int v;
   __scoped_atomic_load(i, &v, __ATOMIC_RELAXED); // expected-error {{too few arguments to function call, expected 4, have 3}}
-  __scoped_atomic_load(i, &v, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
+  __scoped_atomic_load(i, &v, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
   __scoped_atomic_load(i, &v, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
   return v;
 }
 
 int fi1b(int *i) {
   *i = __scoped_atomic_load_n(i, __ATOMIC_RELAXED); // expected-error {{too few arguments to function call, expected 3, have 2}}
-  *i = __scoped_atomic_load_n(i, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *i = __scoped_atomic_load_n(i, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
   *i = __scoped_atomic_load_n(i, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
   return *i;
 }
@@ -20,14 +20,14 @@ int fi1b(int *i) {
 int fi2a(int *i) {
   int v;
   __scoped_atomic_store(i, &v, __ATOMIC_RELAXED); // expected-error {{too few arguments to function call, expected 4, have 3}}
-  __scoped_atomic_store(i, &v, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
+  __scoped_atomic_store(i, &v, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
   __scoped_atomic_store(i, &v, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
   return v;
 }
 
 void fi2b(int *i) {
   __scoped_atomic_store_n(i, 1, __ATOMIC_RELAXED); // expected-error {{too few arguments to function call, expected 4, have 3}}
-  __scoped_atomic_store_n(i, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
+  __scoped_atomic_store_n(i, 1, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
   __scoped_atomic_store_n(i, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
 }
 
@@ -71,16 +71,16 @@ void fi3c(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h, unsign
 }
 
 void fi3d(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h, unsigned *i, unsigned *j) {
-  *a = __scoped_atomic_fetch_add(a, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
-  *b = __scoped_atomic_fetch_sub(b, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
-  *c = __scoped_atomic_fetch_and(c, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
-  *d = __scoped_atomic_fetch_or(d, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
-  *e = __scoped_atomic_fetch_xor(e, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
-  *f = __scoped_atomic_fetch_nand(f, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
-  *g = __scoped_atomic_fetch_min(g, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
-  *h = __scoped_atomic_fetch_max(h, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
-  *i = __scoped_atomic_fetch_uinc(i, 1u, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
-  *j = __scoped_atomic_fetch_udec(j, 1u, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *a = __scoped_atomic_fetch_add(a, 1, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *b = __scoped_atomic_fetch_sub(b, 1, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *c = __scoped_atomic_fetch_and(c, 1, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *d = __scoped_atomic_fetch_or(d, 1, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *e = __scoped_atomic_fetch_xor(e, 1, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *f = __scoped_atomic_fetch_nand(f, 1, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *g = __scoped_atomic_fetch_min(g, 1, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *h = __scoped_atomic_fetch_max(h, 1, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *i = __scoped_atomic_fetch_uinc(i, 1u, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *j = __scoped_atomic_fetch_udec(j, 1u, __ATOMIC_RELAXED, 42); // expected-warning {{synchronization scope should be of type __memory_scope}} expected-error {{synchronization scope argument to atomic operation is invalid}}
 }
 
 void fi3e(float *a, float *b, float *c, float *d, float *e, float *f) {
diff --git a/clang/test/Sema/scoped-atomic-scope-deprecation.c b/clang/test/Sema/scoped-atomic-scope-deprecation.c
new file mode 100644
index 0000000000000..09c418c16d523
--- /dev/null
+++ b/clang/test/Sema/scoped-atomic-scope-deprecation.c
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 -x c -triple=amdgcn-amd-amdhsa -verify -fsyntax-only %s
+// RUN: %clang_cc1 -x c -triple=x86_64-pc-linux-gnu -verify -fsyntax-only %s
+// RUN: %clang_cc1 -x c -triple=spirv64-unknown-unknown -verify -fsyntax-only %s
+
+// Test deprecation warning for integer types used as scope arguments
+
+void test_integer_literal_scope(int *ptr) {
+  int val;
+  // Using integer literals should trigger deprecation warning
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, 0); // expected-warning {{synchronization scope should be of type __memory_scope}}
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, 1); // expected-warning {{synchronization scope should be of type __memory_scope}}
+  *ptr = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, 2); // expected-warning {{synchronization scope should be of type __memory_scope}}
+}
+
+void test_integer_variable_scope(int *ptr) {
+  int val;
+  int scope = 0;
+  // Using integer variables should trigger deprecation warning
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, scope); // expected-warning {{synchronization scope should be of type __memory_scope}}
+  *ptr = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, scope); // expected-warning {{synchronization scope should be of type __memory_scope}}
+}
+
+void test_enum_scope_no_warning(int *ptr) {
+  int val;
+  // Using __memory_scope enum values should NOT trigger warning
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, __memory_scope_system); // no warning
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, __memory_scope_device); // no warning
+  *ptr = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, __memory_scope_workgroup); // no warning
+}
+
+void test_macro_scope_no_warning(int *ptr) {
+  int val;
+  // Using __MEMORY_SCOPE_* macros (which expand to enum values) should NOT trigger warning
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM); // no warning
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, __MEMORY_SCOPE_DEVICE); // no warning
+  *ptr = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, __MEMORY_SCOPE_WRKGRP); // no warning
+}
+
+void test_various_scoped_atomics_with_integer(int *ptr) {
+  // Test deprecation warning with various scoped atomic operations
+  *ptr = __scoped_atomic_fetch_add(ptr, 1, __ATOMIC_RELAXED, 0); // expected-warning {{synchronization scope should be of type __memory_scope}}
+  *ptr = __scoped_atomic_add_fetch(ptr, 1, __ATOMIC_RELAXED, 1); // expected-warning {{synchronization scope should be of type __memory_scope}}
+  *ptr = __scoped_atomic_fetch_sub(ptr, 1, __ATOMIC_RELAXED, 2); // expected-warning {{synchronization scope should be of type __memory_scope}}
+  __scoped_atomic_store_n(ptr, 1, __ATOMIC_RELAXED, 3); // expected-warning {{synchronization scope should be of type __memory_scope}}
+}
+
+void test_various_scoped_atomics_with_enum(int *ptr) {
+  // Test NO warning with various scoped atomic operations using enum
+  *ptr = __scoped_atomic_fetch_add(ptr, 1, __ATOMIC_RELAXED, __memory_scope_device); // no warning
+  *ptr = __scoped_atomic_add_fetch(ptr, 1, __ATOMIC_RELAXED, __memory_scope_system); // no warning
+  *ptr = __scoped_atomic_fetch_sub(ptr, 1, __ATOMIC_RELAXED, __memory_scope_workgroup); // no warning
+  __scoped_atomic_store_n(ptr, 1, __ATOMIC_RELAXED, __memory_scope_wavefront); // no warning
+}
+
+void test_fence_with_integer() {
+  // Test deprecation warning with __scoped_atomic_thread_fence using integer literals
+  __scoped_atomic_thread_fence(__ATOMIC_SEQ_CST, 0); // expected-warning {{synchronization scope should be of type __memory_scope}}
+  __scoped_atomic_thread_fence(__ATOMIC_ACQUIRE, 1); // expected-warning {{synchronization scope should be of type __memory_scope}}
+
+  int scope_var = 2;
+  __scoped_atomic_thread_fence(__ATOMIC_RELEASE, scope_var); // expected-warning {{synchronization scope should be of type __memory_scope}}
+}
+
+void test_fence_with_enum() {
+  // Test NO warning with __scoped_atomic_thread_fence using enum values
+  __scoped_atomic_thread_fence(__ATOMIC_SEQ_CST, __memory_scope_system); // no warning
+  __scoped_atomic_thread_fence(__ATOMIC_ACQUIRE, __memory_scope_device); // no warning
+  __scoped_atomic_thread_fence(__ATOMIC_RELEASE, __memory_scope_workgroup); // no warning
+}
+
+void test_fence_with_macro() {
+  // Test NO warning with __scoped_atomic_thread_fence using macros
+  __scoped_atomic_thread_fence(__ATOMIC_SEQ_CST, __MEMORY_SCOPE_SYSTEM); // no warning
+  __scoped_atomic_thread_fence(__ATOMIC_ACQUIRE, __MEMORY_SCOPE_DEVICE); // no warning
+  __scoped_atomic_thread_fence(__ATOMIC_RELEASE, __MEMORY_SCOPE_WRKGRP); // no warning
+}
+
+void helper_with_scope_param(__memory_scope scope, int *ptr, int val) {
+  // Test that passing __memory_scope as function parameter works without warning
+  __scoped_atomic_store_n(ptr, val, __ATOMIC_RELAXED, scope); // no warning
+  *ptr = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, scope); // no warning
+  *ptr = __scoped_atomic_fetch_add(ptr, 1, __ATOMIC_RELAXED, scope); // no warning
+  __scoped_atomic_thread_fence(__ATOMIC_SEQ_CST, scope); // no warning
+}
+
+void test_function_with_scope_parameter(int *ptr) {
+  // Test calling function that takes __memory_scope parameter
+  helper_with_scope_param(__memory_scope_device, ptr, 42); // no warning
+  helper_with_scope_param(__memory_scope_system, ptr, 100); // no warning
+  helper_with_scope_param(__MEMORY_SCOPE_WRKGRP, ptr, 200); // no warning
+}
+
+__memory_scope get_scope_from_function(void) {
+  return __memory_scope_workgroup;
+}
+
+void test_scope_from_function_call(int *ptr) {
+  // Test using __memory_scope returned from a function
+  __memory_scope scope = get_scope_from_function();
+  __scoped_atomic_store_n(ptr, 1, __ATOMIC_RELAXED, scope); // no warning
+  *ptr = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, scope); // no warning
+  __scoped_atomic_thread_fence(__ATOMIC_RELEASE, scope); // no warning
+
+  // Test using function call directly as argument
+  __scoped_atomic_store_n(ptr, 2, __ATOMIC_RELAXED, get_scope_from_function()); // no warning
+}
diff --git a/clang/test/SemaOpenCL/atomic-ops.cl b/clang/test/SemaOpenCL/atomic-ops.cl
index 59d8b32e9954f..17c8f9829c076 100644
--- a/clang/test/SemaOpenCL/atomic-ops.cl
+++ b/clang/test/SemaOpenCL/atomic-ops.cl
@@ -175,8 +175,8 @@ void syncscope_checks(atomic_int *Ap, int scope) {
 
   // non-integer memory scope is casted to integer type.
   float fscope;
-  (void)__opencl_atomic_load(Ap, memory_order_relaxed, 1.0f);
-  (void)__opencl_atomic_load(Ap, memory_order_relaxed, fscope);
+  (void)__opencl_atomic_load(Ap, memory_order_relaxed, 1.0f); //expected-error{{synchronization scope argument to atomic operation is invalid}}
+  (void)__opencl_atomic_load(Ap, memory_order_relaxed, fscope); //expected-error{{synchronization scope argument to atomic operation is invalid}}
   struct S s;
   (void)__opencl_atomic_load(Ap, memory_order_relaxed, s); //expected-error{{passing '__private struct S' to parameter of incompatible type 'int'}}
 }



More information about the llvm-branch-commits mailing list