diff --git a/compiler/src/dmd/lexer.d b/compiler/src/dmd/lexer.d index 9cce7c567234..c9c3ed18d7a9 100644 --- a/compiler/src/dmd/lexer.d +++ b/compiler/src/dmd/lexer.d @@ -1964,7 +1964,7 @@ class Lexer /*************************************** * Get postfix of string literal. */ - private void stringPostfix(Token* t) pure @nogc + private void stringPostfix(Token* t) { switch (*p) { @@ -1973,6 +1973,13 @@ class Lexer case 'd': t.postfix = *p; p++; + // disallow e.g. `@r"_"dtype var;` + if (!Ccompile && isalpha(*p)) + { + const loc = loc(); + error(loc, "identifier character cannot follow string `%c` postfix without whitespace", + p[-1]); + } break; default: t.postfix = 0; @@ -2187,6 +2194,7 @@ class Lexer FLAGS flags = (base == 10) ? FLAGS.decimal : FLAGS.none; // Parse trailing 'u', 'U', 'l' or 'L' in any combination const psuffix = p; +LIntegerSuffix: while (1) { FLAGS f; @@ -2195,26 +2203,31 @@ class Lexer case 'U': case 'u': f = FLAGS.unsigned; - goto L1; + break; case 'l': - f = FLAGS.long_; error("lower case integer suffix 'l' is not allowed. Please use 'L' instead"); - goto L1; + goto case; case 'L': f = FLAGS.long_; - L1: - p++; - if ((flags & f) && !err) + break; + default: + // disallow e.g. `Foo!5Luvar;` + if (!Ccompile && flags >= FLAGS.unsigned && isalpha(*p)) { - error("repeated integer suffix `%c`", p[-1]); - err = true; + const loc = loc(); + error(loc, "identifier character cannot follow integer `%c` suffix without whitespace", + p[-1]); } - flags = cast(FLAGS)(flags | f); - continue; - default: - break; + break LIntegerSuffix; } - break; + p++; + if ((flags & f) && !err) + { + error("repeated integer suffix `%c`", p[-1]); + err = true; + } + flags = cast(FLAGS)(flags | f); + continue; } if (base == 8 && n >= 8) { @@ -2591,6 +2604,7 @@ class Lexer imaginary = true; } + bool gotSuffix = false; switch (*p) { case 'F': @@ -2604,7 +2618,7 @@ class Lexer if (isWellformedString && !isOutOfRange) isOutOfRange = Port.isFloat64LiteralOutOfRange(sbufptr); result = TOK.float64Literal; - break; + goto LcheckI; case 'l': if (!Ccompile) error("use 'L' suffix instead of 'l'"); @@ -2616,13 +2630,22 @@ class Lexer result = TOK.float80Literal; break; } - + gotSuffix = true; +LcheckI: if ((*p == 'i' || *p == 'I') && !Ccompile) { if (*p == 'I') error("use 'i' suffix instead of 'I'"); p++; imaginary = true; + gotSuffix = true; + } + // disallow e.g. `Foo!5fvar;` + if (!Ccompile && gotSuffix && isalpha(*p)) + { + const loc = loc(); + error(loc, "identifier character cannot follow float `%c` suffix without whitespace", + p[-1]); } if (imaginary) diff --git a/compiler/test/fail_compilation/templatesingleparam.d b/compiler/test/fail_compilation/templatesingleparam.d new file mode 100644 index 000000000000..7e5a9368585b --- /dev/null +++ b/compiler/test/fail_compilation/templatesingleparam.d @@ -0,0 +1,24 @@ +/* +REQUIRED_ARGS: -vcolumns +TEST_OUTPUT: +--- +fail_compilation/templatesingleparam.d(17,14): Error: identifier character cannot follow string `c` postfix without whitespace +fail_compilation/templatesingleparam.d(18,10): Error: identifier character cannot follow integer `U` suffix without whitespace +fail_compilation/templatesingleparam.d(22,6): Error: identifier character cannot follow string `d` postfix without whitespace +fail_compilation/templatesingleparam.d(23,4): Error: identifier character cannot follow float `f` suffix without whitespace +--- +*/ +class Foo(alias str) { + enum STR = str; +} + +class Bar { + Foo!q{foo}bb; // OK + Foo!q{foo}cc; + Foo!2LUNGS; +} + +@`_`int i; // OK +@`_`dint di; +@2flong fi; +@0xFeedObject obj; // not caught