diff options
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 27 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-lookup.cpp | 3 | ||||
| -rw-r--r-- | source/slang/slang-lookup.h | 6 | ||||
| -rw-r--r-- | tests/bugs/keyword-undefined-identifier.slang | 35 | ||||
| -rw-r--r-- | tests/bugs/keyword-undefined-identifier.slang.expected | 7 |
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 = { +} |
