diff --git a/scripts/diagnostics.txt b/scripts/diagnostics.txt index 1af48eeb9..e86fff32e 100644 --- a/scripts/diagnostics.txt +++ b/scripts/diagnostics.txt @@ -410,6 +410,7 @@ error InvalidRandType "{} is not a valid type for a '{}' property" error InvalidMethodOverride "cannot override built-in method '{}'" error InvalidRandomizeOverride "override for '{}' should be a public non-static function that returns void and takes no parameters" error MismatchStaticConstraint "mismatch of 'static' keyword between constraint prototype and declaration" +error MismatchConstraintSpecifiers "mismatch of override specifiers between constraint prototype and declaration" error DPIRefArg "DPI subroutines cannot have 'ref' arguments" error DPIPureArg "DPI imports marked 'pure' cannot have 'output' or 'inout' arguments" error DPIPureReturn "DPI imports marked 'pure' cannot return 'void'" diff --git a/source/ast/symbols/ClassSymbols.cpp b/source/ast/symbols/ClassSymbols.cpp index 5432df5d6..f94a14c7f 100644 --- a/source/ast/symbols/ClassSymbols.cpp +++ b/source/ast/symbols/ClassSymbols.cpp @@ -1259,6 +1259,16 @@ const Constraint& ConstraintBlockSymbol::getConstraints() const { diag.addNote(diag::NoteDeclarationHere, location); } + bitmask declFlags; + addSpecifierFlags(cds.specifiers, declFlags); + + if (declFlags != (flags & (ConstraintBlockFlags::Initial | ConstraintBlockFlags::Extends | + ConstraintBlockFlags::Final))) { + auto& diag = outerScope.addDiag(diag::MismatchConstraintSpecifiers, + cds.name->getLastToken().location()); + diag.addNote(diag::NoteDeclarationHere, location); + } + constraint = &Constraint::bind(*cds.block, context); return *constraint; } diff --git a/tests/unittests/ast/ClassTests.cpp b/tests/unittests/ast/ClassTests.cpp index 3df728e21..38b368d8c 100644 --- a/tests/unittests/ast/ClassTests.cpp +++ b/tests/unittests/ast/ClassTests.cpp @@ -3334,3 +3334,24 @@ endclass REQUIRE(diags.size() == 1); CHECK(diags[0].code == diag::BadSolveBefore); } + +TEST_CASE("v1800-2023: extern constraint blocks must match specifiers") { + auto options = optionsFor(LanguageVersion::v1800_2023); + auto tree = SyntaxTree::fromText(R"( +class A; + extern constraint :initial a; + extern constraint :final b; +endclass + +constraint A::a {} +constraint :final A::b {} +)", + options); + + Compilation compilation(options); + compilation.addSyntaxTree(tree); + + auto& diags = compilation.getAllDiagnostics(); + REQUIRE(diags.size() == 1); + CHECK(diags[0].code == diag::MismatchConstraintSpecifiers); +}