diff --git a/index.html b/index.html
index 92e36f4..078fe42 100644
--- a/index.html
+++ b/index.html
@@ -88,6 +88,12 @@
C Declarations & printf/scanf ➔ Prose
Functions may not be restrict-qualified
+
+ Duplicate qualifier on pointer
+
+
+ Duplicate qualifier on function
+
Zero-size arrays are a non-standard extension
diff --git a/js/prose-decl.js b/js/prose-decl.js
index 8c0291b..8a7d8e6 100644
--- a/js/prose-decl.js
+++ b/js/prose-decl.js
@@ -363,6 +363,18 @@ export class Explainer {
}
}
+ /**
+ * Checks whether there are duplicate qualifiers in the given list
+ * @param {string[]} qualifiers
+ * @param {'function' | 'pointer'} context
+ */
+ checkForDuplicateQualifiers(qualifiers, context) {
+ const withoutDuplicates = new Set(qualifiers.map(q => q === '_Atomic' ? 'atomic' : q))
+ if (withoutDuplicates.size !== qualifiers.length) {
+ this.showDiagnostic(`duplicate-${context}-qualifier`);
+ }
+ }
+
/**
* Throws if there is misuse of specifiers in the declaration specifier
* sequence, depending on the provided kind of context.
@@ -508,6 +520,7 @@ export class Explainer {
break;
}
case '*': {
+ this.checkForDuplicateQualifiers(d.qualifiers, 'pointer');
const q = d.qualifiers
.sort(Explainer.compareSpecifiers)
.map(Explainer.remapSpecifierTextForReadability)
@@ -598,6 +611,7 @@ export class Explainer {
this.showDiagnostic('empty-function-parameters');
}
+ this.checkForDuplicateQualifiers(d.qualifiers, 'function');
let overrideFinal = d.qualifiers[d.qualifiers.length - 1];
if (!['override', 'final'].includes(overrideFinal)) {
overrideFinal = undefined;
diff --git a/test/test.js b/test/test.js
index 81a278f..aea5c19 100644
--- a/test/test.js
+++ b/test/test.js
@@ -258,4 +258,20 @@ describe('Examples', function () {
assert.ok(!diagnostics.includes('constexpr-implicit-const'));
});
});
+
+ code = 'void() const const';
+ describe(code, function () {
+ const diagnostics = codeToProse(code).diagnostics;
+ it('rejects duplicate qualifiers on function', function() {
+ assert.ok(diagnostics.includes('duplicate-function-qualifier'));
+ });
+ });
+
+ code = 'void * const const';
+ describe(code, function () {
+ const diagnostics = codeToProse(code).diagnostics;
+ it('rejects duplicate qualifiers on pointer', function() {
+ assert.ok(diagnostics.includes('duplicate-pointer-qualifier'));
+ });
+ });
});