diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 082a606687b..2aa76fb22b7 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -52,6 +52,9 @@ line upon naming the release. Refer to previous for appropriate section names. #### HLSL Language +- Updated implementation of `string` types to conform to restrictions for + intangible objects aligning with TC57's direction (see: + [hlsl-tc57/tc57#200](https://github.com/hlsl-tc57/tc57/issues/200)). - The `shared` and `uniform` keywords are removed in HLSL 202x, with compatibility warnings available for earlier language versions [#8482](https://github.com/microsoft/DirectXShaderCompiler/issues/8482). diff --git a/lib/DXIL/DxilTypeSystem.cpp b/lib/DXIL/DxilTypeSystem.cpp index da7d85c7548..3d654ee2c8d 100644 --- a/lib/DXIL/DxilTypeSystem.cpp +++ b/lib/DXIL/DxilTypeSystem.cpp @@ -13,6 +13,7 @@ #include "dxc/Support/Global.h" #include "dxc/Support/WinFunctions.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Support/raw_ostream.h" @@ -393,6 +394,21 @@ DxilTypeSystem::AddStructAnnotation(const StructType *pStructType, return pA; } +static bool ContainsString(const Type *Ty, + SmallPtrSetImpl &CheckedTypes) { + if (!CheckedTypes.insert(Ty).second) + return false; + if (Ty->isPointerTy()) + return Ty->getPointerElementType()->isIntegerTy(8); + if (auto *AT = dyn_cast(Ty)) + return ContainsString(AT->getElementType(), CheckedTypes); + if (auto *ST = dyn_cast(Ty)) + for (Type *Element : ST->elements()) + if (ContainsString(Element, CheckedTypes)) + return true; + return false; +} + void DxilTypeSystem::FinishStructAnnotation(DxilStructAnnotation &SA) { const llvm::StructType *ST = SA.GetStructType(); DXASSERT(SA.GetNumFields() == ST->getNumElements(), @@ -411,9 +427,13 @@ void DxilTypeSystem::FinishStructAnnotation(DxilStructAnnotation &SA) { SA.SetContainsTargetTypes(); } - // Mark if empty - if (SA.GetCBufferSize() == 0) - SA.MarkEmptyStruct(); + // Zero cbuffer-layout size does not imply an empty struct: + // string-only aggregates still contain values that must be copied. + if (SA.GetCBufferSize() == 0) { + SmallPtrSet CheckedTypes; + if (!ContainsString(ST, CheckedTypes)) + SA.MarkEmptyStruct(); + } } DxilStructAnnotation * diff --git a/lib/HLSL/HLLegalizeParameter.cpp b/lib/HLSL/HLLegalizeParameter.cpp index 51653070eaf..ed799dfc5d2 100644 --- a/lib/HLSL/HLLegalizeParameter.cpp +++ b/lib/HLSL/HLLegalizeParameter.cpp @@ -295,6 +295,15 @@ bool HLLegalizeParameter::runOnModule(Module &M) { void HLLegalizeParameter::patchWriteOnInParam(Function &F, Argument &Arg, const DataLayout &DL) { + // Skip i8 pointer arguments, these should only occur for strings. + // Note: this is an utter disaster if we ever want to support i8 data types in + // HLSL. So that will be fun... + if (Arg.getType()->isPointerTy()) { + Type *EltTy = Arg.getType()->getPointerElementType(); + if (EltTy->isIntegerTy() && EltTy->getIntegerBitWidth() == 8) + return; + } + // TODO: Adding lifetime intrinsics isn't easy here, have to analyze uses. Type *Ty = Arg.getType()->getPointerElementType(); AllocaInst *temp = createAllocaForPatch(F, Ty); diff --git a/tools/clang/include/clang/AST/ASTContext.h b/tools/clang/include/clang/AST/ASTContext.h index 169efa26ba9..e230e7729e7 100644 --- a/tools/clang/include/clang/AST/ASTContext.h +++ b/tools/clang/include/clang/AST/ASTContext.h @@ -849,8 +849,8 @@ class ASTContext : public RefCountedBase { CanQualType Min12IntTy, Min10FloatTy; CanQualType LitIntTy, LitFloatTy; CanQualType HalfFloatTy, Min16FloatTy, Min16IntTy, Min16UIntTy; - CanQualType HLSLStringTy; CanQualType Int8_4PackedTy, UInt8_4PackedTy; + QualType HLSLStringTy; CanQualType LinAlgMatrixTy; // HLSL Changes end diff --git a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index 90323226fe7..5fd7adc46fd 100644 --- a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7908,7 +7908,7 @@ def err_hlsl_missing_attr: Error< def err_hlsl_missing_inout_attr: Error< "stream-output object must be an inout parameter">; def err_hlsl_unsupported_string_decl: Error< - "%select{array|parameter|return value}0 of type string is not supported">; + "%select{array|parameter|return value|field}0 of type string is not supported">; def err_hlsl_missing_out_attr: Error< "%0 object must be an out parameter">; def err_hlsl_missing_in_attr: Error< diff --git a/tools/clang/lib/AST/ASTContext.cpp b/tools/clang/lib/AST/ASTContext.cpp index 19511b0f41f..566c411f372 100644 --- a/tools/clang/lib/AST/ASTContext.cpp +++ b/tools/clang/lib/AST/ASTContext.cpp @@ -1110,7 +1110,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { InitBuiltinType(UInt8_4PackedTy, BuiltinType::UInt8_4Packed); InitBuiltinType(LinAlgMatrixTy, BuiltinType::LinAlgMatrix); - HLSLStringTy = this->getPointerType(CharTy); + // This shouldn't actually be a canonical type, since it effectively must be + // const. + HLSLStringTy = this->getPointerType(CharTy.withConst()); hlsl::InitializeASTContextForHLSL(*this); // Previously in constructor, guarded by !DelayInitialization } diff --git a/tools/clang/lib/CodeGen/CGDecl.cpp b/tools/clang/lib/CodeGen/CGDecl.cpp index e61750c654b..4d59646da82 100644 --- a/tools/clang/lib/CodeGen/CGDecl.cpp +++ b/tools/clang/lib/CodeGen/CGDecl.cpp @@ -11,15 +11,18 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenFunction.h" #include "CGCleanup.h" #include "CGDebugInfo.h" +#include "CGHLSLRuntime.h" // HLSL Change #include "CGOpenCLRuntime.h" +#include "CodeGenFunction.h" // HLSL Change (clang-format) #include "CodeGenModule.h" +#include "dxc/DXIL/DxilMetadataHelper.h" // HLSL Change #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/HlslTypes.h" // HLSL Change #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" @@ -28,8 +31,6 @@ #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Type.h" -#include "CGHLSLRuntime.h" // HLSL Change -#include "dxc/DXIL/DxilMetadataHelper.h" // HLSL Change using namespace clang; using namespace CodeGen; @@ -1773,7 +1774,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg, } } else { // HLSL Change Starts - if (getLangOpts().HLSL && Arg->getType()->isPointerTy()) { + if (getLangOpts().HLSL && Arg->getType()->isPointerTy() && + !hlsl::IsStringType(Ty)) { // HLSL doesn't have pointer. // Only case pointer type will generated is this pointer for methods. // Don't store this pointer, just use the parameter directly. diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index 1b806933e6d..b0cfeacd335 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -4157,6 +4157,12 @@ void CGMSHLSLRuntime::FlattenValToInitList(CodeGenFunction &CGF, CGBuilderTy &Builder = CGF.Builder; llvm::Type *valTy = val->getType(); + if (hlsl::IsStringType(Ty) && valTy == CGF.ConvertType(Ty)) { + elts.emplace_back(val); + eltTys.emplace_back(Ty); + return; + } + if (valTy->isPointerTy()) { llvm::Type *valEltTy = valTy->getPointerElementType(); if (valEltTy->isVectorTy() || valEltTy->isSingleValueType()) { @@ -4347,6 +4353,9 @@ static void AddMissingCastOpsInInitList(SmallVector &elts, for (FieldDecl *field : RD->fields()) AddMissingCastOpsInInitList(elts, eltTys, idx, field->getType(), CGF); } + } else if (IsStringType(Ty)) { + DXASSERT_NOMSG(IsStringType(eltTys[idx])); + idx++; } else { // Basic type. elts[idx] = ConvertScalarOrVector(CGF, elts[idx], eltTys[idx], Ty); @@ -4743,8 +4752,8 @@ static void FlatConstToList(CodeGenTypes &Types, bool bDefaultRowMajor, EltVals, EltQualTys); } } else { - // At this point, we should have scalars in their memory representation - DXASSERT_NOMSG(QualTy->isBuiltinType()); + // Scalar leaves, including string pointers, are in memory representation. + DXASSERT_NOMSG(QualTy->isBuiltinType() || hlsl::IsStringType(QualTy)); EltVals.emplace_back(C); EltQualTys.emplace_back(QualTy); } @@ -4922,11 +4931,16 @@ static Constant *BuildConstInitializer(CodeGenTypes &Types, return BuildConstStruct(Types, bDefaultRowMajor, QualTy, EltVals, EltQualTys, EltIdx); } else { - DXASSERT_NOMSG(QualTy->isBuiltinType()); + DXASSERT_NOMSG(QualTy->isBuiltinType() || hlsl::IsStringType(QualTy)); Constant *EltVal = EltVals[EltIdx]; QualType EltQualTy = EltQualTys[EltIdx]; EltIdx++; + if (hlsl::IsStringType(QualTy)) { + DXASSERT_NOMSG(hlsl::IsStringType(EltQualTy)); + return EltVal; + } + // Initializer constants are in their memory representation. if (EltQualTy == QualTy && MemRepr) return EltVal; @@ -5549,7 +5563,10 @@ void CGMSHLSLRuntime::FlattenAggregatePtrToGepList( CodeGenFunction &CGF, Value *Ptr, SmallVector &idxList, clang::QualType Type, llvm::Type *Ty, SmallVector &GepList, SmallVector &EltTyList) { - if (llvm::PointerType *PT = dyn_cast(Ty)) { + if (hlsl::IsStringType(Type) && Ty == CGF.ConvertType(Type)) { + GepList.push_back(CGF.Builder.CreateInBoundsGEP(Ptr, idxList)); + EltTyList.push_back(Type); + } else if (llvm::PointerType *PT = dyn_cast(Ty)) { Constant *idx = Constant::getIntegerValue( IntegerType::get(Ty->getContext(), 32), APInt(32, 0)); idxList.emplace_back(idx); @@ -5673,8 +5690,10 @@ void CGMSHLSLRuntime::LoadElements(CodeGenFunction &CGF, ArrayRef Ptrs, for (size_t i = 0, e = Ptrs.size(); i < e; i++) { Value *Ptr = Ptrs[i]; llvm::Type *Ty = Ptr->getType()->getPointerElementType(); - DXASSERT_LOCALVAR(Ty, Ty->isIntegerTy() || Ty->isFloatingPointTy(), - "Expected only element types."); + DXASSERT_LOCALVAR(Ty, + Ty->isIntegerTy() || Ty->isFloatingPointTy() || + hlsl::IsStringType(QualTys[i]), + "Expected only element types or strings."); Value *Val = CGF.Builder.CreateLoad(Ptr); Val = CGF.EmitFromMemory(Val, QualTys[i]); Vals.push_back(Val); @@ -5691,6 +5710,11 @@ void CGMSHLSLRuntime::ConvertAndStoreElements(CodeGenFunction &CGF, QualType DstQualTy = DstQualTys[i]; Value *SrcVal = SrcVals[i]; QualType SrcQualTy = SrcQualTys[i]; + if (hlsl::IsStringType(DstQualTy)) { + DXASSERT_NOMSG(hlsl::IsStringType(SrcQualTy)); + CGF.Builder.CreateStore(SrcVal, DstPtr); + continue; + } DXASSERT(SrcVal->getType()->isIntegerTy() || SrcVal->getType()->isFloatingPointTy(), "Expected only element types."); @@ -6002,6 +6026,12 @@ static void SimpleFlatValCopy(CodeGenFunction &CGF, Value *SrcVal, DXASSERT(DstTy == CGF.ConvertTypeForMem(DstQualTy), "QualType/Type mismatch!"); + if (hlsl::IsStringType(DstQualTy)) { + DXASSERT_NOMSG(hlsl::IsStringType(SrcQualTy)); + CGF.Builder.CreateStore(SrcVal, DstPtr); + return; + } + llvm::VectorType *DstVecTy = dyn_cast(DstTy); QualType DstScalarQualTy = DstQualTy; if (DstVecTy) { @@ -6030,7 +6060,11 @@ void CGMSHLSLRuntime::EmitHLSLSplat(CodeGenFunction &CGF, Value *SrcVal, SmallVector &idxList, QualType Type, QualType SrcType, llvm::Type *Ty) { - if (llvm::PointerType *PT = dyn_cast(Ty)) { + if (hlsl::IsStringType(Type) && Ty == CGF.ConvertType(Type)) { + DXASSERT_NOMSG(hlsl::IsStringType(SrcType)); + Value *DestGEP = CGF.Builder.CreateInBoundsGEP(DestPtr, idxList); + CGF.Builder.CreateStore(SrcVal, DestGEP); + } else if (llvm::PointerType *PT = dyn_cast(Ty)) { idxList.emplace_back(CGF.Builder.getInt32(0)); EmitHLSLSplat(CGF, SrcVal, DestPtr, idxList, Type, SrcType, diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp index 46967298c70..3b7b7df1627 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp @@ -1432,11 +1432,19 @@ DeclResultIdMapper::createOrUpdateStringVar(const VarDecl *var) { // generate an OpString for it. if (!var->hasInit()) { emitError("Found uninitialized string variable.", var->getLocation()); + registerVariableForDecl(var, createDeclSpirvInfo(spvBuilder.getString(""))); return nullptr; } const StringLiteral *stringLiteral = dyn_cast(var->getInit()->IgnoreParenCasts()); + if (!stringLiteral) { + emitError( + "string variable initializer must be a string literal with -spirv", + var->getInit()->getExprLoc()); + registerVariableForDecl(var, createDeclSpirvInfo(spvBuilder.getString(""))); + return nullptr; + } SpirvString *init = spvBuilder.getString(stringLiteral->getString()); registerVariableForDecl(var, createDeclSpirvInfo(init)); return init; diff --git a/tools/clang/lib/Sema/SemaDecl.cpp b/tools/clang/lib/Sema/SemaDecl.cpp index 1b1b6e1305d..8f06c3aa608 100644 --- a/tools/clang/lib/Sema/SemaDecl.cpp +++ b/tools/clang/lib/Sema/SemaDecl.cpp @@ -10381,9 +10381,10 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // HLSL Change Starts if (getLangOpts().HLSL) { const bool IsParm = true; - if (hlsl::IsStringType(parmDeclType)) { + if (getLangOpts().SPIRV && hlsl::IsStringType(parmDeclType)) { static const unsigned selectParamIdx = 1; - Diag(D.getLocStart(), diag::err_hlsl_unsupported_string_decl) << selectParamIdx; + Diag(D.getLocStart(), diag::err_hlsl_unsupported_string_decl) + << selectParamIdx; D.setInvalidType(); } if (!DiagnoseHLSLDecl(D, Context.getTranslationUnitDecl(), /*BitWidth*/ nullptr, TInfo, IsParm)) { @@ -12919,6 +12920,16 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, T = Context.IntTy; } + // HLSL Change Starts + if (!InvalidDecl && getLangOpts().HLSL && getLangOpts().SPIRV && + hlsl::IsStringType(T)) { + static const unsigned selectFieldIdx = 3; + Diag(Loc, diag::err_hlsl_unsupported_string_decl) << selectFieldIdx; + Record->setInvalidDecl(); + InvalidDecl = true; + } + // HLSL Change Ends + QualType EltTy = Context.getBaseElementType(T); if (!EltTy->isDependentType()) { if (RequireCompleteType(Loc, EltTy, diag::err_field_incomplete)) { diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 1d6b56b2693..c14c9f47c2c 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -5925,6 +5925,10 @@ class HLSLExternalSource : public ExternalSemaSource { if (Arg.getKind() == TemplateArgument::ArgKind::Type) { QualType ArgType = Arg.getAsType(); SourceLocation ArgSrcLoc = ArgLoc.getLocation(); + // Instantiate available definitions without rejecting forward + // declarations used in resource type aliases. + if (!ArgType->isDependentType()) + m_sema->RequireCompleteType(ArgSrcLoc, ArgType, 0); if (DiagnoseTypeElements( *m_sema, ArgSrcLoc, ArgType, TypeDiagContext::StructuredBuffers /*ObjDiagContext*/, @@ -10477,7 +10481,10 @@ bool HLSLExternalSource::CanConvert(SourceLocation loc, Expr *sourceExpr, lSuccess: if (standard) { if (sourceExpr->isLValue()) { - if (needsLValueToRValue) { + if (Second == ICK_Flat_Conversion && hlsl::IsStringLiteralType(source)) { + // Aggregate casts must flatten the string pointer, not its characters. + standard->First = ICK_Array_To_Pointer; + } else if (needsLValueToRValue) { // We don't need LValueToRValue cast before casting a derived object // to its base. if (Second == ICK_HLSL_Derived_To_Base) { @@ -10704,7 +10711,7 @@ void HLSLExternalSource::CheckBinOpForHLSL(SourceLocation OpLoc, SuppressWarningsFalse, SuppressErrorsFalse, &standard)) { return; } - if (RHS.get()->isLValue()) { + if (RHS.get()->isLValue() && standard.First != ICK_Array_To_Pointer) { standard.First = ICK_Lvalue_To_Rvalue; } RHS = m_sema->PerformImplicitConversion(RHS.get(), ResultTy, standard, @@ -11525,6 +11532,10 @@ HLSLExternalSource::DeduceTemplateArgumentsForHLSL( } } } else if (IsBABStore) { + if (Is2018 && DiagnoseTypeElements( + *getSema(), Args[1]->getExprLoc(), argTypes[2], + TypeDiagContext::TypeParameter, TypeDiagContext::Valid)) + return Sema::TemplateDeductionResult::TDK_Invalid; // Prior to HLSL 2018, Store operation only stored scalar uint. if (!Is2018) { if (GetNumElements(argTypes[2]) != 1) { @@ -12830,6 +12841,8 @@ void Sema::DiagnoseReachableHLSLCall(CallExpr *CE, const hlsl::ShaderModel *SM, ///////////////////////////////////////////////////////////////////////////// static bool AllowObjectInContext(QualType Ty, TypeDiagContext DiagContext) { + if (IsStringType(Ty)) + return DiagContext == TypeDiagContext::GlobalVariables; // Disallow all object in template type parameters (former // err_hlsl_objectintemplateargument) if (DiagContext == TypeDiagContext::TypeParameter) @@ -12870,6 +12883,8 @@ DiagnoseElementTypes(Sema &S, SourceLocation Loc, QualType Ty, bool &Empty, if (Ty.isNull() || Ty->isDependentType()) return false; + Ty = Ty.getNonReferenceType(); + const bool CheckLongVec = LongVecDiagContext != TypeDiagContext::Valid; const bool CheckObjects = ObjDiagContext != TypeDiagContext::Valid; @@ -12914,6 +12929,7 @@ DiagnoseElementTypes(Sema &S, SourceLocation Loc, QualType Ty, bool &Empty, case AR_TOBJ_MATRIX: Empty = false; return false; + case AR_TOBJ_STRING: case AR_TOBJ_OBJECT: Empty = false; if (!CheckObjects || AllowObjectInContext(Ty, ObjDiagContext)) @@ -15735,11 +15751,11 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC, Expr *BitWidth, } } - // String and subobject declarations are supported only as top level global - // variables. Const and static modifiers are implied - add them if missing. - if ((hlsl::IsStringType(qt) || hlslSource->IsSubobjectType(qt)) && + // Global strings and subobjects have implicit const and static modifiers. + // Strings may also be fields or local variables without these modifiers. + if (((hlsl::IsStringType(qt) && !isField && !isLocalVar) || + hlslSource->IsSubobjectType(qt)) && !D.isInvalidType()) { - // string are supported only as top level global variables if (!DC->isTranslationUnit()) { Diag(D.getLocStart(), diag::err_hlsl_object_not_global) << (int)hlsl::IsStringType(qt); @@ -15752,7 +15768,7 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC, Expr *BitWidth, } const char *PrevSpec = nullptr; unsigned DiagID = 0; - if (!isStatic) { + if (!isStatic && !isParameter) { D.getMutableDeclSpec().SetStorageClassSpec( *this, DeclSpec::SCS_static, D.getLocStart(), PrevSpec, DiagID, Context.getPrintingPolicy()); @@ -16195,8 +16211,21 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC, Expr *BitWidth, result = false; } - // Disallow intangible HLSL objects in the global scope. - if (isGlobal) { + // Recheck element types when a resource alias is used after its forward- + // declared element type has been defined. + if (!isTypedef && hlsl::IsHLSLStructuredBufferType(qt)) { + QualType ElementTy = hlsl::GetHLSLResourceResultType(qt); + if (!ElementTy->isDependentType() && + !RequireCompleteType(D.getLocStart(), ElementTy, 0) && + DiagnoseTypeElements(*this, D.getLocStart(), ElementTy, + TypeDiagContext::StructuredBuffers, + TypeDiagContext::Valid, nullptr, + hlsl::GetHLSLResourceClass(qt))) + result = false; + } + + // Disallow intangible HLSL objects in externally visible storage. + if (isGlobal || (isParameter && isGroupShared)) { // Suppress actual emitting of errors for incompletable types here // They are redundant to those produced in ActOnUninitializedDecl. struct SilentDiagnoser : public TypeDiagnoser { diff --git a/tools/clang/test/CodeGenSPIRV/type.string.field.hlsl b/tools/clang/test/CodeGenSPIRV/type.string.field.hlsl new file mode 100644 index 00000000000..d9aa4132e84 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/type.string.field.hlsl @@ -0,0 +1,17 @@ +// RUN: %dxc -T cs_6_0 -E main -HV 2021 -spirv -verify %s +// RUN: %dxc -T cs_6_0 -E main -HV 202x -spirv -verify %s + +struct StringState { + string Text; // expected-error {{field of type string is not supported}} +}; + +template +struct Wrapper { + T Text; // expected-error {{field of type string is not supported}} +}; + +[numthreads(1, 1, 1)] +void main() { + // expected-note@+1 {{in instantiation of template class 'Wrapper' requested here}} + Wrapper Wrapped; +} diff --git a/tools/clang/test/CodeGenSPIRV/type.string.hlsl b/tools/clang/test/CodeGenSPIRV/type.string.hlsl index 0edb63a9dca..cb6c842f56c 100644 --- a/tools/clang/test/CodeGenSPIRV/type.string.hlsl +++ b/tools/clang/test/CodeGenSPIRV/type.string.hlsl @@ -11,5 +11,6 @@ const string a = "first string"; [numthreads(1,1,1)] void main() { + // CHECK: {{%[0-9]+}} = OpString "local string" + string local = ("local string"); } - diff --git a/tools/clang/test/CodeGenSPIRV/type.string.initializer.hlsl b/tools/clang/test/CodeGenSPIRV/type.string.initializer.hlsl new file mode 100644 index 00000000000..7a826831ef1 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/type.string.initializer.hlsl @@ -0,0 +1,11 @@ +// RUN: not %dxc -T cs_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s --implicit-check-not="fatal error:" + +string globalText = "text"; + +[numthreads(1, 1, 1)] +void main() { + // CHECK: error: string variable initializer must be a string literal with -spirv + // CHECK-NEXT: string local = globalText; + string local = globalText; + printf(local); +} diff --git a/tools/clang/test/CodeGenSPIRV/type.string.parameter.hlsl b/tools/clang/test/CodeGenSPIRV/type.string.parameter.hlsl new file mode 100644 index 00000000000..7a223addb8c --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/type.string.parameter.hlsl @@ -0,0 +1,12 @@ +// RUN: not %dxc -T cs_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s + +// CHECK: error: parameter of type string is not supported +// CHECK-NEXT: void log(string text) { +void log(string text) { + printf(text); +} + +[numthreads(1, 1, 1)] +void main() { + log("hello"); +} diff --git a/tools/clang/test/CodeGenSPIRV/type.string.uninitialized.hlsl b/tools/clang/test/CodeGenSPIRV/type.string.uninitialized.hlsl index 0f36693d955..8df09e22b68 100644 --- a/tools/clang/test/CodeGenSPIRV/type.string.uninitialized.hlsl +++ b/tools/clang/test/CodeGenSPIRV/type.string.uninitialized.hlsl @@ -1,8 +1,16 @@ -// RUN: not %dxc -T cs_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s +// RUN: not %dxc -T cs_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s --implicit-check-not="fatal error:" +// RUN: not %dxc -T cs_6_0 -E main -fcgl -DLOCAL_STRING %s -spirv 2>&1 | FileCheck %s --implicit-check-not="fatal error:" -// CHECK: 4:8: error: Found uninitialized string variable. +// CHECK: error: Found uninitialized string variable. +#ifndef LOCAL_STRING string first; +#endif [numthreads(1,1,1)] -void main() {} +void main() { +#ifdef LOCAL_STRING + string local; + printf(local); +#endif +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/string-constant-initializers.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/string-constant-initializers.hlsl new file mode 100644 index 00000000000..02e0451ba27 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/string-constant-initializers.hlsl @@ -0,0 +1,144 @@ +// RUN: %dxc -T cs_6_0 -E main -HV 202x %s | FileCheck %s --check-prefixes=CHECK,OPT +// RUN: %dxc -T cs_6_0 -E main -HV 202x -Od %s | FileCheck %s --check-prefixes=CHECK,NOOPT +// RUN: %dxc -T cs_6_0 -E main -HV 202x -Zi -Qembed_debug %s | FileCheck %s --check-prefixes=CHECK,OPT +// RUN: %dxc -T cs_6_0 -E main -HV 2021 %s | FileCheck %s --check-prefixes=CHECK,OPT +// RUN: %dxc -T cs_6_0 -E main -HV 202x -fcgl %s | FileCheck %s --check-prefix=FCGL +// RUN: %dxc -T cs_6_0 -E main -HV 2021 -fcgl %s | FileCheck %s --check-prefix=FCGL + +// CHECK: call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle {{.*}}, i32 0, i32 undef, i32 3, +// CHECK: call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle {{.*}}, i32 4, i32 undef, i32 4, +// CHECK: call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle {{.*}}, i32 8, i32 undef, i32 5, +// CHECK: call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle {{.*}}, i32 12, i32 undef, i32 3, +// CHECK: call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle {{.*}}, i32 16, i32 undef, i32 6, +// CHECK: call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle {{.*}}, i32 20, i32 undef, i32 3, +// CHECK: call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle {{.*}}, i32 24, i32 undef, i32 7, +// CHECK: call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle {{.*}}, i32 28, i32 undef, i32 6, +// OPT: call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle {{.*}}, i32 32, i32 undef, i32 5, +// NOOPT: [[FLOAT:%[^ ]+]] = uitofp i32 5 to float +// NOOPT: [[INT:%[^ ]+]] = fptoui float [[FLOAT]] to i32 +// NOOPT: call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle {{.*}}, i32 32, i32 undef, i32 [[INT]], + +// FCGL-DAG: %struct.StringState = type { i8*, i32 } +// FCGL-DAG: %struct.StringOnly = type { i8* } +// FCGL-DAG: %struct.NestedState = type { [2 x %struct.StringState] } +// FCGL-DAG: %struct.DerivedState = type { %struct.StringState, i8* } +// FCGL-DAG: @GlobalText = internal constant i8* getelementptr inbounds ([6 x i8], [6 x i8]* [[HELLO:@"[^"]+"]], i32 0, i32 0) +// FCGL-DAG: @OnlyText = internal constant %struct.StringOnly { i8* getelementptr inbounds ([6 x i8], [6 x i8]* [[HELLO]], i32 0, i32 0) } +// FCGL-DAG: @GlobalLiteral = internal global %struct.StringState { i8* getelementptr inbounds ([6 x i8], [6 x i8]* [[HELLO]], i32 0, i32 0), i32 3 } +// FCGL-DAG: [[HELLO]] = linkonce_odr unnamed_addr constant [6 x i8] c"hello\00" +// FCGL-LABEL: define void @main() +// FCGL: [[COPY_IN:%[^ ]+]] = load i8*, i8** %AliasedText +// FCGL-NEXT: store i8* [[COPY_IN]], i8** [[COPY_TMP:%[^, ]+]] +// FCGL-NEXT: call void {{.*CopyAliasedText.*}}(i8** dereferenceable(4) %AliasedText, i8** dereferenceable(4) [[COPY_TMP]]) +// FCGL-NEXT: [[COPY_OUT:%[^ ]+]] = load i8*, i8** [[COPY_TMP]] +// FCGL-NEXT: store i8* [[COPY_OUT]], i8** %AliasedText +// FCGL: [[LITERAL_FIELD:%[^ ]+]] = getelementptr inbounds %struct.StringOnly, %struct.StringOnly* %LiteralText, i32 0, i32 0 +// FCGL-NEXT: store i8* getelementptr inbounds ([6 x i8], [6 x i8]* [[HELLO]], i32 0, i32 0), i8** [[LITERAL_FIELD]] +// FCGL: [[EMPTY_FIELD:%[^ ]+]] = getelementptr inbounds %struct.StringOnly, %struct.StringOnly* %EmptyLiteralText, i32 0, i32 0 +// FCGL-NEXT: store i8* getelementptr inbounds ([1 x i8], [1 x i8]* {{@"[^"]+"}}, i32 0, i32 0), i8** [[EMPTY_FIELD]] +// FCGL: [[PAREN_FIELD:%[^ ]+]] = getelementptr inbounds %struct.StringOnly, %struct.StringOnly* %ParenLiteralText, i32 0, i32 0 +// FCGL-NEXT: store i8* getelementptr inbounds ([6 x i8], [6 x i8]* [[HELLO]], i32 0, i32 0), i8** [[PAREN_FIELD]] +// FCGL-LABEL: define internal void {{.*CopyText.*}}(i8* %Text, i8** noalias dereferenceable(4) %Result) +// FCGL: [[SLOT:%[^ ]+]] = alloca i8* +// FCGL: store i8* %Text, i8** [[SLOT]] +// FCGL: [[VALUE:%[^ ]+]] = load i8*, i8** [[SLOT]] +// FCGL: store i8* [[VALUE]], i8** %Result +// FCGL-LABEL: define internal void {{.*ConvertState.*}} +// FCGL: [[TEXT_PTR:%[^ ]+]] = getelementptr inbounds %struct.StringState, %struct.StringState* %State, i32 0, i32 0 +// FCGL: [[TEXT:%[^ ]+]] = load i8*, i8** [[TEXT_PTR]] +// FCGL: store i8* [[TEXT]], i8** +// FCGL: uitofp i32 +// FCGL-LABEL: define internal void {{.*SplatText.*}}(%struct.StringOnly* noalias sret %agg.result, i8* %Text) +// FCGL: [[SPLAT_TEXT:%[^ ]+]] = load i8*, i8** +// FCGL: [[SPLAT_FIELD:%[^ ]+]] = getelementptr inbounds %struct.StringOnly, %struct.StringOnly* {{.*}}, i32 0, i32 0 +// FCGL: store i8* [[SPLAT_TEXT]], i8** [[SPLAT_FIELD]] + +struct StringOnly { + string Text; +}; + +struct StringState { + string Text; + uint Value; +}; + +struct FloatStringState { + string Text; + float Value; +}; + +typedef StringState StateType; + +struct NestedState { + StringState Values[2]; +}; + +struct FloatNestedState { + FloatStringState Values[2]; +}; + +struct DerivedState : StringState { + string Other; +}; + +static const string GlobalText = "hello"; +static StringState GlobalLiteral = {"hello", 3}; +static const StateType GlobalReference = {GlobalText, 4}; +static NestedState Nested = {{{"hello", 5}, GlobalLiteral}}; +static DerivedState Derived = {GlobalLiteral, GlobalText}; +static const StringOnly OnlyText = {"hello"}; + +RWByteAddressBuffer Output : register(u0); + +StringState Copy(StringState State) { + return State; +} + +void Set(out StringState State) { + State.Text = "hello"; + State.Value = 6; +} + +void CopyText(string Text, out string Result) { + Result = Text; +} + +FloatStringState ConvertState(StringState State) { + return (FloatStringState)State; +} + +StringOnly SplatText(string Text) { + return (StringOnly)Text; +} + +void CopyAliasedText(inout string First, inout string Second) { + First = "changed"; + Second = First; +} + +[numthreads(1, 1, 1)] +void main() { + string AliasedText = GlobalText; + CopyAliasedText(AliasedText, AliasedText); + StringState Local = Copy(GlobalLiteral); + Output.Store(0, Local.Value); + Output.Store(4, GlobalReference.Value); + Output.Store(8, Nested.Values[0].Value); + Output.Store(12, Derived.Value); + StringOnly Text = OnlyText; + CopyText(Derived.Other, Text.Text); + Local.Text = Text.Text; + Set(Local); + Output.Store(16, Local.Value); + Output.Store(20, Nested.Values[1].Value); + static const StringState StaticLocal = {"hello", 7}; + Output.Store(24, StaticLocal.Value); + FloatStringState Converted = ConvertState(Local); + Output.Store(28, (uint)Converted.Value); + FloatNestedState ConvertedNested = (FloatNestedState)Nested; + Output.Store(32, (uint)ConvertedNested.Values[0].Value); + Text = SplatText(GlobalText); + StringOnly LiteralText = (StringOnly)"hello"; + StringOnly EmptyLiteralText = (StringOnly)""; + StringOnly ParenLiteralText = (StringOnly)("he" "llo"); +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/string-empty-aggregates.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/string-empty-aggregates.hlsl new file mode 100644 index 00000000000..968293221c6 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/string-empty-aggregates.hlsl @@ -0,0 +1,47 @@ +// RUN: %dxc -T cs_6_0 -E main %s | FileCheck %s +// RUN: %dxc -T cs_6_0 -E main -fcgl %s | FileCheck %s + +// String containment must visit distinct types, not every path through this +// shared type graph, even when no strings are present. +// CHECK: define void @main() + +struct Empty {}; +struct S1 { Empty A, B; }; +struct S2 { S1 A, B; }; +struct S3 { S2 A, B; }; +struct S4 { S3 A, B; }; +struct S5 { S4 A, B; }; +struct S6 { S5 A, B; }; +struct S7 { S6 A, B; }; +struct S8 { S7 A, B; }; +struct S9 { S8 A, B; }; +struct S10 { S9 A, B; }; +struct S11 { S10 A, B; }; +struct S12 { S11 A, B; }; +struct S13 { S12 A, B; }; +struct S14 { S13 A, B; }; +struct S15 { S14 A, B; }; +struct S16 { S15 A, B; }; +struct S17 { S16 A, B; }; +struct S18 { S17 A, B; }; +struct S19 { S18 A, B; }; +struct S20 { S19 A, B; }; +struct S21 { S20 A, B; }; +struct S22 { S21 A, B; }; +struct S23 { S22 A, B; }; +struct S24 { S23 A, B; }; +struct S25 { S24 A, B; }; +struct S26 { S25 A, B; }; +struct S27 { S26 A, B; }; +struct S28 { S27 A, B; }; +struct S29 { S28 A, B; }; +struct S30 { S29 A, B; }; +struct S31 { S30 A, B; }; +struct S32 { S31 A, B; }; + +static S32 State; + +[numthreads(1, 1, 1)] +void main() { + S32 Local = State; +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/structured-buffer-forward-declaration.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/structured-buffer-forward-declaration.hlsl new file mode 100644 index 00000000000..70f2d858bc9 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/structured-buffer-forward-declaration.hlsl @@ -0,0 +1,20 @@ +// RUN: %dxc -T cs_6_0 -E main -HV 2021 %s | FileCheck %s +// RUN: %dxc -T cs_6_0 -E main -HV 202x %s | FileCheck %s + +struct Element; +typedef StructuredBuffer InputBuffer; +typedef RWStructuredBuffer OutputBuffer; + +struct Element { + uint Value; +}; + +InputBuffer Input; +OutputBuffer Output; + +// CHECK: call %dx.types.ResRet.i32 @dx.op.bufferLoad.i32 +// CHECK: call void @dx.op.bufferStore.i32 +[numthreads(1, 1, 1)] +void main() { + Output[0] = Input[0]; +} diff --git a/tools/clang/test/SemaHLSL/string-storage.hlsl b/tools/clang/test/SemaHLSL/string-storage.hlsl new file mode 100644 index 00000000000..6b7d07e98b3 --- /dev/null +++ b/tools/clang/test/SemaHLSL/string-storage.hlsl @@ -0,0 +1,140 @@ +// RUN: %dxc -T lib_6_8 -HV 2021 -verify %s +// RUN: %dxc -T lib_6_8 -HV 202x -verify %s + +struct StringState { + string Text; // expected-note 19 {{field declared here}} +}; + +struct NestedState { + StringState Values[2]; +}; + +struct DerivedState : StringState { + uint Value; +}; + +struct Numeric { + uint Value; +}; + +template +struct Wrapper { + T Value; +}; + +// expected-error@+1 {{object 'const string' is not allowed in ConstantBuffers or TextureBuffers}} +ConstantBuffer CB; +// expected-error@+1 {{object 'const string' is not allowed in ConstantBuffers or TextureBuffers}} +TextureBuffer TB; +// expected-error@+1 {{object 'const string' is not allowed in structured buffers}} +StructuredBuffer SB; +// expected-error@+1 {{object 'const string' is not allowed in structured buffers}} +RWStructuredBuffer RWSB; +// expected-error@+1 {{object 'const string' is not allowed in structured buffers}} +AppendStructuredBuffer ASB; +// expected-error@+1 {{object 'const string' is not allowed in structured buffers}} +ConsumeStructuredBuffer CSB; +// expected-error@+1 {{object 'const string' is not allowed in structured buffers}} +RasterizerOrderedStructuredBuffer ROSB; +// expected-error@+1 {{object 'const string' is not allowed in structured buffers}} +StructuredBuffer DirectSB; +// expected-error@+1 {{object 'const string' is not allowed in structured buffers}} +RWStructuredBuffer > Wrapped; + +struct ForwardStringState; +typedef StructuredBuffer ForwardStringBuffer; +typedef RWStructuredBuffer ForwardRWStringBuffer; + +struct ForwardStringState { + string Text; // expected-note 2 {{field declared here}} +}; + +// expected-error@+1 {{object 'const string' is not allowed in structured buffers}} +ForwardStringBuffer ForwardSB; +// expected-error@+1 {{object 'const string' is not allowed in structured buffers}} +ForwardRWStringBuffer ForwardRWSB; + +// expected-error@+1 {{'const string' cannot be used as a type parameter}} +Buffer DirectBuffer; +// expected-error@+2 {{'const string' cannot be used as a type parameter}} +// expected-note@+1 {{usage of 'const string' found in field 'Text'}} +RWTexture2D Texture; + +// expected-error@+1 {{object 'const string' is not allowed in cbuffers or tbuffers}} +NestedState Global; +cbuffer Constants { + // expected-error@+1 {{object 'const string' is not allowed in cbuffers or tbuffers}} + StringState State; +}; +tbuffer TextureConstants { + // expected-error@+1 {{object 'const string' is not allowed in cbuffers or tbuffers}} + DerivedState Derived; +}; + +// expected-error@+1 {{object 'const string' is not allowed in groupshared variables}} +groupshared string SharedString; +// expected-error@+1 {{object 'const string' is not allowed in groupshared variables}} +groupshared StringState Shared; +// expected-error@+1 {{object 'const string' is not allowed in groupshared variables}} +groupshared NestedState SharedArray[2]; +// expected-error@+1 {{object 'const string' is not allowed in groupshared variables}} +groupshared DerivedState SharedDerived; + +// expected-error@+1 {{object 'const string' is not allowed in groupshared variables}} +void SharedParameter(groupshared StringState State); +#if __HLSL_VERSION <= 2021 +// expected-warning@-2 {{Support for groupshared parameter annotation not added until HLSL 202x}} +#endif + +ByteAddressBuffer Bytes; +RWByteAddressBuffer RWBytes; + +void ByteAddressAccess(StringState A, NestedState B, DerivedState C) { + // expected-error@+2 {{Explicit template arguments on intrinsic Load must be a single numeric type}} + // expected-error@+1 {{object 'const string' is not allowed in builtin template parameters}} + A = Bytes.Load(0); + // expected-error@+2 {{Explicit template arguments on intrinsic Load must be a single numeric type}} + // expected-error@+1 {{object 'const string' is not allowed in builtin template parameters}} + B = RWBytes.Load(0); + // expected-error@+2 {{Explicit template arguments on intrinsic Store must be a single numeric type}} + // expected-error@+1 {{object 'const string' is not allowed in builtin template parameters}} + RWBytes.Store(0, C); + // expected-error@+2 {{object 'const string' is not allowed in builtin template parameters}} + // expected-error@+1 {{no matching member function for call to 'Store'}} + RWBytes.Store(0, C); + // expected-note@? {{candidate template ignored: couldn't infer template argument 'TResult'}} +} + +ConstantBuffer NumericCB; +RWStructuredBuffer NumericBuffer; +groupshared Numeric SharedNumeric[2]; +static StringState PrivateState; + +void PrivateStrings() { + string Text = "hello"; + StringState Local = {Text}; + NestedState Nested = {{Local, Local}}; + Text = "goodbye"; + Local.Text = Text; + PrivateState = Local; +} + +[shader("pixel")] +float4 StringInput(string Text : TEXCOORD0) : SV_Target { + // expected-error@-1 {{object 'const string' is not allowed in entry function parameters}} + return 0; +} + +[shader("pixel")] +float4 StringOutput(out string Text : SV_Target1) : SV_Target0 { + // expected-error@-1 {{object 'const string' is not allowed in entry function parameters}} + Text = "hello"; + return 0; +} + +[shader("pixel")] +float4 StringInOut(inout string Text : TEXCOORD0) : SV_Target { + // expected-error@-1 {{object 'const string' is not allowed in entry function parameters}} + Text = "hello"; + return 0; +} diff --git a/tools/clang/test/SemaHLSL/string.hlsl b/tools/clang/test/SemaHLSL/string.hlsl index dc4ca5b3321..36224de1ada 100644 --- a/tools/clang/test/SemaHLSL/string.hlsl +++ b/tools/clang/test/SemaHLSL/string.hlsl @@ -26,30 +26,30 @@ string s_global_concat = "my string " "with " "broken up" " parts"; -static const bool b1 = s_global1; /* expected-error {{cannot initialize a variable of type 'const bool' with an lvalue of type 'string'}} fxc-error {{X3017: cannot implicitly convert from 'const string' to 'const bool'}} */ +static const bool b1 = s_global1; /* expected-error {{cannot initialize a variable of type 'const bool' with an lvalue of type 'const string'}} fxc-error {{X3017: cannot implicitly convert from 'const string' to 'const bool'}} */ static const bool b2 = false; -static const string s_global4 = true; /* expected-error {{cannot initialize a variable of type 'string' with an rvalue of type 'bool'}} fxc-error {{X3017: cannot implicitly convert from 'bool' to 'const string'}} */ -static const string s_global5 = b2; /* expected-error {{cannot initialize a variable of type 'string' with an lvalue of type 'const bool'}} fxc-error {{X3017: cannot implicitly convert from 'const bool' to 'const string'}} */ +static const string s_global4 = true; /* expected-error {{cannot initialize a variable of type 'const string' with an rvalue of type 'bool'}} fxc-error {{X3017: cannot implicitly convert from 'bool' to 'const string'}} */ +static const string s_global5 = b2; /* expected-error {{cannot initialize a variable of type 'const string' with an lvalue of type 'const bool'}} fxc-error {{X3017: cannot implicitly convert from 'const bool' to 'const string'}} */ -static const int i1 = s_global1; /* expected-error {{cannot initialize a variable of type 'const int' with an lvalue of type 'string'}} fxc-error {{X3017: cannot implicitly convert from 'const string' to 'const int'}} */ +static const int i1 = s_global1; /* expected-error {{cannot initialize a variable of type 'const int' with an lvalue of type 'const string'}} fxc-error {{X3017: cannot implicitly convert from 'const string' to 'const int'}} */ static const int i2 = 10; -static const string s_global6 = 10; /* expected-error {{cannot initialize a variable of type 'string' with an rvalue of type 'literal int'}} fxc-error {{X3017: cannot implicitly convert from 'int' to 'const string'}} */ -static const string s_global7 = i2; /* expected-error {{cannot initialize a variable of type 'string' with an lvalue of type 'const int'}} fxc-error {{X3017: cannot implicitly convert from 'const int' to 'const string'}} */ +static const string s_global6 = 10; /* expected-error {{cannot initialize a variable of type 'const string' with an rvalue of type 'literal int'}} fxc-error {{X3017: cannot implicitly convert from 'int' to 'const string'}} */ +static const string s_global7 = i2; /* expected-error {{cannot initialize a variable of type 'const string' with an lvalue of type 'const int'}} fxc-error {{X3017: cannot implicitly convert from 'const int' to 'const string'}} */ -static const float f1 = s_global1; /* expected-error {{cannot initialize a variable of type 'const float' with an lvalue of type 'string'}} fxc-error {{X3017: cannot implicitly convert from 'const string' to 'const float'}} */ +static const float f1 = s_global1; /* expected-error {{cannot initialize a variable of type 'const float' with an lvalue of type 'const string'}} fxc-error {{X3017: cannot implicitly convert from 'const string' to 'const float'}} */ static const float f2 = 3.15; -static const string s_global8= 3.14; /* expected-error {{cannot initialize a variable of type 'string' with an rvalue of type 'literal float'}} fxc-error {{X3017: cannot implicitly convert from 'float' to 'const string'}} */ -static const string s_global9= f2; /* expected-error {{cannot initialize a variable of type 'string' with an lvalue of type 'const float'}} fxc-error {{X3017: cannot implicitly convert from 'const float' to 'const string'}} */ +static const string s_global8= 3.14; /* expected-error {{cannot initialize a variable of type 'const string' with an rvalue of type 'literal float'}} fxc-error {{X3017: cannot implicitly convert from 'float' to 'const string'}} */ +static const string s_global9= f2; /* expected-error {{cannot initialize a variable of type 'const string' with an lvalue of type 'const float'}} fxc-error {{X3017: cannot implicitly convert from 'const float' to 'const string'}} */ static const string s_global10 = { 'A', 'B', 'C' }; /* expected-error {{too many elements in vector initialization (expected 1 element, have 3)}} fxc-error {{X3017: 's_global10': initializer does not match type}} */ static const string s_global11 = { 1, 2, 3 }; /* expected-error {{too many elements in vector initialization (expected 1 element, have 3)}} fxc-error {{X3017: 's_global11': initializer does not match type}} */ static const string s_global12 = { "ABC" }; string g_strArray[5]; /* expected-error {{array of type string is not supported}} fxc-pass {{}} */ -vector g_strVector1; /* expected-error {{'string' cannot be used as a type parameter where a scalar is required}} fxc-error {{X3122: vector element type must be a scalar type}} */ -matrix g_strMatrix1; /* expected-error {{'string' cannot be used as a type parameter where a scalar is required}} fxc-error {{X3123: matrix element type must be a scalar type}} */ +vector g_strVector1; /* expected-error {{'const string' cannot be used as a type parameter where a scalar is required}} fxc-error {{X3122: vector element type must be a scalar type}} */ +matrix g_strMatrix1; /* expected-error {{'const string' cannot be used as a type parameter where a scalar is required}} fxc-error {{X3123: matrix element type must be a scalar type}} */ -void hello_here(string message, string s, float f) { /* expected-error {{parameter of type string is not supported}} expected-error {{parameter of type string is not supported}} fxc-pass {{}} */ +void hello_here(string message, string s, float f) { /* fxc-pass {{}} */ printf(s); printf(message); printf("%f", f); @@ -60,17 +60,17 @@ string get_message() { /* expected-error {{ } struct test { - string field; /* expected-error {{string declaration may only appear in global scope}} fxc-pass {{}} */ + string field; /* fxc-pass {{}} */ }; [shader("pixel")] float4 main() : SV_Target0 { /* */ - string str; /* expected-error {{string declaration may only appear in global scope}} fxc-pass {{}} */ - str = s_global2; /* expected-error {{use of undeclared identifier 'str'}} fxc-pass {{}} */ + string str; /* fxc-pass {{}} */ + str = s_global2; /* fxc-pass {{}} */ string strArray[5]; /* expected-error {{array of type string is not supported}} fxc-pass {{}} */ - vector strVector1; /* expected-error {{'string' cannot be used as a type parameter where a scalar is required}} fxc-error {{X3122: vector element type must be a scalar type}} */ - matrix strMatrix1; /* expected-error {{'string' cannot be used as a type parameter where a scalar is required}} fxc-error {{X3123: matrix element type must be a scalar type}} */ + vector strVector1; /* expected-error {{'const string' cannot be used as a type parameter where a scalar is required}} fxc-error {{X3122: vector element type must be a scalar type}} */ + matrix strMatrix1; /* expected-error {{'const string' cannot be used as a type parameter where a scalar is required}} fxc-error {{X3123: matrix element type must be a scalar type}} */ float4 cp4_local; printf("hi mom", 1, 2, 3); diff --git a/tools/clang/test/SemaHLSL/subobjects-ast-dump.hlsl b/tools/clang/test/SemaHLSL/subobjects-ast-dump.hlsl index ecd155ed41c..9413814b6e1 100644 --- a/tools/clang/test/SemaHLSL/subobjects-ast-dump.hlsl +++ b/tools/clang/test/SemaHLSL/subobjects-ast-dump.hlsl @@ -15,18 +15,18 @@ // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 1 2 // ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final -// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Data 'string' +// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Data 'const string' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit referenced struct LocalRootSignature definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 2 2 // ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final -// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Data 'string' +// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Data 'const string' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit referenced struct SubobjectToExportsAssociation definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 8 2 // ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final -// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Subobject 'string' -// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Exports 'string' +// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Subobject 'const string' +// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Exports 'const string' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit referenced struct RaytracingShaderConfig definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 9 2 // ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit @@ -42,15 +42,15 @@ // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 11 0 // ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final -// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit AnyHit 'string' -// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit ClosestHit 'string' +// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit AnyHit 'const string' +// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit ClosestHit 'const string' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit referenced struct ProceduralPrimitiveHitGroup definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 11 1 // ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final -// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit AnyHit 'string' -// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit ClosestHit 'string' -// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Intersection 'string' +// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit AnyHit 'const string' +// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit ClosestHit 'const string' +// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Intersection 'const string' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit referenced struct RaytracingPipelineConfig1 definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 12 2 // ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit diff --git a/tools/clang/test/SemaHLSL/subobjects-syntax.hlsl b/tools/clang/test/SemaHLSL/subobjects-syntax.hlsl index 5ab083a064e..f9e1fa5e2d2 100644 --- a/tools/clang/test/SemaHLSL/subobjects-syntax.hlsl +++ b/tools/clang/test/SemaHLSL/subobjects-syntax.hlsl @@ -7,7 +7,7 @@ string localRs = "UAV(u0, visibility = SHADER_VISIBILITY_GEOMETRY)"; GlobalRootSignature grs1_1 = {"CBV(b0)"}; GlobalRootSignature grs1_2 = { globalRs }; -GlobalRootSignature grs2_2 = globalRs; /* expected-error {{cannot initialize a variable of type 'GlobalRootSignature' with an lvalue of type 'string'}} */ +GlobalRootSignature grs2_2 = globalRs; /* expected-error {{cannot initialize a variable of type 'GlobalRootSignature' with an lvalue of type 'const string'}} */ GlobalRootSignature grs2_3 = "CBV(b0)"; /* expected-error {{cannot initialize a variable of type 'GlobalRootSignature' with an lvalue of type 'literal string'}} */ GlobalRootSignature grs2_4 = 10; /* expected-error {{cannot initialize a variable of type 'GlobalRootSignature' with an rvalue of type 'literal int'}} */ GlobalRootSignature grs2_5 = {"CBV(b0)", 78};; /* expected-error {{too many elements in subobject initialization (expected 1 element, have 2)}} */ @@ -29,7 +29,7 @@ StateObjectConfig soc2_7 = 1.5f; /* expected-error {{ LocalRootSignature lrs1_1 = {"UAV(u0, visibility = SHADER_VISIBILITY_GEOMETRY)"}; LocalRootSignature lrs1_2 = { localRs }; -LocalRootSignature lrs2_2 = localRs; /* expected-error {{cannot initialize a variable of type 'LocalRootSignature' with an lvalue of type 'string'}} */ +LocalRootSignature lrs2_2 = localRs; /* expected-error {{cannot initialize a variable of type 'LocalRootSignature' with an lvalue of type 'const string'}} */ LocalRootSignature lrs2_3 = "UAV(u0, visibility = SHADER_VISIBILITY_GEOMETRY)"; /* expected-error {{cannot initialize a variable of type 'LocalRootSignature' with an lvalue of type 'literal string'}} */ LocalRootSignature lrs2_4 = 10; /* expected-error {{cannot initialize a variable of type 'LocalRootSignature' with an rvalue of type 'literal int'}} */ LocalRootSignature lrs2_5 = { 1.7f, "UAV(u0, visibility = SHADER_VISIBILITY_GEOMETRY)" };; /* expected-error {{too many elements in subobject initialization (expected 1 element, have 2)}} */ @@ -83,7 +83,7 @@ TriangleHitGroup trHitGt2_3 = { "a", 10 }; /* expected-error TriangleHitGroup trHitGt2_4 = { 1, 2 }; /* expected-error {{type mismatch}} */ TriangleHitGroup trHitGt2_5 = "foo"; /* expected-error {{cannot initialize a variable of type 'TriangleHitGroup' with an lvalue of type 'literal string'}} */ TriangleHitGroup trHitGt2_6 = 115; /* expected-error {{cannot initialize a variable of type 'TriangleHitGroup' with an rvalue of type 'literal int'}} */ -TriangleHitGroup trHitGt2_7 = s2; /* expected-error {{cannot initialize a variable of type 'TriangleHitGroup' with an lvalue of type 'string'}} */ +TriangleHitGroup trHitGt2_7 = s2; /* expected-error {{cannot initialize a variable of type 'TriangleHitGroup' with an lvalue of type 'const string'}} */ ProceduralPrimitiveHitGroup ppHitGt1_1 = { "a", "b", "c"}; ProceduralPrimitiveHitGroup ppHitGt1_2 = { s1, s2, s3 }; @@ -94,7 +94,7 @@ ProceduralPrimitiveHitGroup ppHitGt2_3 = { "a", "b", 10 }; /* expected-error ProceduralPrimitiveHitGroup ppHitGt2_4 = { 1, 2, 3 }; /* expected-error {{type mismatch}} */ ProceduralPrimitiveHitGroup ppHitGt2_5 = "foo"; /* expected-error {{cannot initialize a variable of type 'ProceduralPrimitiveHitGroup' with an lvalue of type 'literal string'}} */ ProceduralPrimitiveHitGroup ppHitGt2_6 = 115; /* expected-error {{cannot initialize a variable of type 'ProceduralPrimitiveHitGroup' with an rvalue of type 'literal int'}} */ -ProceduralPrimitiveHitGroup ppHitGt2_7 = s2; /* expected-error {{cannot initialize a variable of type 'ProceduralPrimitiveHitGroup' with an lvalue of type 'string'}} */ +ProceduralPrimitiveHitGroup ppHitGt2_7 = s2; /* expected-error {{cannot initialize a variable of type 'ProceduralPrimitiveHitGroup' with an lvalue of type 'const string'}} */ TriangleHitGroup trHitGt2_8 = { s1, s4 }; ProceduralPrimitiveHitGroup ppHitGt2_8 = { s1, "", s4 };