summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/slang-check-decl.cpp27
-rw-r--r--source/slang/slang-check-expr.cpp2
-rw-r--r--source/slang/slang-check-impl.h2
-rw-r--r--source/slang/slang-diagnostic-defs.h1
-rw-r--r--source/slang/slang-lookup.cpp3
-rw-r--r--source/slang/slang-lookup.h6
-rw-r--r--tests/bugs/keyword-undefined-identifier.slang35
-rw-r--r--tests/bugs/keyword-undefined-identifier.slang.expected7
8 files changed, 71 insertions, 12 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 027ddc70f..7c8322fa7 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -252,7 +252,8 @@ namespace Slang
SemanticsVisitor* sema,
DiagnosticSink* sink,
DeclRef<Decl> declRef,
- RefPtr<Type>* outTypeResult)
+ RefPtr<Type>* outTypeResult,
+ SourceLoc loc)
{
if( sema )
{
@@ -386,17 +387,30 @@ namespace Slang
}
if( sink )
{
- sink->diagnose(declRef, Diagnostics::unimplemented, "cannot form reference to this kind of declaration");
+ // The compiler is trying to form a reference to a declaration
+ // that doesn't appear to be usable as an expression or type.
+ //
+ // In practice, this arises when user code has an undefined-identifier
+ // error, but the name that was undefined in context also matches
+ // a contextual keyword. Rather than confuse the user with the
+ // details of contextual keywords in the compiler, we will diagnose
+ // this as an undefined identifier.
+ //
+ // TODO: This code could break if we ever go down this path with
+ // an identifier that doesn't have a name.
+ //
+ sink->diagnose(loc, Diagnostics::undefinedIdentifier2, declRef.GetName());
}
return QualType(session->getErrorType());
}
QualType getTypeForDeclRef(
Session* session,
- DeclRef<Decl> declRef)
+ DeclRef<Decl> declRef,
+ SourceLoc loc)
{
RefPtr<Type> typeResult;
- return getTypeForDeclRef(session, nullptr, nullptr, declRef, &typeResult);
+ return getTypeForDeclRef(session, nullptr, nullptr, declRef, &typeResult, loc);
}
DeclRef<ExtensionDecl> ApplyExtensionToType(
@@ -2832,7 +2846,7 @@ namespace Slang
return extDeclRef;
}
- QualType SemanticsVisitor::GetTypeForDeclRef(DeclRef<Decl> declRef)
+ QualType SemanticsVisitor::GetTypeForDeclRef(DeclRef<Decl> declRef, SourceLoc loc)
{
RefPtr<Type> typeResult;
return getTypeForDeclRef(
@@ -2840,7 +2854,8 @@ namespace Slang
this,
getSink(),
declRef,
- &typeResult);
+ &typeResult,
+ loc);
}
void SemanticsVisitor::importModuleIntoScope(Scope* scope, ModuleDecl* moduleDecl)
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index f1c1b9a43..e7db665ae 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -177,7 +177,7 @@ namespace Slang
{
// Compute the type that this declaration reference will have in context.
//
- auto type = GetTypeForDeclRef(declRef);
+ auto type = GetTypeForDeclRef(declRef, loc);
// Construct an appropriate expression based on the structured of
// the declaration reference.
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index 8cb691f4a..e4d49b1e6 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -1256,7 +1256,7 @@ namespace Slang
RefPtr<Expr> CheckInvokeExprWithCheckedOperands(InvokeExpr *expr);
// Get the type to use when referencing a declaration
- QualType GetTypeForDeclRef(DeclRef<Decl> declRef);
+ QualType GetTypeForDeclRef(DeclRef<Decl> declRef, SourceLoc loc);
//
//
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 6d0f01354..cc93ccc3b 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -228,7 +228,6 @@ DIAGNOSTIC(30012, Error, noApplicationUnaryOperator, "no overload found for oper
DIAGNOSTIC(30012, Error, noOverloadFoundForBinOperatorOnTypes, "no overload found for operator $0 ($1, $2).")
DIAGNOSTIC(30013, Error, subscriptNonArray, "no subscript operation found for type '$0'")
DIAGNOSTIC(30014, Error, subscriptIndexNonInteger, "index expression must evaluate to int.")
-DIAGNOSTIC(30015, Error, undefinedIdentifier, "'$0': undefined identifier.")
DIAGNOSTIC(30015, Error, undefinedIdentifier2, "undefined identifier '$0'.")
DIAGNOSTIC(30017, Error, componentNotAccessibleFromShader, "component '$0' is not accessible from shader '$1'.")
DIAGNOSTIC(30019, Error, typeMismatch, "expected an expression of type '$0', got '$1'")
diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp
index 2a99d8e53..e860d91d1 100644
--- a/source/slang/slang-lookup.cpp
+++ b/source/slang/slang-lookup.cpp
@@ -223,7 +223,8 @@ void DoMemberLookupImpl(
{
auto baseType = getTypeForDeclRef(
session,
- baseDeclRef);
+ baseDeclRef,
+ SourceLoc());
return DoMemberLookupImpl(
session,
name, baseType, request, ioResult, breadcrumbs);
diff --git a/source/slang/slang-lookup.h b/source/slang/slang-lookup.h
index d1675015d..eaf51f1e5 100644
--- a/source/slang/slang-lookup.h
+++ b/source/slang/slang-lookup.h
@@ -48,11 +48,13 @@ QualType getTypeForDeclRef(
SemanticsVisitor* sema,
DiagnosticSink* sink,
DeclRef<Decl> declRef,
- RefPtr<Type>* outTypeResult);
+ RefPtr<Type>* outTypeResult,
+ SourceLoc loc);
QualType getTypeForDeclRef(
Session* session,
- DeclRef<Decl> declRef);
+ DeclRef<Decl> declRef,
+ SourceLoc loc);
/// Add a found item to a lookup result
void AddToLookupResult(
diff --git a/tests/bugs/keyword-undefined-identifier.slang b/tests/bugs/keyword-undefined-identifier.slang
new file mode 100644
index 000000000..e1f46f517
--- /dev/null
+++ b/tests/bugs/keyword-undefined-identifier.slang
@@ -0,0 +1,35 @@
+// keyword-undeclared-identifier.slang
+
+//DIAGNOSTIC_TEST:SIMPLE:
+
+// Test that using a contextual keyword in
+// a context where it is an underfined
+// identifier produces a reasonable error
+// message instead of an internal compiler error
+//
+// Note that HLSL has keywords with very
+// common names like `triangle` and `sample`,
+// so it is easy for those to collide with
+// local variable names.
+//
+// Slang decides to make almost all keywords
+// contextual, so that they are looked up
+// in lexical scope and can be shadowed by
+// user-defined variables or functions.
+//
+// The problem in this case is that code
+// could easily be refactored so that it
+// uses one of the contextual keywrods in
+// a place where it is no longer shadowed,
+// but contextually needs to be treated
+// as an expression.
+
+int instanceTest()
+{
+ return instance;
+}
+
+int triangleTest()
+{
+ return triangle;
+}
diff --git a/tests/bugs/keyword-undefined-identifier.slang.expected b/tests/bugs/keyword-undefined-identifier.slang.expected
new file mode 100644
index 000000000..00c9fe8db
--- /dev/null
+++ b/tests/bugs/keyword-undefined-identifier.slang.expected
@@ -0,0 +1,7 @@
+result code = -1
+standard error = {
+tests/bugs/keyword-undefined-identifier.slang(29): error 30015: undefined identifier 'instance'.
+tests/bugs/keyword-undefined-identifier.slang(34): error 30015: undefined identifier 'triangle'.
+}
+standard output = {
+}