[clang] [HLSL] Add `[[hlsl::row_access]]` attribute (PR #107954)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 9 22:38:18 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Helena Kotas (hekota)
<details>
<summary>Changes</summary>
This PR introduces new HLSL resource type attribute `[[hlsl::row_access]]`. Presence of this attribute on a resource handle means that the resource must be accessed in 16-byte blocks at-a-time, or four 32-bit components, also known as rows.
This information is necessary in order to properly distinguish between handles for typed buffer types (like `RWBuffer<float4>`) which require row-level access and will be translated to target extension type `dx.TypedBuffer` versus buffer types that do not have this access constraint (like `RWStructuredBuffer<float4>`) and will be using target ext. type `dx.RawBuffer`.
Fixes #<!-- -->107907
---
Full diff: https://github.com/llvm/llvm-project/pull/107954.diff
12 Files Affected:
- (modified) clang/include/clang/AST/Type.h (+8-3)
- (modified) clang/include/clang/AST/TypeProperties.td (+4-1)
- (modified) clang/include/clang/Basic/Attr.td (+6)
- (modified) clang/lib/AST/ASTStructuralEquivalence.cpp (+2-2)
- (modified) clang/lib/AST/TypePrinter.cpp (+3)
- (modified) clang/lib/Sema/HLSLExternalSemaSource.cpp (+9-5)
- (modified) clang/lib/Sema/SemaHLSL.cpp (+10)
- (modified) clang/lib/Sema/SemaType.cpp (+7-2)
- (modified) clang/test/AST/HLSL/RWBuffer-AST.hlsl (+4-4)
- (modified) clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl (+2-2)
- (added) clang/test/ParserHLSL/hlsl_row_access_attr.hlsl (+16)
- (added) clang/test/ParserHLSL/hlsl_row_access_attr_error.hlsl (+16)
``````````diff
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index ef36a73716454f..d8336e1960c64e 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -6169,9 +6169,13 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
// Data gathered from HLSL resource attributes
llvm::dxil::ResourceClass ResourceClass;
uint8_t IsROV : 1;
- Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV)
- : ResourceClass(ResourceClass), IsROV(IsROV) {}
- Attributes() : ResourceClass(llvm::dxil::ResourceClass::UAV), IsROV(0) {}
+ uint8_t RowAccess : 1;
+ Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV,
+ bool RowAccess)
+ : ResourceClass(ResourceClass), IsROV(IsROV), RowAccess(RowAccess) {}
+ Attributes()
+ : ResourceClass(llvm::dxil::ResourceClass::UAV), IsROV(0),
+ RowAccess(0) {}
};
private:
@@ -6204,6 +6208,7 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
ID.AddPointer(Contained.getAsOpaquePtr());
ID.AddInteger(static_cast<uint32_t>(Attrs.ResourceClass));
ID.AddBoolean(Attrs.IsROV);
+ ID.AddBoolean(Attrs.RowAccess);
}
static bool classof(const Type *T) {
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 539a344cb0b690..f310996d144959 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -697,6 +697,9 @@ let Class = HLSLAttributedResourceType in {
def : Property<"isROV", Bool> {
let Read = [{ node->getAttrs().IsROV }];
}
+ def : Property<"rowAccess", Bool> {
+ let Read = [{ node->getAttrs().RowAccess }];
+ }
def : Property<"wrappedTy", QualType> {
let Read = [{ node->getWrappedType() }];
}
@@ -704,7 +707,7 @@ let Class = HLSLAttributedResourceType in {
let Read = [{ node->getContainedType() }];
}
def : Creator<[{
- HLSLAttributedResourceType::Attributes attrs(static_cast<llvm::dxil::ResourceClass>(resClass), isROV);
+ HLSLAttributedResourceType::Attributes attrs(static_cast<llvm::dxil::ResourceClass>(resClass), isROV, rowAccess);
return ctx.getHLSLAttributedResourceType(wrappedTy, containedTy, attrs);
}]>;
}
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 9a7b163b2c6da8..7edf33dee93d0a 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4669,6 +4669,12 @@ def HLSLResourceClass : TypeAttr {
let Documentation = [InternalOnly];
}
+def HLSLRowAccess : TypeAttr {
+ let Spellings = [CXX11<"hlsl", "row_access">];
+ let LangOpts = [HLSL];
+ let Documentation = [InternalOnly];
+}
+
def HLSLGroupSharedAddressSpace : TypeAttr {
let Spellings = [CustomKeyword<"groupshared">];
let Subjects = SubjectList<[Var]>;
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index f13ca2d08d769f..9896e0f48aed58 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -808,8 +808,8 @@ static bool
IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const HLSLAttributedResourceType::Attributes &Attrs1,
const HLSLAttributedResourceType::Attributes &Attrs2) {
- return std::tie(Attrs1.ResourceClass, Attrs1.IsROV) ==
- std::tie(Attrs2.ResourceClass, Attrs2.IsROV);
+ return std::tie(Attrs1.ResourceClass, Attrs1.IsROV, Attrs1.RowAccess) ==
+ std::tie(Attrs2.ResourceClass, Attrs2.IsROV, Attrs2.RowAccess);
}
/// Determine structural equivalence of two types.
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index add6a5d10d61f7..61cd88dd642509 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1945,6 +1945,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::HLSLResourceClass:
case attr::HLSLROV:
+ case attr::HLSLRowAccess:
llvm_unreachable("HLSL resource type attributes handled separately");
case attr::OpenCLPrivateAddressSpace:
@@ -2078,6 +2079,8 @@ void TypePrinter::printHLSLAttributedResourceAfter(
<< ")]]";
if (Attrs.IsROV)
OS << " [[hlsl::is_rov()]]";
+ if (Attrs.RowAccess)
+ OS << " [[hlsl::row_access]]";
}
void TypePrinter::printObjCInterfaceBefore(const ObjCInterfaceType *T,
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 071e64fe56d48a..1722bb6aba84e6 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -111,6 +111,7 @@ struct BuiltinTypeDeclBuilder {
BuiltinTypeDeclBuilder &
addHandleMember(Sema &S, ResourceClass RC, ResourceKind RK, bool IsROV,
+ bool RowAccess,
AccessSpecifier Access = AccessSpecifier::AS_private) {
if (Record->isCompleteDefinition())
return *this;
@@ -126,7 +127,9 @@ struct BuiltinTypeDeclBuilder {
QualType AttributedResTy = QualType();
SmallVector<const Attr *> Attrs = {
HLSLResourceClassAttr::CreateImplicit(Record->getASTContext(), RC),
- IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr};
+ IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr,
+ RowAccess ? HLSLRowAccessAttr::CreateImplicit(Record->getASTContext())
+ : nullptr};
Attr *ResourceAttr =
HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RK);
if (CreateHLSLAttributedResourceType(S, Ty, Attrs, AttributedResTy))
@@ -495,9 +498,9 @@ void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
/// Set up common members and attributes for buffer types
static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
ResourceClass RC, ResourceKind RK,
- bool IsROV) {
+ bool IsROV, bool RowAccess) {
return BuiltinTypeDeclBuilder(Decl)
- .addHandleMember(S, RC, RK, IsROV)
+ .addHandleMember(S, RC, RK, IsROV, RowAccess)
.addDefaultHandleConstructor(S, RC);
}
@@ -510,7 +513,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
ResourceKind::TypedBuffer,
- /*IsROV=*/false)
+ /*IsROV=*/false, /*RowAccess=*/true)
.addArraySubscriptOperators()
.completeDefinition();
});
@@ -521,7 +524,8 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
.Record;
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
- ResourceKind::TypedBuffer, /*IsROV=*/true)
+ ResourceKind::TypedBuffer, /*IsROV=*/true,
+ /*RowAccess=*/true)
.addArraySubscriptOperators()
.completeDefinition();
});
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 3b91303ac8cb8a..5f741e3124461f 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -593,6 +593,13 @@ bool clang::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
case attr::HLSLROV:
ResAttrs.IsROV = true;
break;
+ case attr::HLSLRowAccess:
+ if (ResAttrs.RowAccess) {
+ S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
+ return false;
+ }
+ ResAttrs.RowAccess = true;
+ break;
default:
llvm_unreachable("unhandled resource attribute type");
}
@@ -645,6 +652,9 @@ bool SemaHLSL::handleResourceTypeAttr(const ParsedAttr &AL) {
case ParsedAttr::AT_HLSLROV:
A = HLSLROVAttr::Create(getASTContext(), AL.getLoc());
break;
+ case ParsedAttr::AT_HLSLRowAccess:
+ A = HLSLRowAccessAttr::Create(getASTContext(), AL.getLoc());
+ break;
default:
llvm_unreachable("unhandled HLSL attribute");
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 520dce870b7b78..79e4fa77e001e9 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8843,8 +8843,13 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
break;
}
case ParsedAttr::AT_HLSLResourceClass:
- case ParsedAttr::AT_HLSLROV: {
- if (state.getSema().HLSL().handleResourceTypeAttr(attr))
+ case ParsedAttr::AT_HLSLROV:
+ case ParsedAttr::AT_HLSLRowAccess: {
+ // Only collect HLSL resource type attributes that are in
+ // decl-specifier-seq; do not collect attributes on declarations or those
+ // that get to slide after declaration name.
+ if (TAL == TAL_DeclSpec &&
+ state.getSema().HLSL().handleResourceTypeAttr(attr))
attr.setUsedAsTypeAttr();
break;
}
diff --git a/clang/test/AST/HLSL/RWBuffer-AST.hlsl b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
index 0e7803ce50a890..10bcf9b70d1121 100644
--- a/clang/test/AST/HLSL/RWBuffer-AST.hlsl
+++ b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
@@ -30,7 +30,7 @@ RWBuffer<float> Buffer;
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class RWBuffer definition
// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
-// CHECK-NEXT: implicit h 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *'
+// CHECK-NEXT: implicit h 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::row_access]]':'element_type *'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
@@ -38,7 +38,7 @@ RWBuffer<float> Buffer;
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue
-// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
+// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::row_access]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const RWBuffer<element_type>' lvalue implicit this
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
@@ -48,7 +48,7 @@ RWBuffer<float> Buffer;
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue
-// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
+// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::row_access]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'RWBuffer<element_type>' lvalue implicit this
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
@@ -58,5 +58,5 @@ RWBuffer<float> Buffer;
// CHECK: TemplateArgument type 'float'
// CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float'
// CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
-// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]]':'float *'
+// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::row_access]]':'float *'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
diff --git a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl
index 6324a11fc8a2df..b8e843eb3448f2 100644
--- a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl
+++ b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl
@@ -3,7 +3,7 @@
// CHECK: -ClassTemplateSpecializationDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> class RWBuffer definition implicit_instantiation
// CHECK: -TemplateArgument type 'float'
// CHECK: `-BuiltinType 0x{{[0-9a-f]+}} 'float'
-// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]]':'float *'
+// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::row_access]]':'float *'
// CHECK: -HLSLResourceAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit TypedBuffer
RWBuffer<float> Buffer1;
@@ -11,6 +11,6 @@ RWBuffer<float> Buffer1;
// CHECK: -TemplateArgument type 'vector<float, 4>'
// CHECK: `-ExtVectorType 0x{{[0-9a-f]+}} 'vector<float, 4>' 4
// CHECK: `-BuiltinType 0x{{[0-9a-f]+}} 'float'
-// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'vector<float *, 4> {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::is_rov()]]':'vector<float *, 4>'
+// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'vector<float *, 4> {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::is_rov()]] {{\[\[}}hlsl::row_access]]':'vector<float *, 4>'
// CHECK: -HLSLResourceAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit TypedBuffer
RasterizerOrderedBuffer<vector<float, 4> > BufferArray3[4];
diff --git a/clang/test/ParserHLSL/hlsl_row_access_attr.hlsl b/clang/test/ParserHLSL/hlsl_row_access_attr.hlsl
new file mode 100644
index 00000000000000..3bcaf53f7984ad
--- /dev/null
+++ b/clang/test/ParserHLSL/hlsl_row_access_attr.hlsl
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s
+
+// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} struct MyBuffer definition
+// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:6:3, col:72> col:72 h1 '__hlsl_resource_t {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::row_access]]':'__hlsl_resource_t'
+struct MyBuffer {
+ __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::row_access]] h1;
+};
+
+// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:10:1, col:70> col:70 h2 '__hlsl_resource_t {{\[\[}}hlsl::resource_class(SRV)]] {{\[\[}}hlsl::row_access]]':'__hlsl_resource_t'
+__hlsl_resource_t [[hlsl::row_access]] [[hlsl::resource_class(SRV)]] h2;
+
+// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:14:1, line:16:1> line:14:6 f 'void ()
+// CHECK: VarDecl 0x{{[0-9a-f]+}} <col:3, col:72> col:72 h3 '__hlsl_resource_t {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::row_access]]':'__hlsl_resource_t'
+void f() {
+ __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::row_access]] h3;
+}
diff --git a/clang/test/ParserHLSL/hlsl_row_access_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_row_access_attr_error.hlsl
new file mode 100644
index 00000000000000..e1a0349d90d146
--- /dev/null
+++ b/clang/test/ParserHLSL/hlsl_row_access_attr_error.hlsl
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -o - %s -verify
+
+// expected-error at +1{{'row_access' attribute cannot be applied to a declaration}}
+[[hlsl::row_access]] __hlsl_resource_t res0;
+
+// expected-error at +1{{HLSL resource needs to have [[hlsl::resource_class()]] attribute}}
+__hlsl_resource_t [[hlsl::row_access]] res1;
+
+// expected-error at +1{{'row_access' attribute takes no arguments}}
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::row_access(3)]] res2;
+
+// expected-error at +1{{use of undeclared identifier 'gibberish'}}
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::row_access(gibberish)]] res3;
+
+// expected-warning at +1{{attribute 'row_access' is already applied}}
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::row_access]] [[hlsl::row_access]] res4;
``````````
</details>
https://github.com/llvm/llvm-project/pull/107954
More information about the cfe-commits
mailing list