From 6c39d1bb7325ba1dcd79b0f32dd6b103802f4d1c Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 25 Feb 2026 07:06:55 +0000 Subject: [PATCH] 8371683: TYPE_USE annotation on var lambda parameter should be rejected Reviewed-by: vromero --- .../com/sun/tools/javac/code/Flags.java | 12 ++++- .../com/sun/tools/javac/code/Source.java | 3 +- .../com/sun/tools/javac/comp/Attr.java | 3 +- .../com/sun/tools/javac/comp/Check.java | 11 ++-- .../com/sun/tools/javac/comp/MemberEnter.java | 4 +- .../sun/tools/javac/parser/JavacParser.java | 14 +++-- .../com/sun/tools/javac/tree/JCTree.java | 15 ++++-- .../failures/target/VarVariables-old.out | 9 ++++ .../failures/target/VarVariables.java | 52 +++++++++++++++++++ .../failures/target/VarVariables.out | 9 ++++ 10 files changed, 115 insertions(+), 17 deletions(-) create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/target/VarVariables-old.out create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/target/VarVariables.java create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/target/VarVariables.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java index 5b59e47027e..ac1bcc84194 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -156,12 +156,22 @@ public class Flags { @Use({FlagTarget.CLASS}) public static final int IMPLICIT_CLASS = 1<<19; + /** Variable with implicit/inferred type. + */ + @Use(FlagTarget.VARIABLE) + public static final int VAR_VARIABLE = 1<<19; + /** Flag is set for compiler-generated anonymous method symbols * that `own' an initializer block. */ @Use({FlagTarget.METHOD}) public static final int BLOCK = 1<<20; + /** A parameter of a lambda function. + */ + @Use(FlagTarget.VARIABLE) + public static final int LAMBDA_PARAMETER = 1<<20; + /** Flag is set for ClassSymbols that are being compiled from source. */ @Use({FlagTarget.CLASS}) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java index 84a823f785f..cf5e5ca83f5 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -272,6 +272,7 @@ public enum Source { CASE_NULL(JDK21, Fragments.FeatureCaseNull, DiagKind.NORMAL), PATTERN_SWITCH(JDK21, Fragments.FeaturePatternSwitch, DiagKind.PLURAL), REDUNDANT_STRICTFP(JDK17), + TYPE_ANNOTATIONS_ON_VAR_LAMBDA_PARAMETER(MIN, JDK19), UNCONDITIONAL_PATTERN_IN_INSTANCEOF(JDK21, Fragments.FeatureUnconditionalPatternsInInstanceof, DiagKind.PLURAL), RECORD_PATTERNS(JDK21, Fragments.FeatureDeconstructionPatterns, DiagKind.PLURAL), IMPLICIT_CLASSES(JDK25, Fragments.FeatureImplicitClasses, DiagKind.PLURAL), diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index d4bfbce0699..48e0238fb07 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -4224,7 +4224,8 @@ public class Attr extends JCTree.Visitor { type = resultInfo.pt; } tree.type = tree.var.type = type; - BindingSymbol v = new BindingSymbol(tree.var.mods.flags, tree.var.name, type, env.info.scope.owner); + BindingSymbol v = new BindingSymbol(tree.var.mods.flags | tree.var.declKind.additionalSymbolFlags, + tree.var.name, type, env.info.scope.owner); v.pos = tree.pos; tree.var.sym = v; if (chk.checkUnique(tree.var.pos(), v, env.info.scope)) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java index 94b14f3122f..0af30be4671 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3544,7 +3544,10 @@ public class Check { if (s.kind == PCK) applicableTargets.add(names.PACKAGE); } else if (target == names.TYPE_USE) { - if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) { + if (s.kind == VAR && + (s.flags() & Flags.VAR_VARIABLE) != 0 && + (!Feature.TYPE_ANNOTATIONS_ON_VAR_LAMBDA_PARAMETER.allowedInSource(source) || + ((s.flags() & Flags.LAMBDA_PARAMETER) == 0))) { //cannot type annotate implicitly typed locals continue; } else if (s.kind == TYP || s.kind == VAR || @@ -5632,8 +5635,8 @@ public class Check { } case JCVariableDecl variableDecl -> { if (variableDecl.vartype != null && - (variableDecl.sym.flags_field & RECORD) == 0 || - (variableDecl.sym.flags_field & ~(Flags.PARAMETER | RECORD | GENERATED_MEMBER)) != 0) { + ((variableDecl.sym.flags_field & RECORD) == 0 || + (variableDecl.sym.flags_field & ~(Flags.PARAMETER | RECORD | GENERATED_MEMBER)) != 0)) { /* we don't want to warn twice so if this variable is a compiler generated parameter of * a canonical record constructor, we don't want to issue a warning as we will warn the * corresponding compiler generated private record field anyways diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java index d63ba1677d6..e02fb9849c9 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -281,7 +281,7 @@ public class MemberEnter extends JCTree.Visitor { : tree.vartype.type; Name name = tree.name; VarSymbol v = new VarSymbol(0, name, vartype, enclScope.owner); - v.flags_field = chk.checkFlags(tree.mods.flags, v, tree); + v.flags_field = chk.checkFlags(tree.mods.flags | tree.declKind.additionalSymbolFlags, v, tree); tree.sym = v; if (tree.init != null) { v.flags_field |= HASINIT; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index e78537c10f5..40f91a004fd 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3902,7 +3902,7 @@ public class JavacParser implements Parser { if (allowThisIdent || !lambdaParameter || LAX_IDENTIFIER.test(token.kind) || - mods.flags != Flags.PARAMETER || + (mods.flags & ~(Flags.PARAMETER | Flags.LAMBDA_PARAMETER)) != 0 || mods.annotations.nonEmpty()) { JCExpression pn; if (token.kind == UNDERSCORE && (catchParameter || lambdaParameter)) { @@ -5405,7 +5405,13 @@ public class JavacParser implements Parser { * LastFormalParameter = { FINAL | '@' Annotation } Type '...' Ident | FormalParameter */ protected JCVariableDecl formalParameter(boolean lambdaParameter, boolean recordComponent) { - JCModifiers mods = !recordComponent ? optFinal(Flags.PARAMETER) : modifiersOpt(); + JCModifiers mods; + + if (recordComponent) { + mods = modifiersOpt(); + } else { + mods = optFinal(Flags.PARAMETER | (lambdaParameter ? Flags.LAMBDA_PARAMETER : 0)); + } if (recordComponent && mods.flags != 0) { log.error(mods.pos, Errors.RecordCantDeclareFieldModifiers); } @@ -5436,7 +5442,7 @@ public class JavacParser implements Parser { } protected JCVariableDecl implicitParameter() { - JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER); + JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER | Flags.LAMBDA_PARAMETER); return variableDeclaratorId(mods, null, false, true, false); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java index e0a99a6f103..c54507bed3f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1012,9 +1012,16 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { public static class JCVariableDecl extends JCStatement implements VariableTree { public enum DeclKind { - EXPLICIT, // "SomeType name" - IMPLICIT, // "name" - VAR, // "var name" + EXPLICIT(0), // "SomeType name" + IMPLICIT(Flags.VAR_VARIABLE), // "name" + VAR(Flags.VAR_VARIABLE), // "var name" + ; + + public final long additionalSymbolFlags; + + private DeclKind(long additionalSymbolFlags) { + this.additionalSymbolFlags = additionalSymbolFlags; + } } /** variable modifiers */ diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/target/VarVariables-old.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/target/VarVariables-old.out new file mode 100644 index 00000000000..5b16d28d053 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/target/VarVariables-old.out @@ -0,0 +1,9 @@ +VarVariables.java:34:36: compiler.err.feature.not.supported.in.source.plural: (compiler.misc.feature.deconstruction.patterns), 19, 21 +VarVariables.java:18:9: compiler.err.annotation.type.not.applicable +VarVariables.java:24:14: compiler.err.annotation.type.not.applicable +VarVariables.java:27:14: compiler.err.annotation.type.not.applicable +VarVariables.java:32:14: compiler.err.annotation.type.not.applicable +VarVariables.java:36:37: compiler.err.annotation.type.not.applicable +VarVariables.java:32:18: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @VarVariables.TA), java.lang, @VarVariables.TA java.lang.AutoCloseable +VarVariables.java:36:41: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @VarVariables.TA), java.lang, @VarVariables.TA java.lang.String +8 errors diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/target/VarVariables.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/target/VarVariables.java new file mode 100644 index 00000000000..a47b8b31da7 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/target/VarVariables.java @@ -0,0 +1,52 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8371683 + * @summary Test that type annotations cannot appears on 'var' variables + * @compile/fail/ref=VarVariables.out -XDrawDiagnostics VarVariables.java + * @compile/fail/ref=VarVariables-old.out --release 19 -XDrawDiagnostics -XDshould-stop.at=FLOW VarVariables.java + */ + +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.util.List; +import java.util.function.Consumer; + +class VarVariables { + private void test(Object o) { + @DA var v1 = ""; + @DTA var v2 = ""; + @TA var v3 = ""; + Consumer c1 = (@DA var v) -> {}; + Consumer c2 = (@DTA var v) -> {}; + Consumer c3 = (@TA var v) -> {}; + for (@DA var v = ""; !v.isEmpty(); ) {} + for (@DTA var v = ""; !v.isEmpty(); ) {} + for (@TA var v = ""; !v.isEmpty(); ) {} + for (@DA var v : List.of("")) {} + for (@DTA var v : List.of("")) {} + for (@TA var v : List.of("")) {} + try (@DA var v = open()) { + } catch (Exception ex) {} + try (@DTA var v = open()) { + } catch (Exception ex) {} + try (@TA var v = open()) { + } catch (Exception ex) {} + boolean b1 = o instanceof R(@DA var v); + boolean b2 = o instanceof R(@DTA var v); + boolean b3 = o instanceof R(@TA var v); + } + + private AutoCloseable open() { + return null; + } + record R(String str) {} + + @Target(ElementType.TYPE_USE) + @interface TA { } + + @Target({ElementType.TYPE_USE, ElementType.LOCAL_VARIABLE, ElementType.PARAMETER}) + @interface DTA { } + + @Target({ElementType.LOCAL_VARIABLE, ElementType.PARAMETER}) + @interface DA { } +} diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/target/VarVariables.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/target/VarVariables.out new file mode 100644 index 00000000000..2586e7883d6 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/target/VarVariables.out @@ -0,0 +1,9 @@ +VarVariables.java:18:9: compiler.err.annotation.type.not.applicable +VarVariables.java:21:32: compiler.err.annotation.type.not.applicable +VarVariables.java:24:14: compiler.err.annotation.type.not.applicable +VarVariables.java:27:14: compiler.err.annotation.type.not.applicable +VarVariables.java:32:14: compiler.err.annotation.type.not.applicable +VarVariables.java:36:37: compiler.err.annotation.type.not.applicable +VarVariables.java:32:18: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @VarVariables.TA), java.lang, @VarVariables.TA java.lang.AutoCloseable +VarVariables.java:36:41: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @VarVariables.TA), java.lang, @VarVariables.TA java.lang.String +8 errors