Skip to content

Commit 162bf4e

Browse files
authored
Fix intrinsic lookup with namespaces (#7599)
This change fixes issues with intrinsic lookup caused by not correctly respecting the using declaration(s) that impact unqualified lookups. This probably isn't a perfect solution because I'm sure there's some nuance of unqualified lookups in C++ that I'm not handling, but this does respect scoped using directives and allows us to get things working. Additionally this change disables emitting some "declared here" notes when the source location referred to is invalid. Fixes #7495
1 parent 68dedee commit 162bf4e

File tree

10 files changed

+247
-84
lines changed

10 files changed

+247
-84
lines changed

tools/clang/include/clang/Sema/ExternalSemaSource.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,9 @@ class ExternalSemaSource : public ExternalASTSource {
211211
// add call candidates to the given expression. It returns 'true'
212212
// if standard overload search should be suppressed; false otherwise.
213213
virtual bool AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
214-
ArrayRef<Expr *> Args,
215-
OverloadCandidateSet &CandidateSet,
216-
bool PartialOverloading)
217-
{
214+
ArrayRef<Expr *> Args,
215+
OverloadCandidateSet &CandidateSet,
216+
Scope *S, bool PartialOverloading) {
218217
return false;
219218
}
220219

tools/clang/include/clang/Sema/Sema.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2495,9 +2495,14 @@ class Sema {
24952495
DeclAccessPair FoundDecl,
24962496
FunctionDecl *Fn);
24972497

2498+
// HLSL Change Begin
2499+
void CollectNamespaceContexts(Scope *,
2500+
SmallVectorImpl<const DeclContext *> &);
2501+
// HLSL Change End
24982502
void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
24992503
ArrayRef<Expr *> Args,
25002504
OverloadCandidateSet &CandidateSet,
2505+
Scope *S, // HLSL Change
25012506
bool PartialOverloading = false);
25022507

25032508
// An enum used to represent the different possible results of building a

tools/clang/lib/Sema/SemaCodeComplete.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4020,7 +4020,7 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args) {
40204020

40214021
Expr *NakedFn = Fn->IgnoreParenCasts();
40224022
if (auto ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn))
4023-
AddOverloadedCallCandidates(ULE, Args, CandidateSet,
4023+
AddOverloadedCallCandidates(ULE, Args, CandidateSet, S, // HLSL Change
40244024
/*PartialOverloading=*/true);
40254025
else if (auto UME = dyn_cast<UnresolvedMemberExpr>(NakedFn)) {
40264026
TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;

tools/clang/lib/Sema/SemaHLSL.cpp

Lines changed: 99 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -4152,6 +4152,7 @@ class HLSLExternalSource : public ExternalSemaSource {
41524152
SourceLocation(), &context.Idents.get("dx"),
41534153
/*PrevDecl*/ nullptr);
41544154
m_dxNSDecl->setImplicit();
4155+
m_dxNSDecl->setHasExternalLexicalStorage(true);
41554156
context.getTranslationUnitDecl()->addDecl(m_dxNSDecl);
41564157

41574158
#ifdef ENABLE_SPIRV_CODEGEN
@@ -5169,7 +5170,7 @@ class HLSLExternalSource : public ExternalSemaSource {
51695170

51705171
bool AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
51715172
ArrayRef<Expr *> Args,
5172-
OverloadCandidateSet &CandidateSet,
5173+
OverloadCandidateSet &CandidateSet, Scope *S,
51735174
bool PartialOverloading) override {
51745175
DXASSERT_NOMSG(ULE != nullptr);
51755176

@@ -5194,6 +5195,8 @@ class HLSLExternalSource : public ExternalSemaSource {
51945195
// Exceptions:
51955196
// - Vulkan-specific intrinsics live in the 'vk::' namespace.
51965197
// - DirectX-specific intrinsics live in the 'dx::' namespace.
5198+
// - Global namespaces could just mean we have a `using` declaration... so
5199+
// it can be anywhere!
51975200
if (isQualified && !isGlobalNamespace && !isVkNamespace && !isDxNamespace)
51985201
return false;
51995202

@@ -5204,81 +5207,106 @@ class HLSLExternalSource : public ExternalSemaSource {
52045207
}
52055208

52065209
StringRef nameIdentifier = idInfo->getName();
5207-
const HLSL_INTRINSIC *table = g_Intrinsics;
5208-
auto tableCount = _countof(g_Intrinsics);
5209-
if (isDxNamespace) {
5210-
table = g_DxIntrinsics;
5211-
tableCount = _countof(g_DxIntrinsics);
5210+
using IntrinsicArray = llvm::ArrayRef<const HLSL_INTRINSIC>;
5211+
struct IntrinsicTableEntry {
5212+
IntrinsicArray Table;
5213+
NamespaceDecl *NS;
5214+
};
5215+
5216+
llvm::SmallVector<IntrinsicTableEntry, 3> SearchTables;
5217+
5218+
bool SearchDX = isDxNamespace;
5219+
bool SearchVK = isVkNamespace;
5220+
if (isGlobalNamespace || !isQualified)
5221+
SearchTables.push_back(
5222+
IntrinsicTableEntry{IntrinsicArray(g_Intrinsics), m_hlslNSDecl});
5223+
5224+
if (S && !isQualified) {
5225+
SmallVector<const DeclContext *, 4> NSContexts;
5226+
m_sema->CollectNamespaceContexts(S, NSContexts);
5227+
for (const auto &UD : NSContexts) {
5228+
if (static_cast<DeclContext *>(m_dxNSDecl) == UD)
5229+
SearchDX = true;
5230+
else if (static_cast<DeclContext *>(m_vkNSDecl) == UD)
5231+
SearchVK = true;
5232+
}
52125233
}
5234+
5235+
if (SearchDX)
5236+
SearchTables.push_back(
5237+
IntrinsicTableEntry{IntrinsicArray(g_DxIntrinsics), m_dxNSDecl});
52135238
#ifdef ENABLE_SPIRV_CODEGEN
5214-
if (isVkNamespace) {
5215-
table = g_VkIntrinsics;
5216-
tableCount = _countof(g_VkIntrinsics);
5217-
}
5218-
#endif // ENABLE_SPIRV_CODEGEN
5239+
if (SearchVK)
5240+
SearchTables.push_back(
5241+
IntrinsicTableEntry{IntrinsicArray(g_VkIntrinsics), m_vkNSDecl});
5242+
#endif
52195243

5220-
IntrinsicDefIter cursor = FindIntrinsicByNameAndArgCount(
5221-
table, tableCount, StringRef(), nameIdentifier, Args.size());
5222-
IntrinsicDefIter end = IntrinsicDefIter::CreateEnd(
5223-
table, tableCount, IntrinsicTableDefIter::CreateEnd(m_intrinsicTables));
5224-
5225-
for (; cursor != end; ++cursor) {
5226-
// If this is the intrinsic we're interested in, build up a representation
5227-
// of the types we need.
5228-
const HLSL_INTRINSIC *pIntrinsic = *cursor;
5229-
LPCSTR tableName = cursor.GetTableName();
5230-
LPCSTR lowering = cursor.GetLoweringStrategy();
5231-
DXASSERT(pIntrinsic->uNumArgs <= g_MaxIntrinsicParamCount + 1,
5232-
"otherwise g_MaxIntrinsicParamCount needs to be updated for "
5233-
"wider signatures");
5234-
5235-
std::vector<QualType> functionArgTypes;
5236-
size_t badArgIdx;
5237-
bool argsMatch =
5238-
MatchArguments(cursor, QualType(), QualType(), QualType(), Args,
5239-
&functionArgTypes, badArgIdx);
5240-
if (!functionArgTypes.size())
5241-
return false;
5244+
assert(!SearchTables.empty() && "Must have at least one search table!");
5245+
5246+
for (const auto &T : SearchTables) {
5247+
5248+
IntrinsicDefIter cursor = FindIntrinsicByNameAndArgCount(
5249+
T.Table.data(), T.Table.size(), StringRef(), nameIdentifier,
5250+
Args.size());
5251+
IntrinsicDefIter end = IntrinsicDefIter::CreateEnd(
5252+
T.Table.data(), T.Table.size(),
5253+
IntrinsicTableDefIter::CreateEnd(m_intrinsicTables));
5254+
5255+
for (; cursor != end; ++cursor) {
5256+
// If this is the intrinsic we're interested in, build up a
5257+
// representation of the types we need.
5258+
const HLSL_INTRINSIC *pIntrinsic = *cursor;
5259+
LPCSTR tableName = cursor.GetTableName();
5260+
LPCSTR lowering = cursor.GetLoweringStrategy();
5261+
DXASSERT(pIntrinsic->uNumArgs <= g_MaxIntrinsicParamCount + 1,
5262+
"otherwise g_MaxIntrinsicParamCount needs to be updated for "
5263+
"wider signatures");
5264+
5265+
std::vector<QualType> functionArgTypes;
5266+
size_t badArgIdx;
5267+
bool argsMatch =
5268+
MatchArguments(cursor, QualType(), QualType(), QualType(), Args,
5269+
&functionArgTypes, badArgIdx);
5270+
if (!functionArgTypes.size())
5271+
return false;
52425272

5243-
// Get or create the overload we're interested in.
5244-
FunctionDecl *intrinsicFuncDecl = nullptr;
5245-
std::pair<UsedIntrinsicStore::iterator, bool> insertResult =
5246-
m_usedIntrinsics.insert(UsedIntrinsic(pIntrinsic, functionArgTypes));
5247-
bool insertedNewValue = insertResult.second;
5248-
if (insertedNewValue) {
5249-
NamespaceDecl *nsDecl = m_hlslNSDecl;
5250-
if (isVkNamespace)
5251-
nsDecl = m_vkNSDecl;
5252-
else if (isDxNamespace)
5253-
nsDecl = m_dxNSDecl;
5254-
DXASSERT(tableName,
5255-
"otherwise IDxcIntrinsicTable::GetTableName() failed");
5256-
intrinsicFuncDecl =
5257-
AddHLSLIntrinsicFunction(*m_context, nsDecl, tableName, lowering,
5258-
pIntrinsic, &functionArgTypes);
5259-
insertResult.first->setFunctionDecl(intrinsicFuncDecl);
5260-
} else {
5261-
intrinsicFuncDecl = (*insertResult.first).getFunctionDecl();
5262-
}
5273+
// Get or create the overload we're interested in.
5274+
FunctionDecl *intrinsicFuncDecl = nullptr;
5275+
std::pair<UsedIntrinsicStore::iterator, bool> insertResult =
5276+
m_usedIntrinsics.insert(
5277+
UsedIntrinsic(pIntrinsic, functionArgTypes));
5278+
bool insertedNewValue = insertResult.second;
5279+
if (insertedNewValue) {
5280+
DXASSERT(tableName,
5281+
"otherwise IDxcIntrinsicTable::GetTableName() failed");
5282+
intrinsicFuncDecl =
5283+
AddHLSLIntrinsicFunction(*m_context, T.NS, tableName, lowering,
5284+
pIntrinsic, &functionArgTypes);
5285+
insertResult.first->setFunctionDecl(intrinsicFuncDecl);
5286+
} else {
5287+
intrinsicFuncDecl = (*insertResult.first).getFunctionDecl();
5288+
}
52635289

5264-
OverloadCandidate &candidate = CandidateSet.addCandidate(Args.size());
5265-
candidate.Function = intrinsicFuncDecl;
5266-
candidate.FoundDecl.setDecl(intrinsicFuncDecl);
5267-
candidate.Viable = argsMatch;
5268-
CandidateSet.isNewCandidate(intrinsicFuncDecl); // used to insert into set
5269-
if (argsMatch)
5270-
return true;
5271-
if (badArgIdx) {
5272-
candidate.FailureKind = ovl_fail_bad_conversion;
5273-
QualType ParamType =
5274-
intrinsicFuncDecl->getParamDecl(badArgIdx - 1)->getType();
5275-
candidate.Conversions[badArgIdx - 1].setBad(
5276-
BadConversionSequence::no_conversion, Args[badArgIdx - 1],
5277-
ParamType);
5278-
} else {
5279-
// A less informative error. Needed when the failure relates to the
5280-
// return type
5281-
candidate.FailureKind = ovl_fail_bad_final_conversion;
5290+
OverloadCandidate &candidate = CandidateSet.addCandidate(Args.size());
5291+
candidate.Function = intrinsicFuncDecl;
5292+
candidate.FoundDecl.setDecl(intrinsicFuncDecl);
5293+
candidate.Viable = argsMatch;
5294+
CandidateSet.isNewCandidate(
5295+
intrinsicFuncDecl); // used to insert into set
5296+
if (argsMatch)
5297+
return true;
5298+
if (badArgIdx) {
5299+
candidate.FailureKind = ovl_fail_bad_conversion;
5300+
QualType ParamType =
5301+
intrinsicFuncDecl->getParamDecl(badArgIdx - 1)->getType();
5302+
candidate.Conversions[badArgIdx - 1].setBad(
5303+
BadConversionSequence::no_conversion, Args[badArgIdx - 1],
5304+
ParamType);
5305+
} else {
5306+
// A less informative error. Needed when the failure relates to the
5307+
// return type
5308+
candidate.FailureKind = ovl_fail_bad_final_conversion;
5309+
}
52825310
}
52835311
}
52845312

tools/clang/lib/Sema/SemaLookup.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
using namespace clang;
5656
using namespace sema;
5757

58+
// HLSL Note: This set of utilities copied to SemaHLSL.cpp.
5859
namespace {
5960
class UnqualUsingEntry {
6061
const DeclContext *Nominated;
@@ -4809,9 +4810,12 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction,
48094810

48104811
NamedDecl *ChosenDecl =
48114812
Correction.isKeyword() ? nullptr : Correction.getCorrectionDecl();
4812-
if (PrevNote.getDiagID() && ChosenDecl)
4813+
// HLSL Change begin: don't put notes on invalid source locations.
4814+
if (PrevNote.getDiagID() && ChosenDecl &&
4815+
!ChosenDecl->getLocation().isInvalid())
48134816
Diag(ChosenDecl->getLocation(), PrevNote)
48144817
<< CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo);
4818+
// HLSL Change end
48154819
}
48164820

48174821
TypoExpr *Sema::createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC,
@@ -4836,3 +4840,33 @@ const Sema::TypoExprState &Sema::getTypoExprState(TypoExpr *TE) const {
48364840
void Sema::clearDelayedTypo(TypoExpr *TE) {
48374841
DelayedTypos.erase(TE);
48384842
}
4843+
4844+
// HLSL Change Begin
4845+
void Sema::CollectNamespaceContexts(Scope *S,
4846+
SmallVectorImpl<const DeclContext *> &NSs) {
4847+
UnqualUsingDirectiveSet UDirs;
4848+
4849+
// Add using directives from this context up to the top level. This
4850+
// handles cases where the current declaration is in a context that has
4851+
// a using directive but might be in a scope chain that doesn't reach
4852+
// the using directive (i.e. a using inside a namespace or class
4853+
// declaration but the function definition is outside).
4854+
DeclContext *Ctx = S->getEntity();
4855+
for (DeclContext *UCtx = Ctx; UCtx; UCtx = UCtx->getParent()) {
4856+
if (UCtx->isTransparentContext())
4857+
continue;
4858+
4859+
UDirs.visit(UCtx, UCtx);
4860+
}
4861+
// Find the first namespace or translation-unit scope.
4862+
Scope *Innermost = S;
4863+
while (Innermost && !isNamespaceOrTranslationUnitScope(Innermost))
4864+
Innermost = Innermost->getParent();
4865+
4866+
UDirs.visitScopeChain(S, Innermost);
4867+
UDirs.done();
4868+
4869+
for (auto &UD : UDirs)
4870+
NSs.push_back(UD.getNominatedNamespace());
4871+
}
4872+
// HLSL Change End

tools/clang/lib/Sema/SemaOverload.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10627,6 +10627,7 @@ static void AddOverloadedCallCandidate(Sema &S,
1062710627
void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
1062810628
ArrayRef<Expr *> Args,
1062910629
OverloadCandidateSet &CandidateSet,
10630+
Scope *S, // HLSL Change
1063010631
bool PartialOverloading) {
1063110632

1063210633
#ifndef NDEBUG
@@ -10659,8 +10660,8 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
1065910660
#endif
1066010661

1066110662
// HLSL Change - allow ExternalSource the ability to add the overloads for a call.
10662-
if (ExternalSource &&
10663-
ExternalSource->AddOverloadedCallCandidates(ULE, Args, CandidateSet, PartialOverloading)) {
10663+
if (ExternalSource && ExternalSource->AddOverloadedCallCandidates(
10664+
ULE, Args, CandidateSet, S, PartialOverloading)) {
1066410665
return;
1066510666
}
1066610667

@@ -10970,7 +10971,7 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
1097010971

1097110972
// Add the functions denoted by the callee to the set of candidate
1097210973
// functions, including those from argument-dependent lookup.
10973-
AddOverloadedCallCandidates(ULE, Args, *CandidateSet);
10974+
AddOverloadedCallCandidates(ULE, Args, *CandidateSet, S); // HLSL Change
1097410975

1097510976
if (getLangOpts().MSVCCompat &&
1097610977
CurContext->isDependentContext() && !isSFINAEContext() &&

tools/clang/test/SemaHLSL/effects-syntax.hlsl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,10 @@ static const PixelShader ps1 { state=foo; }; /* expected-warning
108108
/*verify-ast
109109
No matching AST found for line!
110110
*/
111-
// expected-note@? {{'PixelShader' declared here}}
112111
PixelShadeR ps < int foo=1;> = ps1; // Case insensitive! /* expected-error {{unknown type name 'PixelShadeR'; did you mean 'PixelShader'?}} expected-warning {{effect object ignored - effect syntax is deprecated}} expected-warning {{possible effect annotation ignored - effect syntax is deprecated}} fxc-pass {{}} */
113112
/*verify-ast
114113
No matching AST found for line!
115114
*/
116-
// expected-note@? {{'VertexShader' declared here}}
117115
VertexShadeR vs; // Case insensitive! /* expected-error {{unknown type name 'VertexShadeR'; did you mean 'VertexShader'?}} expected-warning {{effect object ignored - effect syntax is deprecated}} fxc-pass {{}} */
118116

119117
// Case sensitive

tools/clang/test/SemaHLSL/raytracings.hlsl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ void run() {
1212
RAY_FLAG_CULL_OPAQUE +
1313
RAY_FLAG_CULL_NON_OPAQUE;
1414

15-
rayFlags += RAY_FLAG_INVALID; /* expected-note@? {{'RAY_FLAG_NONE' declared here}} expected-error {{use of undeclared identifier 'RAY_FLAG_INVALID'; did you mean 'RAY_FLAG_NONE'?}} */
15+
rayFlags += RAY_FLAG_INVALID; /* expected-error {{use of undeclared identifier 'RAY_FLAG_INVALID'; did you mean 'RAY_FLAG_NONE'?}} */
1616

1717
int intFlag = RAY_FLAG_CULL_OPAQUE;
1818

1919
int hitKindFlag =
2020
HIT_KIND_TRIANGLE_FRONT_FACE + HIT_KIND_TRIANGLE_BACK_FACE;
2121

22-
hitKindFlag += HIT_KIND_INVALID; /* expected-note@? {{'HIT_KIND_NONE' declared here}} expected-error {{use of undeclared identifier 'HIT_KIND_INVALID'; did you mean 'HIT_KIND_NONE'?}} */
22+
hitKindFlag += HIT_KIND_INVALID; /* expected-error {{use of undeclared identifier 'HIT_KIND_INVALID'; did you mean 'HIT_KIND_NONE'?}} */
2323

2424

2525
BuiltInTriangleIntersectionAttributes attr;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %dxc -T lib_6_9 %s -verify
2+
3+
RaytracingAccelerationStructure Scene : register(t0, space0);
4+
5+
struct[raypayload] RayPayload {
6+
float4 color : write(caller) : read(closesthit);
7+
};
8+
9+
[shader("raygeneration")] void MyRaygenShader() {
10+
// Set the ray's extents.
11+
RayDesc ray;
12+
ray.Origin = float3(0, 0, 1);
13+
ray.Direction = float3(1, 0, 0);
14+
ray.TMin = 0.001;
15+
ray.TMax = 10000.0;
16+
17+
RayPayload payload = {float4(0, 0, 0, 0)};
18+
19+
{
20+
using namespace dx;
21+
HitObject hit =
22+
HitObject::TraceRay(Scene, RAY_FLAG_NONE, ~0, 0, 1, 0,
23+
ray, payload);
24+
25+
int sortKey = 1;
26+
MaybeReorderThread(sortKey, 1);
27+
}
28+
29+
{
30+
int sortKey = 1;
31+
MaybeReorderThread(sortKey, 1); // expected-error{{use of undeclared identifier 'MaybeReorderThread'; did you mean 'MaybeReorderThread'?}}
32+
}
33+
34+
int sortKey = 1;
35+
MaybeReorderThread(sortKey, 1); // expected-error{{use of undeclared identifier 'MaybeReorderThread'; did you mean 'MaybeReorderThread'?}}
36+
37+
HitObject hit = // expected-error{{unknown type name 'HitObject'}}
38+
HitObject::TraceRay(Scene, RAY_FLAG_NONE, ~0, 0, 1, 0,
39+
ray, payload);
40+
41+
HitObject::Invoke(hit, payload); // expected-error{{use of undeclared identifier 'HitObject'}}
42+
}

0 commit comments

Comments
 (0)