summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/check.cpp16
-rw-r--r--source/slang/diagnostic-defs.h14
-rw-r--r--source/slang/preprocessor.cpp105
3 files changed, 123 insertions, 12 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp
index 95a958495..42bcfe4b5 100644
--- a/source/slang/check.cpp
+++ b/source/slang/check.cpp
@@ -1876,7 +1876,7 @@ namespace Slang
}
return true;
}
-
+
bool validateAttribute(RefPtr<Attribute> attr)
{
if(auto numThreadsAttr = attr.As<NumThreadsAttribute>())
@@ -1939,7 +1939,7 @@ namespace Slang
entryPointAttr->stage = stage;
}
- else if ((attr.As<DomainAttribute>()) ||
+ else if ((attr.As<DomainAttribute>()) ||
(attr.As<MaxTessFactorAttribute>()) ||
(attr.As<OutputTopologyAttribute>()) ||
(attr.As<PartitioningAttribute>()) ||
@@ -1964,7 +1964,7 @@ namespace Slang
// Has no args
SLANG_ASSERT(attr->args.Count() == 0);
}
- else
+ else
{
if(attr->args.Count() == 0)
{
@@ -3639,8 +3639,9 @@ namespace Slang
auto prevResultType = GetResultType(prevFuncDeclRef);
if (!resultType->Equals(prevResultType))
{
- // Bad dedeclaration
- getSink()->diagnose(funcDecl, Diagnostics::unimplemented, "redeclaration has a different return type");
+ // Bad redeclaration
+ getSink()->diagnose(funcDecl, Diagnostics::functionRedeclarationWithDifferentReturnType, funcDecl->getName(), resultType, prevResultType);
+ getSink()->diagnose(prevFuncDecl, Diagnostics::seePreviousDeclarationOf, funcDecl->getName());
// Don't bother emitting other errors at this point
break;
@@ -3671,7 +3672,8 @@ namespace Slang
if (funcDecl->Body && prevFuncDecl->Body)
{
// Redefinition
- getSink()->diagnose(funcDecl, Diagnostics::unimplemented, "function redefinition");
+ getSink()->diagnose(funcDecl, Diagnostics::functionRedefinition, funcDecl->getName());
+ getSink()->diagnose(prevFuncDecl, Diagnostics::seePreviousDefinitionOf, funcDecl->getName());
// Don't bother emitting other errors
break;
@@ -8379,7 +8381,7 @@ namespace Slang
// TODO: We currently do minimal checking here, but this is the
// right place to perform the following validation checks:
//
-
+
// * Are the function input/output parameters and result type
// all valid for the chosen stage? (e.g., there shouldn't be
// an `OutputStream<X>` type in a vertex shader signature)
diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h
index fd836e946..c0c74c78e 100644
--- a/source/slang/diagnostic-defs.h
+++ b/source/slang/diagnostic-defs.h
@@ -42,6 +42,7 @@ DIAGNOSTIC(-1, Note, doYouForgetToMakeComponentAccessible, "do you forget to mak
DIAGNOSTIC(-1, Note, seeDeclarationOf, "see declaration of '$0'")
DIAGNOSTIC(-1, Note, seeOtherDeclarationOf, "see other declaration of '$0'")
+DIAGNOSTIC(-1, Note, seePreviousDeclarationOf, "see previous declaration of '$0'")
//
// 0xxxx - Command line and interaction with host platform APIs.
@@ -67,7 +68,7 @@ DIAGNOSTIC( 12, Error, cannotDeduceSourceLanguage, "can't deduce language for
DIAGNOSTIC( 13, Error, unknownCodeGenerationTarget, "unknown code generation target '$0'");
DIAGNOSTIC( 14, Error, unknownProfile, "unknown profile '$0'");
DIAGNOSTIC( 15, Error, unknownStage, "unknown stage '$0'");
-DIAGNOSTIC( 16, Error, unknownPassThroughTarget, "unknown pass-through target '$0'");
+DIAGNOSTIC( 16, Error, unknownPassThroughTarget, "unknown pass-through target '$0'");
DIAGNOSTIC( 17, Error, unknownCommandLineOption, "unknown command-line option '$0'");
DIAGNOSTIC( 18, Error, noProfileSpecified, "no profile specified; use the '-profile <profile name>' option");
DIAGNOSTIC( 19, Error, multipleEntryPointsNeedMulitpleProfiles, "when multiple entry points are specified, each must have a profile given (with '-profile') before the '-entry' option");
@@ -130,6 +131,10 @@ DIAGNOSTIC(15403, Error, expectedTokenInMacroParameters, "expected '$0' in macro
DIAGNOSTIC(15500, Warning, expectedTokenInMacroArguments, "expected '$0' in macro invocation")
DIAGNOSTIC(15501, Error, wrongNumberOfArgumentsToMacro, "wrong number of arguments to macro (expected $0, got $1)")
+// 156xx - pragmas
+DIAGNOSTIC(15600, Error, expectedPragmaDirectiveName, "expected a name after '#pragma'")
+DIAGNOSTIC(15601, Warning, unknownPragmaDirectiveIgnored, "ignoring unknown directive '#pragma $0'")
+
// 159xx - user-defined error/warning
DIAGNOSTIC(15900, Error, userDefinedError, "#error: $0")
DIAGNOSTIC(15901, Warning, userDefinedWarning, "#warning: $0")
@@ -160,7 +165,6 @@ DIAGNOSTIC(20011, Error, unexpectedColon, "unexpected ':'.")
// 3xxxx - Semantic analysis
//
-DIAGNOSTIC(30001, Error, functionRedefinitionWithArgList, "'$0$1': function redefinition.")
DIAGNOSTIC(30002, Error, parameterAlreadyDefined, "parameter '$0' already defined.")
DIAGNOSTIC(30003, Error, breakOutsideLoop, "'break' must appear inside loop constructs.")
DIAGNOSTIC(30004, Error, continueOutsideLoop, "'continue' must appear inside loop constructs.")
@@ -203,9 +207,15 @@ DIAGNOSTIC(30052, Error, invalidSwizzleExpr, "invalid swizzle pattern '$0' on ty
DIAGNOSTIC(30100, Error, staticRefToNonStaticMember, "type '$0' cannot be used to refer to non-static member '$1'")
+DIAGNOSTIC(30201, Error, functionRedefinition, "function '$0' already has a body")
+DIAGNOSTIC(30202, Error, functionRedeclarationWithDifferentReturnType, "function '$0' declared to return '$1' was previously declared to return '$2'")
+
+
DIAGNOSTIC(33070, Error, expectedFunction, "expression preceding parenthesis of apparent call must have function type.")
DIAGNOSTIC(33071, Error, expectedAStringLiteral, "expected a string literal")
+
+
// Attributes
DIAGNOSTIC(31000, Error, unknownAttributeName, "unknown attribute '$0'")
DIAGNOSTIC(31001, Error, attributeArgumentCountMismatch, "attribute '$0' expects $1 arguments ($2 provided)")
diff --git a/source/slang/preprocessor.cpp b/source/slang/preprocessor.cpp
index 3ec44fc28..71c6fd4bb 100644
--- a/source/slang/preprocessor.cpp
+++ b/source/slang/preprocessor.cpp
@@ -197,6 +197,11 @@ struct Preprocessor
// The translation unit that is being parsed
TranslationUnitRequest* translationUnit;
+ // Any paths that have issued `#pragma once` directives to
+ // stop them from being included again.
+ HashSet<String> pragmaOncePaths;
+
+
TranslationUnitRequest* getTranslationUnit()
{
return translationUnit;
@@ -1608,6 +1613,12 @@ static void HandleIncludeDirective(PreprocessorDirectiveContext* context)
// a switch of input stream
expectEndOfDirective(context);
+ // Check whether we've previously included this file and seen a `#pragma once` directive
+ if(context->preprocessor->pragmaOncePaths.Contains(foundPath))
+ {
+ return;
+ }
+
// Push the new file onto our stack of input streams
// TODO(tfoley): check if we have made our include stack too deep
@@ -1818,12 +1829,100 @@ static void HandleLineDirective(PreprocessorDirectiveContext* context)
inputStream->primaryStream->lexer.startOverridingSourceLocations(newLoc);
}
+#define SLANG_PRAGMA_DIRECTIVE_CALLBACK(NAME) \
+ void NAME(PreprocessorDirectiveContext* context, Token subDirectiveToken)
+
+// Callback interface used by `#pragma` directives
+typedef SLANG_PRAGMA_DIRECTIVE_CALLBACK((*PragmaDirectiveCallback));
+
+SLANG_PRAGMA_DIRECTIVE_CALLBACK(handleUnknownPragmaDirective)
+{
+ GetSink(context)->diagnose(subDirectiveToken, Diagnostics::unknownPragmaDirectiveIgnored, subDirectiveToken.getName());
+ SkipToEndOfLine(context);
+ return;
+}
+
+SLANG_PRAGMA_DIRECTIVE_CALLBACK(handlePragmaOnceDirective)
+{
+ // We need to identify the path of the file we are preprocessing,
+ // so that we can avoid including it again.
+ //
+ // Note: for now we are doing a very simplistic check where
+ // we use the raw file path as the key for our duplicate checking.
+ //
+ // TODO: a more refined implementation should probably apply Unicode
+ // normalization and case-folding to the path, and then use that
+ // plus a hash of the file contents to determine whether things
+ // represent the "same" file.
+ //
+ // TODO: even for our simplistic implementation, we need to add
+ // logic to deal with `../` segments in path names to detect
+ // trivial cases of the "same" path.
+ //
+ auto directiveLoc = GetDirectiveLoc(context);
+ auto expandedDirectiveLoc = context->preprocessor->translationUnit->compileRequest->getSourceManager()->expandSourceLoc(directiveLoc);
+ String pathIssuedFrom = expandedDirectiveLoc.getSpellingPath();
+
+ context->preprocessor->pragmaOncePaths.Add(pathIssuedFrom);
+}
+
+// Information about a specific `#pragma` directive
+struct PragmaDirective
+{
+ // name of the directive
+ char const* name;
+
+ // Callback to handle the directive
+ PragmaDirectiveCallback callback;
+};
+
+// A simple array of all the `#pragma` directives we know how to handle.
+static const PragmaDirective kPragmaDirectives[] =
+{
+ { "once", &handlePragmaOnceDirective },
+
+ { NULL, NULL },
+};
+
+static const PragmaDirective kUnknownPragmaDirective = {
+ NULL, &handleUnknownPragmaDirective,
+};
+
+// Look up the `#pragma` directive with the given name.
+static PragmaDirective const* findPragmaDirective(String const& name)
+{
+ char const* nameStr = name.Buffer();
+ for (int ii = 0; kPragmaDirectives[ii].name; ++ii)
+ {
+ if (strcmp(kPragmaDirectives[ii].name, nameStr) != 0)
+ continue;
+
+ return &kPragmaDirectives[ii];
+ }
+
+ return &kUnknownPragmaDirective;
+}
+
// Handle a `#pragma` directive
static void HandlePragmaDirective(PreprocessorDirectiveContext* context)
{
- // TODO(tfoley): figure out which pragmas to parse,
- // and which to pass along
- SkipToEndOfLine(context);
+ // Try to read the sub-directive name.
+ Token subDirectiveToken = PeekRawToken(context);
+
+ // The sub-directive had better be an identifier
+ if (subDirectiveToken.type != TokenType::Identifier)
+ {
+ GetSink(context)->diagnose(GetDirectiveLoc(context), Diagnostics::expectedPragmaDirectiveName);
+ SkipToEndOfLine(context);
+ return;
+ }
+ AdvanceRawToken(context);
+
+ // Look up the handler for the sub-directive.
+ PragmaDirective const* subDirective = findPragmaDirective(subDirectiveToken.getName()->text);
+
+ // Apply the sub-directive-specific callback
+ (subDirective->callback)(context, subDirectiveToken);
}
// Handle a `#version` directive