@@ -10829,18 +10829,24 @@ HLSLExternalSource::ApplyTypeSpecSignToParsedType(clang::QualType &type,
1082910829 }
1083010830}
1083110831
10832- bool DiagnoseIntersectionAttributes(Sema &S, SourceLocation Loc, QualType Ty) {
10833- // Must be a UDT
10832+ bool CheckIntersectionAttributeArg(Sema &S, Expr *E) {
10833+ SourceLocation Loc = E->getExprLoc();
10834+ QualType Ty = E->getType();
10835+
10836+ // Identify problematic fields first (high diagnostic accuracy, may miss some
10837+ // invalid cases)
10838+ const TypeDiagContext DiagContext = TypeDiagContext::Attributes;
10839+ if (DiagnoseTypeElements(S, Loc, Ty, DiagContext, DiagContext))
10840+ return true;
10841+
10842+ // Must be a UDT (low diagnostic accuracy, catches remaining invalid cases)
1083410843 if (Ty.isNull() || !hlsl::IsHLSLCopyableAnnotatableRecord(Ty)) {
1083510844 S.Diag(Loc, diag::err_payload_attrs_must_be_udt)
1083610845 << /*payload|attributes|callable*/ 1 << /*parameter %2|type*/ 1;
10837- return false ;
10846+ return true ;
1083810847 }
1083910848
10840- const TypeDiagContext DiagContext = TypeDiagContext::Attributes;
10841- if (DiagnoseTypeElements(S, Loc, Ty, DiagContext, DiagContext))
10842- return false;
10843- return true;
10849+ return false;
1084410850}
1084510851
1084610852Sema::TemplateDeductionResult
@@ -10951,7 +10957,6 @@ HLSLExternalSource::DeduceTemplateArgumentsForHLSL(
1095110957 LPCSTR tableName = cursor.GetTableName();
1095210958 // Currently only intrinsic we allow for explicit template arguments are
1095310959 // for Load/Store for ByteAddressBuffer/RWByteAddressBuffer
10954- // and HitObject::GetAttributes with user-defined intersection attributes.
1095510960
1095610961 // Check Explicit template arguments
1095710962 UINT intrinsicOp = (*cursor)->Op;
@@ -10966,11 +10971,9 @@ HLSLExternalSource::DeduceTemplateArgumentsForHLSL(
1096610971 IsBABLoad = intrinsicOp == (UINT)IntrinsicOp::MOP_Load;
1096710972 IsBABStore = intrinsicOp == (UINT)IntrinsicOp::MOP_Store;
1096810973 }
10969- bool IsHitObjectGetAttributes =
10970- intrinsicOp == (UINT)IntrinsicOp::MOP_DxHitObject_GetAttributes;
1097110974 if (ExplicitTemplateArgs && ExplicitTemplateArgs->size() >= 1) {
1097210975 SourceLocation Loc = ExplicitTemplateArgs->getLAngleLoc();
10973- if (!IsBABLoad && !IsBABStore && !IsHitObjectGetAttributes ) {
10976+ if (!IsBABLoad && !IsBABStore) {
1097410977 getSema()->Diag(Loc, diag::err_hlsl_intrinsic_template_arg_unsupported)
1097510978 << intrinsicName;
1097610979 return Sema::TemplateDeductionResult::TDK_Invalid;
@@ -11000,10 +11003,6 @@ HLSLExternalSource::DeduceTemplateArgumentsForHLSL(
1100011003 return Sema::TemplateDeductionResult::TDK_Invalid;
1100111004 }
1100211005 }
11003- if (IsHitObjectGetAttributes &&
11004- !DiagnoseIntersectionAttributes(*getSema(), Loc,
11005- functionTemplateTypeArg))
11006- return Sema::TemplateDeductionResult::TDK_Invalid;
1100711006 } else if (IsBABStore) {
1100811007 // Prior to HLSL 2018, Store operation only stored scalar uint.
1100911008 if (!Is2018) {
@@ -12277,9 +12276,78 @@ static bool CheckVKBufferPointerCast(Sema &S, FunctionDecl *FD, CallExpr *CE,
1227712276}
1227812277#endif
1227912278
12279+ static bool isRelatedDeclMarkedNointerpolation(Expr *E) {
12280+ if (!E)
12281+ return false;
12282+ E = E->IgnoreCasts();
12283+ if (auto *DRE = dyn_cast<DeclRefExpr>(E))
12284+ return DRE->getDecl()->hasAttr<HLSLNoInterpolationAttr>();
12285+
12286+ if (auto *ME = dyn_cast<MemberExpr>(E))
12287+ return ME->getMemberDecl()->hasAttr<HLSLNoInterpolationAttr>() ||
12288+ isRelatedDeclMarkedNointerpolation(ME->getBase());
12289+
12290+ if (auto *HVE = dyn_cast<HLSLVectorElementExpr>(E))
12291+ return isRelatedDeclMarkedNointerpolation(HVE->getBase());
12292+
12293+ if (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
12294+ return isRelatedDeclMarkedNointerpolation(ASE->getBase());
12295+
12296+ return false;
12297+ }
12298+
12299+ static bool CheckIntrinsicGetAttributeAtVertex(Sema &S, FunctionDecl *FDecl,
12300+ CallExpr *TheCall) {
12301+ assert(TheCall->getNumArgs() > 0);
12302+ auto argument = TheCall->getArg(0)->IgnoreCasts();
12303+
12304+ if (!isRelatedDeclMarkedNointerpolation(argument)) {
12305+ S.Diag(argument->getExprLoc(), diag::err_hlsl_parameter_requires_attribute)
12306+ << 0 << FDecl->getName() << "nointerpolation";
12307+ return true;
12308+ }
12309+
12310+ return false;
12311+ }
12312+
12313+ static bool CheckNoInterpolationParams(Sema &S, FunctionDecl *FDecl,
12314+ CallExpr *TheCall) {
12315+ // See #hlsl-specs/issues/181. Feature is broken. For SPIR-V we want
12316+ // to limit the scope, and fail gracefully in some cases.
12317+ if (!S.getLangOpts().SPIRV)
12318+ return false;
12319+
12320+ bool error = false;
12321+ for (unsigned i = 0; i < FDecl->getNumParams(); i++) {
12322+ assert(i < TheCall->getNumArgs());
12323+
12324+ if (!FDecl->getParamDecl(i)->hasAttr<HLSLNoInterpolationAttr>())
12325+ continue;
12326+
12327+ if (!isRelatedDeclMarkedNointerpolation(TheCall->getArg(i))) {
12328+ S.Diag(TheCall->getArg(i)->getExprLoc(),
12329+ diag::err_hlsl_parameter_requires_attribute)
12330+ << i << FDecl->getName() << "nointerpolation";
12331+ error = true;
12332+ }
12333+ }
12334+
12335+ return error;
12336+ }
12337+
12338+ // Verify that user-defined intrinsic struct args contain no long vectors
12339+ static bool CheckUDTIntrinsicArg(Sema &S, Expr *Arg) {
12340+ const TypeDiagContext DiagContext =
12341+ TypeDiagContext::UserDefinedStructParameter;
12342+ return DiagnoseTypeElements(S, Arg->getExprLoc(), Arg->getType(), DiagContext,
12343+ DiagContext);
12344+ }
12345+
1228012346// Check HLSL call constraints, not fatal to creating the AST.
12281- void Sema::CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
12282- const FunctionProtoType *Proto) {
12347+ void Sema::CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
12348+ if (CheckNoInterpolationParams(*this, FDecl, TheCall))
12349+ return;
12350+
1228312351 HLSLIntrinsicAttr *IntrinsicAttr = FDecl->getAttr<HLSLIntrinsicAttr>();
1228412352 if (!IntrinsicAttr)
1228512353 return;
@@ -12307,6 +12375,28 @@ void Sema::CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
1230712375 case hlsl::IntrinsicOp::IOP___builtin_OuterProductAccumulate:
1230812376 CheckOuterProductAccumulateCall(*this, FDecl, TheCall);
1230912377 break;
12378+ case hlsl::IntrinsicOp::IOP_GetAttributeAtVertex:
12379+ // See #hlsl-specs/issues/181. Feature is broken. For SPIR-V we want
12380+ // to limit the scope, and fail gracefully in some cases.
12381+ if (!getLangOpts().SPIRV)
12382+ return;
12383+ CheckIntrinsicGetAttributeAtVertex(*this, FDecl, TheCall);
12384+ break;
12385+ case hlsl::IntrinsicOp::IOP_DispatchMesh:
12386+ CheckUDTIntrinsicArg(*this, TheCall->getArg(3)->IgnoreCasts());
12387+ break;
12388+ case hlsl::IntrinsicOp::IOP_CallShader:
12389+ CheckUDTIntrinsicArg(*this, TheCall->getArg(1)->IgnoreCasts());
12390+ break;
12391+ case hlsl::IntrinsicOp::IOP_TraceRay:
12392+ CheckUDTIntrinsicArg(*this, TheCall->getArg(7)->IgnoreCasts());
12393+ break;
12394+ case hlsl::IntrinsicOp::IOP_ReportHit:
12395+ CheckIntersectionAttributeArg(*this, TheCall->getArg(2)->IgnoreCasts());
12396+ break;
12397+ case hlsl::IntrinsicOp::MOP_DxHitObject_GetAttributes:
12398+ CheckIntersectionAttributeArg(*this, TheCall->getArg(0)->IgnoreCasts());
12399+ break;
1231012400#ifdef ENABLE_SPIRV_CODEGEN
1231112401 case hlsl::IntrinsicOp::IOP_Vkreinterpret_pointer_cast:
1231212402 CheckVKBufferPointerCast(*this, FDecl, TheCall, false);
@@ -16841,118 +16931,6 @@ QualType Sema::getHLSLDefaultSpecialization(TemplateDecl *Decl) {
1684116931 return QualType();
1684216932}
1684316933
16844- static bool isRelatedDeclMarkedNointerpolation(Expr *E) {
16845- if (!E)
16846- return false;
16847- E = E->IgnoreCasts();
16848- if (auto *DRE = dyn_cast<DeclRefExpr>(E))
16849- return DRE->getDecl()->hasAttr<HLSLNoInterpolationAttr>();
16850-
16851- if (auto *ME = dyn_cast<MemberExpr>(E))
16852- return ME->getMemberDecl()->hasAttr<HLSLNoInterpolationAttr>() ||
16853- isRelatedDeclMarkedNointerpolation(ME->getBase());
16854-
16855- if (auto *HVE = dyn_cast<HLSLVectorElementExpr>(E))
16856- return isRelatedDeclMarkedNointerpolation(HVE->getBase());
16857-
16858- if (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
16859- return isRelatedDeclMarkedNointerpolation(ASE->getBase());
16860-
16861- return false;
16862- }
16863-
16864- // Verify that user-defined intrinsic struct args contain no long vectors
16865- static bool CheckUDTIntrinsicArg(Sema *S, Expr *Arg) {
16866- const TypeDiagContext DiagContext =
16867- TypeDiagContext::UserDefinedStructParameter;
16868- return DiagnoseTypeElements(*S, Arg->getExprLoc(), Arg->getType(),
16869- DiagContext, DiagContext);
16870- }
16871-
16872- static bool CheckIntrinsicGetAttributeAtVertex(Sema *S, FunctionDecl *FDecl,
16873- CallExpr *TheCall) {
16874- assert(TheCall->getNumArgs() > 0);
16875- auto argument = TheCall->getArg(0)->IgnoreCasts();
16876-
16877- if (!isRelatedDeclMarkedNointerpolation(argument)) {
16878- S->Diag(argument->getExprLoc(), diag::err_hlsl_parameter_requires_attribute)
16879- << 0 << FDecl->getName() << "nointerpolation";
16880- return true;
16881- }
16882-
16883- return false;
16884- }
16885-
16886- bool Sema::CheckHLSLIntrinsicCall(FunctionDecl *FDecl, CallExpr *TheCall) {
16887- auto attr = FDecl->getAttr<HLSLIntrinsicAttr>();
16888-
16889- if (!attr)
16890- return false;
16891-
16892- if (!IsBuiltinTable(attr->getGroup()))
16893- return false;
16894-
16895- switch (hlsl::IntrinsicOp(attr->getOpcode())) {
16896- case hlsl::IntrinsicOp::IOP_GetAttributeAtVertex:
16897- // See #hlsl-specs/issues/181. Feature is broken. For SPIR-V we want
16898- // to limit the scope, and fail gracefully in some cases.
16899- if (!getLangOpts().SPIRV)
16900- return false;
16901- // This should never happen for SPIR-V. But on the DXIL side, extension can
16902- // be added by inserting new intrinsics, meaning opcodes can collide with
16903- // existing ones. See the ExtensionTest.EvalAttributeCollision test.
16904- assert(FDecl->getName() == "GetAttributeAtVertex");
16905- return CheckIntrinsicGetAttributeAtVertex(this, FDecl, TheCall);
16906- case hlsl::IntrinsicOp::IOP_DispatchMesh:
16907- assert(TheCall->getNumArgs() > 3);
16908- assert(FDecl->getName() == "DispatchMesh");
16909- return CheckUDTIntrinsicArg(this, TheCall->getArg(3)->IgnoreCasts());
16910- case hlsl::IntrinsicOp::IOP_CallShader:
16911- assert(TheCall->getNumArgs() > 1);
16912- assert(FDecl->getName() == "CallShader");
16913- return CheckUDTIntrinsicArg(this, TheCall->getArg(1)->IgnoreCasts());
16914- case hlsl::IntrinsicOp::IOP_TraceRay:
16915- assert(TheCall->getNumArgs() > 7);
16916- assert(FDecl->getName() == "TraceRay");
16917- return CheckUDTIntrinsicArg(this, TheCall->getArg(7)->IgnoreCasts());
16918- case hlsl::IntrinsicOp::IOP_ReportHit:
16919- assert(TheCall->getNumArgs() > 2);
16920- assert(FDecl->getName() == "ReportHit");
16921- return CheckUDTIntrinsicArg(this, TheCall->getArg(2)->IgnoreCasts());
16922- default:
16923- break;
16924- }
16925-
16926- return false;
16927- }
16928-
16929- bool Sema::CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
16930- if (hlsl::IsIntrinsicOp(FDecl) && CheckHLSLIntrinsicCall(FDecl, TheCall))
16931- return true;
16932-
16933- // See #hlsl-specs/issues/181. Feature is broken. For SPIR-V we want
16934- // to limit the scope, and fail gracefully in some cases.
16935- if (!getLangOpts().SPIRV)
16936- return false;
16937-
16938- bool error = false;
16939- for (unsigned i = 0; i < FDecl->getNumParams(); i++) {
16940- assert(i < TheCall->getNumArgs());
16941-
16942- if (!FDecl->getParamDecl(i)->hasAttr<HLSLNoInterpolationAttr>())
16943- continue;
16944-
16945- if (!isRelatedDeclMarkedNointerpolation(TheCall->getArg(i))) {
16946- Diag(TheCall->getArg(i)->getExprLoc(),
16947- diag::err_hlsl_parameter_requires_attribute)
16948- << i << FDecl->getName() << "nointerpolation";
16949- error = true;
16950- }
16951- }
16952-
16953- return error;
16954- }
16955-
1695616934namespace hlsl {
1695716935
1695816936static bool nodeInputIsCompatible(DXIL::NodeIOKind IOType,
0 commit comments