diff --git a/tools/clang/include/clang/Basic/DiagnosticParseKinds.td b/tools/clang/include/clang/Basic/DiagnosticParseKinds.td index 3de70da1e7..a722882071 100644 --- a/tools/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1025,6 +1025,8 @@ def warn_hlsl_effect_technique : Warning < def warn_hlsl_semantic_identifier_collision : Warning < "'%0' interpreted as semantic; previous definition(s) ignored">, InGroup< HLSLSemanticIdentifierCollision >; +def err_hlsl_register_is_misspelled : Error < + "Syntax similar to : register() was used but unexpected keyword '%0' was used instead.">; def err_hlsl_enum : Error< "enum is unsupported in HLSL before 2017">; def warn_hlsl_new_feature : Warning < diff --git a/tools/clang/include/clang/Parse/Parser.h b/tools/clang/include/clang/Parse/Parser.h index 1c8eca36ce..ef52890896 100644 --- a/tools/clang/include/clang/Parse/Parser.h +++ b/tools/clang/include/clang/Parse/Parser.h @@ -2098,6 +2098,9 @@ class Parser : public CodeCompletionHandler { // HLSL Change Starts: Parse HLSL Attributes and append them to Declarator Object bool MaybeParseHLSLAttributes(std::vector &target); + bool ConsumeRegisterAssignment( + hlsl::RegisterAssignment + &asg); // Make sure it starts with register( first inline bool MaybeParseHLSLAttributes(Declarator &D) { return MaybeParseHLSLAttributes(D.UnusualAnnotations); } diff --git a/tools/clang/lib/Parse/ParseDecl.cpp b/tools/clang/lib/Parse/ParseDecl.cpp index 59be41a484..ada99f1388 100644 --- a/tools/clang/lib/Parse/ParseDecl.cpp +++ b/tools/clang/lib/Parse/ParseDecl.cpp @@ -341,6 +341,143 @@ static void ParseSpaceForHLSL(const StringRef name, } } +bool Parser::ConsumeRegisterAssignment(hlsl::RegisterAssignment &r) { + + ASTContext &context = getActions().getASTContext(); + + if (!Tok.is(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; + SkipUntil(tok::r_paren, StopAtSemi); // skip through ) + return true; + } + + StringRef identifierText = Tok.getIdentifierInfo()->getName(); + if (IsShaderProfileLike(identifierText) || + IsShaderProfileShort(identifierText)) { + r.ShaderProfile = Tok.getIdentifierInfo()->getName(); + ConsumeToken(); // consume shader model + if (ExpectAndConsume(tok::comma, diag::err_expected)) { + SkipUntil(tok::r_paren, StopAtSemi); // skip through ) + return true; + } + } + + if (!Tok.is(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; + SkipUntil(tok::r_paren, StopAtSemi); // skip through ) + return true; + } + + DXASSERT(Tok.is(tok::identifier), + "otherwise previous code should have failed"); + unsigned diagId; + + bool hasOnlySpace = false; + identifierText = Tok.getIdentifierInfo()->getName(); + if (identifierText.substr(0, sizeof("space") - 1).equals("space")) { + hasOnlySpace = true; + } else { + ParseRegisterNumberForHLSL(Tok.getIdentifierInfo()->getName(), + &r.RegisterType, &r.RegisterNumber, &diagId); + if (diagId == 0) { + r.setIsValid(true); + } else { + r.setIsValid(false); + Diag(Tok.getLocation(), diagId); + } + + ConsumeToken(); // consume register (type'#') + + ExprResult subcomponentResult; + if (Tok.is(tok::l_square)) { + BalancedDelimiterTracker brackets(*this, tok::l_square); + brackets.consumeOpen(); + + ExprResult result; + if (Tok.isNot(tok::r_square)) { + subcomponentResult = ParseConstantExpression(); + r.IsValid = r.IsValid && !subcomponentResult.isInvalid(); + Expr::EvalResult evalResult; + if (!subcomponentResult.get()->EvaluateAsRValue(evalResult, context) || + evalResult.hasSideEffects() || + (!evalResult.Val.isInt() && !evalResult.Val.isFloat())) { + Diag(Tok.getLocation(), + diag::err_hlsl_unsupported_register_noninteger); + r.setIsValid(false); + } else { + llvm::APSInt intResult; + if (evalResult.Val.isFloat()) { + bool isExact; + // TODO: consider what to do when convertToInteger fails + evalResult.Val.getFloat().convertToInteger( + intResult, llvm::APFloat::roundingMode::rmTowardZero, &isExact); + } else { + DXASSERT( + evalResult.Val.isInt(), + "otherwise prior test in this function should have failed"); + intResult = evalResult.Val.getInt(); + } + + if (intResult.isNegative()) { + Diag(Tok.getLocation(), + diag::err_hlsl_unsupported_register_noninteger); + r.setIsValid(false); + } else { + r.RegisterOffset = intResult.getLimitedValue(); + } + } + } else { + Diag(Tok.getLocation(), diag::err_expected_expression); + r.setIsValid(false); + } + + if (brackets.consumeClose()) { + SkipUntil(tok::r_paren, StopAtSemi); // skip through ) + return true; + } + } + } + if (hasOnlySpace) { + uint32_t RegisterSpaceValue = 0; + ParseSpaceForHLSL(Tok.getIdentifierInfo()->getName(), &RegisterSpaceValue, + &diagId); + if (diagId != 0) { + Diag(Tok.getLocation(), diagId); + r.setIsValid(false); + } else { + r.RegisterSpace = RegisterSpaceValue; + r.setIsValid(true); + } + ConsumeToken(); // consume identifier + } else { + if (Tok.is(tok::comma)) { + ConsumeToken(); // consume comma + if (!Tok.is(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; + SkipUntil(tok::r_paren, StopAtSemi); // skip through ) + return true; + } + unsigned RegisterSpaceVal = 0; + ParseSpaceForHLSL(Tok.getIdentifierInfo()->getName(), &RegisterSpaceVal, + &diagId); + if (diagId != 0) { + Diag(Tok.getLocation(), diagId); + r.setIsValid(false); + } else { + r.RegisterSpace = RegisterSpaceVal; + } + ConsumeToken(); // consume identifier + } + } + + if (ExpectAndConsume(tok::r_paren, diag::err_expected)) { + SkipUntil(tok::r_paren, StopAtSemi); // skip through ) + return true; + } + + return false; +} + bool Parser::MaybeParseHLSLAttributes(std::vector &target) { if (!getLangOpts().HLSL) { @@ -428,127 +565,9 @@ bool Parser::MaybeParseHLSLAttributes(std::vector &ta if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "register")) { return true; } - if (!Tok.is(tok::identifier)) { - Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; - SkipUntil(tok::r_paren, StopAtSemi); // skip through ) - return true; - } - - StringRef identifierText = Tok.getIdentifierInfo()->getName(); - if (IsShaderProfileLike(identifierText) || IsShaderProfileShort(identifierText)) { - r.ShaderProfile = Tok.getIdentifierInfo()->getName(); - ConsumeToken(); // consume shader model - if (ExpectAndConsume(tok::comma, diag::err_expected)) { - SkipUntil(tok::r_paren, StopAtSemi); // skip through ) - return true; - } - } - - if (!Tok.is(tok::identifier)) { - Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; - SkipUntil(tok::r_paren, StopAtSemi); // skip through ) - return true; - } - - DXASSERT(Tok.is(tok::identifier), "otherwise previous code should have failed"); - unsigned diagId; - - bool hasOnlySpace = false; - identifierText = Tok.getIdentifierInfo()->getName(); - if (identifierText.substr(0, sizeof("space")-1).equals("space")) { - hasOnlySpace = true; - } else { - ParseRegisterNumberForHLSL( - Tok.getIdentifierInfo()->getName(), &r.RegisterType, &r.RegisterNumber, &diagId); - if (diagId == 0) { - r.setIsValid(true); - } else { - r.setIsValid(false); - Diag(Tok.getLocation(), diagId); - } - - ConsumeToken(); // consume register (type'#') - - ExprResult subcomponentResult; - if (Tok.is(tok::l_square)) { - BalancedDelimiterTracker brackets(*this, tok::l_square); - brackets.consumeOpen(); - - ExprResult result; - if (Tok.isNot(tok::r_square)) { - subcomponentResult = ParseConstantExpression(); - r.IsValid = r.IsValid && !subcomponentResult.isInvalid(); - Expr::EvalResult evalResult; - if (!subcomponentResult.get()->EvaluateAsRValue(evalResult, context) || - evalResult.hasSideEffects() || - (!evalResult.Val.isInt() && !evalResult.Val.isFloat())) { - Diag(Tok.getLocation(), diag::err_hlsl_unsupported_register_noninteger); - r.setIsValid(false); - } else { - llvm::APSInt intResult; - if (evalResult.Val.isFloat()) { - bool isExact; - // TODO: consider what to do when convertToInteger fails - evalResult.Val.getFloat().convertToInteger(intResult, llvm::APFloat::roundingMode::rmTowardZero, &isExact); - } else { - DXASSERT(evalResult.Val.isInt(), "otherwise prior test in this function should have failed"); - intResult = evalResult.Val.getInt(); - } - - if (intResult.isNegative()) { - Diag(Tok.getLocation(), diag::err_hlsl_unsupported_register_noninteger); - r.setIsValid(false); - } else { - r.RegisterOffset = intResult.getLimitedValue(); - } - } - } else { - Diag(Tok.getLocation(), diag::err_expected_expression); - r.setIsValid(false); - } - if (brackets.consumeClose()) { - SkipUntil(tok::r_paren, StopAtSemi); // skip through ) - return true; - } - } - } - if (hasOnlySpace) { - uint32_t RegisterSpaceValue = 0; - ParseSpaceForHLSL(Tok.getIdentifierInfo()->getName(), &RegisterSpaceValue, &diagId); - if (diagId != 0) { - Diag(Tok.getLocation(), diagId); - r.setIsValid(false); - } else { - r.RegisterSpace = RegisterSpaceValue; - r.setIsValid(true); - } - ConsumeToken(); // consume identifier - } else { - if (Tok.is(tok::comma)) { - ConsumeToken(); // consume comma - if (!Tok.is(tok::identifier)) { - Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; - SkipUntil(tok::r_paren, StopAtSemi); // skip through ) - return true; - } - unsigned RegisterSpaceVal = 0; - ParseSpaceForHLSL(Tok.getIdentifierInfo()->getName(), &RegisterSpaceVal, &diagId); - if (diagId != 0) { - Diag(Tok.getLocation(), diagId); - r.setIsValid(false); - } - else { - r.RegisterSpace = RegisterSpaceVal; - } - ConsumeToken(); // consume identifier - } - } - - if (ExpectAndConsume(tok::r_paren, diag::err_expected)) { - SkipUntil(tok::r_paren, StopAtSemi); // skip through ) + if (ConsumeRegisterAssignment(r)) return true; - } target.push_back(new (context) hlsl::RegisterAssignment(r)); } @@ -633,6 +652,20 @@ bool Parser::MaybeParseHLSLAttributes(std::vector &ta Actions.DiagnoseSemanticDecl(pUA); ConsumeToken(); // consume semantic + // Likely a misspell of register() or a mismatching macro: + // registers() would cause a crash without this fix. + + if (Tok.is(tok::l_paren)) { + + Diag(Tok.getLocation(), diag::err_hlsl_register_is_misspelled) + << semanticName; + + ConsumeParen(); + hlsl::RegisterAssignment dummy; + if (ConsumeRegisterAssignment(dummy)) // Skip invalid syntax + return true; + } + target.push_back(pUA); } else {