[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
Fri Mar 20 01:13:03 PDT 2026


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

>From 5f8f61f0d9ca78b28d552dc89d1ad45e2c3a468b 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 1/5] [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 40091acd878fd..e9c12de8cfdc0 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -516,6 +516,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
@@ -1449,6 +1452,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 d4d09a8ecef36..74dc610b69a87 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9635,6 +9635,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 a8cfdca1cb96d..b436d1d75507c 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 29add9d092e6b..2168839d13bd4 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);
@@ -5154,12 +5183,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 e9c4ff3a75801..f6f1ec816f769 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -8427,6 +8427,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 e3db39a1acb74..6088eb9d0e7e9 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5672,6 +5672,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 49ddc64ce23eb..9fbbdd457e078 100644
--- a/clang/test/Sema/scoped-atomic-ops.c
+++ b/clang/test/Sema/scoped-atomic-ops.c
@@ -6,14 +6,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;
 }
@@ -21,14 +21,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);
 }
 
@@ -72,16 +72,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'}}
 }

>From 7a9584dedf4fcb70457e303f6e87590f58734bae Mon Sep 17 00:00:00 2001
From: Sameer Sahasrabuddhe <sameer.sahasrabuddhe at amd.com>
Date: Wed, 11 Mar 2026 09:35:25 +0530
Subject: [PATCH 2/5] superfluous comments; move declarations closer to use

---
 clang/lib/AST/ASTContext.cpp | 33 +++++++++++----------------------
 1 file changed, 11 insertions(+), 22 deletions(-)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index b436d1d75507c..7cf287e6f4630 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1220,19 +1220,9 @@ TypedefDecl *ASTContext::getMemoryScopeDecl() const {
   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
+  const char *EnumName = "__memory_scope";
   IdentifierInfo &II = Idents.get(EnumName);
   DeclContext::lookup_result Existing =
       getTranslationUnitDecl()->lookup(DeclarationName(&II));
@@ -1251,12 +1241,18 @@ TypedefDecl *ASTContext::getMemoryScopeDecl() const {
   MemoryScopeEnum->setImplicit();
   MemoryScopeEnum->startDefinition();
 
-  // Track max value for bit calculation
-  int MaxValue = 0;
-
   // Create enumerators
+  int MaxValue = 0;
   llvm::APSInt Val(getIntWidth(IntTy), false);
 
+#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)
+
 #define ADD_ENUMERATOR(Name, Value)                                            \
   Val = Value;                                                                 \
   if ((Value) > MaxValue)                                                      \
@@ -1271,21 +1267,17 @@ TypedefDecl *ASTContext::getMemoryScopeDecl() const {
 
   MEMORY_SCOPE_ENUMERATORS(ADD_ENUMERATOR)
 #undef ADD_ENUMERATOR
+#undef MEMORY_SCOPE_ENUMERATORS
 
-  // 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
@@ -1297,9 +1289,6 @@ TypedefDecl *ASTContext::getMemoryScopeDecl() const {
 
   // Cache the typedef (mutable field allows modification in const method)
   MemoryScopeDecl = TypedefD;
-
-#undef MEMORY_SCOPE_ENUMERATORS
-
   return TypedefD;
 }
 

>From 319bbc3ac379124c23d57f794b25b2443b0fe217 Mon Sep 17 00:00:00 2001
From: Sameer Sahasrabuddhe <sameer.sahasrabuddhe at amd.com>
Date: Wed, 11 Mar 2026 09:35:57 +0530
Subject: [PATCH 3/5] warning and note when user declares their own
 __memory_scope enum

---
 clang/include/clang/Basic/DiagnosticGroups.td |  1 +
 .../clang/Basic/DiagnosticSemaKinds.td        |  5 +++-
 clang/lib/Sema/SemaChecking.cpp               |  2 +-
 clang/lib/Sema/SemaLookup.cpp                 | 23 +++++++++++++++++--
 .../test/Sema/builtin-memory-scope-conflict.c |  6 ++---
 5 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index e440c9d2fb982..89d8f320a2d2f 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1169,6 +1169,7 @@ def UserDefinedWarnings : DiagGroup<"user-defined-warnings">;
 def UndeclaredSelector : DiagGroup<"undeclared-selector">;
 def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">;
 def AtomicAlignment : DiagGroup<"atomic-alignment">;
+def AtomicMemoryScope : DiagGroup<"atomic-memory-scope">;
 def CustomAtomic : DiagGroup<"custom-atomic-properties">;
 def AtomicProperties : DiagGroup<"atomic-properties",
                                  [ImplicitAtomic, CustomAtomic]>;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 74dc610b69a87..baec087c9c93d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9637,7 +9637,10 @@ 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">>;
+  InGroup<AtomicMemoryScope>;
+def warn_memory_scope_redeclared : Warning<
+  "user declaration of '%0' conflicts with builtin memory scope enum">,
+  InGroup<AtomicMemoryScope>;
 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/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 2168839d13bd4..b1f3a2b66f339 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5196,7 +5196,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
       // 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) {
+    } else if (IsScoped) {
       // In the case of language-agnostic builtins, also check if it uses the
       // builtin enum type "__memory_scope".
       CheckScopedAtomicScopeArgument(*this, Scope);
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index c881e71da1fa4..132a1504be5a3 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2211,6 +2211,24 @@ bool LookupResult::isAvailableForLookup(Sema &SemaRef, NamedDecl *ND) {
   return false;
 }
 
+/// Diagnose user redeclaration of the __memory_scope builtin.
+static void DiagnoseMemoryScopeConflict(Sema &S, LookupResult &R) {
+  // Don't diagnose during typo correction
+  if (R.isSuppressingAmbiguousDiagnostics())
+    return;
+
+  IdentifierInfo &II = S.Context.Idents.get("__memory_scope");
+  DeclContext::lookup_result Existing =
+      S.Context.getTranslationUnitDecl()->lookup(DeclarationName(&II));
+  if (!Existing.empty()) {
+    S.Diag(R.getNameLoc(), diag::warn_memory_scope_redeclared)
+        << "__memory_scope";
+    for (NamedDecl *D : Existing) {
+      S.Diag(D->getLocation(), diag::note_previous_decl) << D;
+    }
+  }
+}
+
 /// 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,
@@ -2227,6 +2245,8 @@ static bool TryCreateMemoryScopeBuiltin(Sema &S, LookupResult &R,
       R.resolveKind();
       return true;
     }
+    // getMemoryScopeDecl() returned nullptr - user declared __memory_scope
+    DiagnoseMemoryScopeConflict(S, R);
     return false;
   }
 
@@ -2235,8 +2255,7 @@ static bool TryCreateMemoryScopeBuiltin(Sema &S, LookupResult &R,
     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
+      DiagnoseMemoryScopeConflict(S, R);
       return false;
     }
 
diff --git a/clang/test/Sema/builtin-memory-scope-conflict.c b/clang/test/Sema/builtin-memory-scope-conflict.c
index 32e57b4570784..e6189e9215efb 100644
--- a/clang/test/Sema/builtin-memory-scope-conflict.c
+++ b/clang/test/Sema/builtin-memory-scope-conflict.c
@@ -3,12 +3,12 @@
 // Test that declaring __memory_scope conflicts with the builtin enum
 
 // User declares their own enum first
-enum __memory_scope {
+typedef enum {
   my_value = 0
-};
+} __memory_scope; // expected-note {{'__memory_scope' declared here}}
 
 // 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'}}
+  __memory_scope x = __memory_scope_system; // expected-warning {{user declaration of '__memory_scope' conflicts with builtin memory scope enum}} expected-error {{use of undeclared identifier '__memory_scope_system'}}
 }

>From bea8f1139f2f205a5b1d24049ceaa0415e6d491f Mon Sep 17 00:00:00 2001
From: Sameer Sahasrabuddhe <sameer.sahasrabuddhe at amd.com>
Date: Fri, 20 Mar 2026 11:59:03 +0530
Subject: [PATCH 4/5] enumerators are int type in C, but enum type in C++

---
 clang/lib/AST/ASTContext.cpp                         |  5 +++--
 clang/lib/Sema/SemaChecking.cpp                      | 12 ++++++++++++
 .../test/Sema/builtin-memory-scope-enumerator-type.c | 12 ++++++++++++
 .../Sema/builtin-memory-scope-enumerator-type.cpp    | 11 +++++++++++
 4 files changed, 38 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/Sema/builtin-memory-scope-enumerator-type.c
 create mode 100644 clang/test/Sema/builtin-memory-scope-enumerator-type.cpp

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 7cf287e6f4630..44b47d86be053 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1274,8 +1274,9 @@ TypedefDecl *ASTContext::getMemoryScopeDecl() const {
   MemoryScopeEnum->completeDefinition(IntTy, IntTy, NumPositiveBits, 0);
 
   QualType EnumType = getCanonicalTagType(MemoryScopeEnum);
-  for (EnumConstantDecl *Constant : MemoryScopeEnum->enumerators()) {
-    Constant->setType(EnumType);
+  if (getLangOpts().CPlusPlus) {
+    for (EnumConstantDecl *Constant : MemoryScopeEnum->enumerators())
+      Constant->setType(EnumType);
   }
 
   getTranslationUnitDecl()->addDecl(MemoryScopeEnum);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index b1f3a2b66f339..3390e69890ddb 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2112,6 +2112,18 @@ static void CheckScopedAtomicScopeArgument(Sema &S, Expr *Scope) {
   if (const auto *EnumTy = OrigScope->getType()->getAs<EnumType>()) {
     if (EnumTy->getDecl()->getName() == "__memory_scope") {
       return;
+
+  // In C, enumerators have type int, not the enum type. Check if this is a
+  // reference to an enumerator to detect wrong enum usage in C.
+  if (auto *DRE = dyn_cast<DeclRefExpr>(OrigScope)) {
+    if (auto *ECD = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
+      if (auto *EnumDecl = dyn_cast<clang::EnumDecl>(ECD->getDeclContext())) {
+        if (EnumDecl->getName() == "__memory_scope")
+          return;
+        S.Diag(OrigScope->getBeginLoc(), diag::warn_atomic_scope_wrong_enum)
+            << OrigScope->getSourceRange();
+        return;
+      }
     }
   }
 
diff --git a/clang/test/Sema/builtin-memory-scope-enumerator-type.c b/clang/test/Sema/builtin-memory-scope-enumerator-type.c
new file mode 100644
index 0000000000000..ca4d76011fce9
--- /dev/null
+++ b/clang/test/Sema/builtin-memory-scope-enumerator-type.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c11 -verify %s
+// expected-no-diagnostics
+
+// In C, enumerators have type int (C11 6.7.2.2p3), not the enumeration type.
+// Verify using _Generic, which selects based on the type of the controlling
+// expression without any implicit conversion.
+_Static_assert(_Generic(__memory_scope_system,      int: 1, default: 0), "");
+_Static_assert(_Generic(__memory_scope_device,      int: 1, default: 0), "");
+_Static_assert(_Generic(__memory_scope_workgroup,   int: 1, default: 0), "");
+_Static_assert(_Generic(__memory_scope_wavefront,   int: 1, default: 0), "");
+_Static_assert(_Generic(__memory_scope_singlethread,int: 1, default: 0), "");
+_Static_assert(_Generic(__memory_scope_cluster,     int: 1, default: 0), "");
diff --git a/clang/test/Sema/builtin-memory-scope-enumerator-type.cpp b/clang/test/Sema/builtin-memory-scope-enumerator-type.cpp
new file mode 100644
index 0000000000000..5e40cb7aaa213
--- /dev/null
+++ b/clang/test/Sema/builtin-memory-scope-enumerator-type.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// expected-no-diagnostics
+
+// In C++, enumerators have the enumeration type. Verify using decltype, which
+// yields the declared type of the enumerator without any implicit conversion.
+static_assert(__is_same(decltype(__memory_scope_system),      __memory_scope), "");
+static_assert(__is_same(decltype(__memory_scope_device),      __memory_scope), "");
+static_assert(__is_same(decltype(__memory_scope_workgroup),   __memory_scope), "");
+static_assert(__is_same(decltype(__memory_scope_wavefront),   __memory_scope), "");
+static_assert(__is_same(decltype(__memory_scope_singlethread),__memory_scope), "");
+static_assert(__is_same(decltype(__memory_scope_cluster),     __memory_scope), "");

>From 2759474cb65c0ceb5cdec2e265cab69d9ba9d558 Mon Sep 17 00:00:00 2001
From: Sameer Sahasrabuddhe <sameer.sahasrabuddhe at amd.com>
Date: Fri, 20 Mar 2026 12:02:18 +0530
Subject: [PATCH 5/5] all enums are ints; optional warning for non-enum scope

---
 .../clang/Basic/DiagnosticSemaKinds.td        |   5 +-
 clang/lib/Sema/SemaChecking.cpp               |  26 ++---
 clang/lib/Sema/SemaLookup.cpp                 |   3 +-
 .../Sema/builtin-memory-scope-shadowing.c     |  14 +--
 clang/test/Sema/scoped-atomic-ops.c           |  28 ++---
 .../Sema/scoped-atomic-scope-deprecation.c    | 106 ------------------
 clang/test/Sema/scoped-atomic-scope-warning.c |  58 ++++++++++
 clang/test/SemaOpenCL/atomic-ops.cl           |   4 +-
 8 files changed, 97 insertions(+), 147 deletions(-)
 delete mode 100644 clang/test/Sema/scoped-atomic-scope-deprecation.c
 create mode 100644 clang/test/Sema/scoped-atomic-scope-warning.c

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index baec087c9c93d..81b27016d1fdf 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9635,9 +9635,12 @@ 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<
+def warn_atomic_scope_wrong_enum : Warning<
   "synchronization scope should be of type __memory_scope">,
   InGroup<AtomicMemoryScope>;
+def warn_atomic_scope_incorrect_type : Warning<
+  "synchronization scope should be of type __memory_scope">,
+  InGroup<AtomicMemoryScope>, DefaultIgnore;
 def warn_memory_scope_redeclared : Warning<
   "user declaration of '%0' conflicts with builtin memory scope enum">,
   InGroup<AtomicMemoryScope>;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3390e69890ddb..7bf8ff399c86a 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2100,18 +2100,18 @@ CheckBuiltinTargetInSupported(Sema &S, CallExpr *TheCall,
 }
 
 /// 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.
+/// operations and fences. Warns if a wrong enum type is used, and optionally
+/// warns if a non-enum 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") {
+    if (EnumTy->getDecl()->getName() == "__memory_scope")
       return;
+    S.Diag(OrigScope->getBeginLoc(), diag::warn_atomic_scope_wrong_enum)
+        << OrigScope->getSourceRange();
+    return;
+  }
 
   // In C, enumerators have type int, not the enum type. Check if this is a
   // reference to an enumerator to detect wrong enum usage in C.
@@ -2127,9 +2127,9 @@ static void CheckScopedAtomicScopeArgument(Sema &S, Expr *Scope) {
     }
   }
 
-  // Use of any other integer type gets a warning
-  S.Diag(Scope->getBeginLoc(), diag::warn_atomic_op_scope_should_be_enum)
-      << Scope->getSourceRange();
+  // Not an enum. But this warning is disabled by default.
+  S.Diag(OrigScope->getBeginLoc(), diag::warn_atomic_scope_incorrect_type)
+      << OrigScope->getSourceRange();
 }
 
 static void CheckNonNullArgument(Sema &S, const Expr *ArgExpr,
@@ -5204,11 +5204,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
             << 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 (IsScoped) {
+    if (IsScoped) {
       // In the case of language-agnostic builtins, also check if it uses the
       // builtin enum type "__memory_scope".
       CheckScopedAtomicScopeArgument(*this, Scope);
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 132a1504be5a3..2638b620e0db5 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2374,8 +2374,7 @@ 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.
+  // Check for enum __memory_scope even when AllowBuiltinCreation is false.
   if (IdentifierInfo *II = Name.getAsIdentifierInfo()) {
     if (TryCreateMemoryScopeBuiltin(*this, R, *II))
       return true;
diff --git a/clang/test/Sema/builtin-memory-scope-shadowing.c b/clang/test/Sema/builtin-memory-scope-shadowing.c
index fc12952f8a287..a3d479ac04bce 100644
--- a/clang/test/Sema/builtin-memory-scope-shadowing.c
+++ b/clang/test/Sema/builtin-memory-scope-shadowing.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c11 -verify -triple=amdgcn-amd-amdhsa %s
+// RUN: %clang_cc1 -fsyntax-only -std=c11 -verify %s
 
 // Test that user enumerators shadowing builtin __memory_scope_* names
 // are caught by type checking when passed to scoped atomic operations.
@@ -29,17 +29,17 @@ void test_builtin_still_works(int *ptr) {
   val = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, __memory_scope_device); // no warning
 }
 
-void test_integer_literal_deprecated(int *ptr) {
+void test_integer_literal_no_warning(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}}
+  // Integer literals do not warn by default (warning is opt-in with -Watomic-memory-scope)
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, 0);
 
-  val = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, 1); // expected-warning {{synchronization scope should be of type __memory_scope}}
+  val = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, 1);
 
-  // Integer variables should also get deprecation warning
+  // Integer variables also do not warn by default
   int scope = 2;
-  __scoped_atomic_store_n(ptr, 42, __ATOMIC_RELAXED, scope); // expected-warning {{synchronization scope should be of type __memory_scope}}
+  __scoped_atomic_store_n(ptr, 42, __ATOMIC_RELAXED, scope);
 }
 
 // Test shadowing with anonymous enum
diff --git a/clang/test/Sema/scoped-atomic-ops.c b/clang/test/Sema/scoped-atomic-ops.c
index 9fbbdd457e078..49ddc64ce23eb 100644
--- a/clang/test/Sema/scoped-atomic-ops.c
+++ b/clang/test/Sema/scoped-atomic-ops.c
@@ -6,14 +6,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-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, 42); // 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-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, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
   *i = __scoped_atomic_load_n(i, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
   return *i;
 }
@@ -21,14 +21,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-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, 42); // 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-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, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
   __scoped_atomic_store_n(i, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
 }
 
@@ -72,16 +72,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-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}}
+  *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}}
 }
 
 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
deleted file mode 100644
index 09c418c16d523..0000000000000
--- a/clang/test/Sema/scoped-atomic-scope-deprecation.c
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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/Sema/scoped-atomic-scope-warning.c b/clang/test/Sema/scoped-atomic-scope-warning.c
new file mode 100644
index 0000000000000..e4689f4cdffea
--- /dev/null
+++ b/clang/test/Sema/scoped-atomic-scope-warning.c
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -x c -verify -fsyntax-only %s
+// RUN: %clang_cc1 -x c -Watomic-memory-scope -verify=enabled -fsyntax-only %s
+
+// Test warnings for scope arguments:
+// - Integer arguments trigger warning only when -Watomic-memory-scope is enabled
+// - Wrong enum types always trigger warning
+
+void test_integer_literal_scope(int *ptr) {
+  int val;
+  // Using integer literals: warning only with -Watomic-memory-scope
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, 0); // enabled-warning {{synchronization scope should be of type __memory_scope}}
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, 1); // enabled-warning {{synchronization scope should be of type __memory_scope}}
+  *ptr = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, 2); // enabled-warning {{synchronization scope should be of type __memory_scope}}
+}
+
+void test_integer_variable_scope(int *ptr) {
+  int val;
+  int scope = 0;
+  // Using integer variables: warning only with -Watomic-memory-scope
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, scope); // enabled-warning {{synchronization scope should be of type __memory_scope}}
+  *ptr = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, scope); // enabled-warning {{synchronization scope should be of type __memory_scope}}
+}
+
+// Test warning for wrong enum type
+enum my_scope {
+  MY_SCOPE_SYSTEM = 0,
+  MY_SCOPE_DEVICE = 1
+};
+
+void test_wrong_enum_type(int *ptr) {
+  int val;
+  // Using wrong enum type should trigger warning (enabled by default)
+  // Test with enumerators (in C these have type int, triggering DeclRefExpr check)
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, MY_SCOPE_SYSTEM); // expected-warning {{synchronization scope should be of type __memory_scope}} enabled-warning {{synchronization scope should be of type __memory_scope}}
+  *ptr = __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, MY_SCOPE_DEVICE); // expected-warning {{synchronization scope should be of type __memory_scope}} enabled-warning {{synchronization scope should be of type __memory_scope}}
+  __scoped_atomic_thread_fence(__ATOMIC_SEQ_CST, MY_SCOPE_SYSTEM); // expected-warning {{synchronization scope should be of type __memory_scope}} enabled-warning {{synchronization scope should be of type __memory_scope}}
+
+  // Test with variable of wrong enum type (triggers enum type check)
+  enum my_scope wrong_scope = MY_SCOPE_SYSTEM;
+  __scoped_atomic_load(ptr, &val, __ATOMIC_RELAXED, wrong_scope); // expected-warning {{synchronization scope should be of type __memory_scope}} enabled-warning {{synchronization scope should be of type __memory_scope}}
+}
+
+void test_various_scoped_atomics_with_integer(int *ptr) {
+  // Test warnings with various scoped atomic operations
+  *ptr = __scoped_atomic_fetch_add(ptr, 1, __ATOMIC_RELAXED, 0); // enabled-warning {{synchronization scope should be of type __memory_scope}}
+  *ptr = __scoped_atomic_add_fetch(ptr, 1, __ATOMIC_RELAXED, 1); // enabled-warning {{synchronization scope should be of type __memory_scope}}
+  *ptr = __scoped_atomic_fetch_sub(ptr, 1, __ATOMIC_RELAXED, 2); // enabled-warning {{synchronization scope should be of type __memory_scope}}
+  __scoped_atomic_store_n(ptr, 1, __ATOMIC_RELAXED, 3); // enabled-warning {{synchronization scope should be of type __memory_scope}}
+}
+
+void test_fence_with_integer() {
+  // Test warnings with __scoped_atomic_thread_fence using integer literals
+  __scoped_atomic_thread_fence(__ATOMIC_SEQ_CST, 0); // enabled-warning {{synchronization scope should be of type __memory_scope}}
+  __scoped_atomic_thread_fence(__ATOMIC_ACQUIRE, 1); // enabled-warning {{synchronization scope should be of type __memory_scope}}
+
+  int scope_var = 2;
+  __scoped_atomic_thread_fence(__ATOMIC_RELEASE, scope_var); // enabled-warning {{synchronization scope should be of type __memory_scope}}
+}
diff --git a/clang/test/SemaOpenCL/atomic-ops.cl b/clang/test/SemaOpenCL/atomic-ops.cl
index 17c8f9829c076..59d8b32e9954f 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); //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}}
+  (void)__opencl_atomic_load(Ap, memory_order_relaxed, 1.0f);
+  (void)__opencl_atomic_load(Ap, memory_order_relaxed, fscope);
   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