changeset 47598:b4af284aa0b1 condy-folding

emit warning if a member is not found or a method handle is incorrect
author vromero
date Thu, 26 Oct 2017 15:42:58 -0700
parents 27741fa6616e
children 70f6e416e669
files src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/com/sun/tools/javac/util/Constables.java test/langtools/tools/javac/specialConstantFolding/IndyCrashTest.out test/langtools/tools/javac/specialConstantFolding/warningNotFoundOrIncorrect/WarningIfClassOrMemberNotFound.java test/langtools/tools/javac/specialConstantFolding/warningNotFoundOrIncorrect/WarningIfClassOrMemberNotFound.out test/langtools/tools/javac/specialConstantFolding/warningNotFoundOrIncorrect/WarningIfMemberIncorrect.java test/langtools/tools/javac/specialConstantFolding/warningNotFoundOrIncorrect/WarningIfMemberIncorrect.out
diffstat 10 files changed, 283 insertions(+), 60 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Thu Oct 26 22:06:04 2017 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Thu Oct 26 15:42:58 2017 -0700
@@ -2646,7 +2646,7 @@
                                   List<Type> typeargtypes) {
         return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes);
     }
-    private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext,
+    public Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext,
                                   DiagnosticPosition pos, Env<AttrContext> env,
                                   Symbol location, Type site, Name name, List<Type> argtypes,
                                   List<Type> typeargtypes) {
@@ -2660,7 +2660,7 @@
             @Override
             Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
                 if (sym.kind.isResolutionError()) {
-                    sym = super.access(env, pos, location, sym);
+                    sym = resolveContext.silentFail ? sym : super.access(env, pos, location, sym);
                 } else if (allowMethodHandles) {
                     MethodSymbol msym = (MethodSymbol)sym;
                     if ((msym.flags() & SIGNATURE_POLYMORPHIC) != 0) {
@@ -4724,7 +4724,7 @@
      * can be nested - this means that when each overload resolution routine should
      * work within the resolution context it created.
      */
-    class MethodResolutionContext {
+    public class MethodResolutionContext {
 
         private List<Candidate> candidates = List.nil();
 
@@ -4732,7 +4732,9 @@
 
         MethodCheck methodCheck = resolveMethodCheck;
 
-        private boolean internalResolution = false;
+        public boolean internalResolution = false;
+        // in case of failure, don't report the error
+        public boolean silentFail = false;
         private DeferredAttr.AttrMode attrMode = DeferredAttr.AttrMode.SPECULATIVE;
 
         void addInapplicableCandidate(Symbol sym, JCDiagnostic details) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Thu Oct 26 22:06:04 2017 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Thu Oct 26 15:42:58 2017 -0700
@@ -389,7 +389,7 @@
             if (value instanceof MethodSymbol) {
                 MethodSymbol m = (MethodSymbol)value;
                 if (!m.isDynamic()) {
-                    poolbuf.appendByte((m.owner.flags() & INTERFACE) != 0
+                    poolbuf.appendByte((m.owner.flags_field & INTERFACE) != 0
                               ? CONSTANT_InterfaceMethodref
                               : CONSTANT_Methodref);
                     poolbuf.appendChar(pool.put(m.owner));
@@ -1068,8 +1068,7 @@
         try {
             c.complete();
         } catch (CompletionFailure ex) {
-            System.err.println("error: " + c + ": " + ex.getMessage());
-            throw ex;
+            System.err.println("warning: " + c + ": " + ex.getMessage());
         }
         if (!c.type.hasTag(CLASS)) return; // arrays
         if (pool != null && // pool might be null if called from xClassName
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java	Thu Oct 26 22:06:04 2017 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java	Thu Oct 26 15:42:58 2017 -0700
@@ -39,10 +39,13 @@
 
 import java.util.*;
 
-import com.sun.tools.javac.code.Type.MethodType;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 
+import static com.sun.tools.javac.code.Flags.INTERFACE;
 import static com.sun.tools.javac.code.Kinds.*;
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 
@@ -359,10 +362,13 @@
         UniqueType uniqueType;
 
         public MethodHandle(int refKind, Symbol refSym, Types types) {
+            this(refKind, refSym, types, new StrictMethodHandleCheckHelper(refKind, refSym));
+        }
+        public MethodHandle(int refKind, Symbol refSym, Types types, MethodHandleCheckHelper mhCheckHelper) {
             this.refKind = refKind;
             this.refSym = refSym;
             this.uniqueType = new UniqueType(this.refSym.type, types);
-            checkConsistent();
+            mhCheckHelper.check();
         }
         public boolean equals(Object other) {
             if (!(other instanceof MethodHandle)) return false;
@@ -382,55 +388,113 @@
                 uniqueType.hashCode();
         }
 
-        /**
-         * Check consistency of reference kind and symbol (see JVMS 4.4.8)
-         */
-        @SuppressWarnings("fallthrough")
-        private void checkConsistent() {
-            boolean staticOk = false;
-            Kind expectedKind = null;
-            Filter<Name> nameFilter = nonInitFilter;
-            boolean interfaceOwner = false;
-            switch (refKind) {
-                case ClassFile.REF_getStatic:
-                case ClassFile.REF_putStatic:
-                    staticOk = true;
-                case ClassFile.REF_getField:
-                case ClassFile.REF_putField:
-                    expectedKind = VAR;
-                    break;
-                case ClassFile.REF_newInvokeSpecial:
-                    nameFilter = initFilter;
-                    expectedKind = MTH;
-                    break;
-                case ClassFile.REF_invokeInterface:
-                    interfaceOwner = true;
-                    expectedKind = MTH;
-                    break;
-                case ClassFile.REF_invokeStatic:
-                    interfaceOwner = true;
-                    staticOk = true;
-                case ClassFile.REF_invokeVirtual:
-                    expectedKind = MTH;
-                    break;
-                case ClassFile.REF_invokeSpecial:
-                    interfaceOwner = true;
-                    expectedKind = MTH;
-                    break;
+        public abstract static class MethodHandleCheckHelper {
+            int refKind;
+            Symbol refSym;
+            public boolean staticOk = false;
+            public Kind expectedKind = null;
+            public Filter<Name> nameFilter = nonInitFilter;
+            public boolean interfaceOwner = false;
+
+            static Filter<Name> nonInitFilter = n -> (n != n.table.names.init && n != n.table.names.clinit);
+            static Filter<Name> initFilter = n -> n == n.table.names.init;
+
+            @SuppressWarnings("fallthrough")
+            public MethodHandleCheckHelper(int refKind, Symbol refSym) {
+                this.refKind = refKind;
+                this.refSym = refSym;
+                switch (refKind) {
+                    case ClassFile.REF_getStatic:
+                    case ClassFile.REF_putStatic:
+                        staticOk = true;
+                    case ClassFile.REF_getField:
+                    case ClassFile.REF_putField:
+                        expectedKind = VAR;
+                        break;
+                    case ClassFile.REF_newInvokeSpecial:
+                        nameFilter = initFilter;
+                        expectedKind = MTH;
+                        break;
+                    case ClassFile.REF_invokeInterface:
+                        interfaceOwner = true;
+                        expectedKind = MTH;
+                        break;
+                    case ClassFile.REF_invokeStatic:
+                        interfaceOwner = true;
+                        staticOk = true;
+                    case ClassFile.REF_invokeVirtual:
+                        expectedKind = MTH;
+                        break;
+                    case ClassFile.REF_invokeSpecial:
+                        interfaceOwner = true;
+                        expectedKind = MTH;
+                        break;
+                }
             }
-            Assert.check(!refSym.isStatic() || staticOk, "incorrect static-ness for symbol " + refSym);
-            Assert.check(refSym.kind == expectedKind, "unexpected kind for symbol " + refSym +". \n"
-                    + "Expected = " + expectedKind + "\n"
-                    + "Found = " + refSym.kind);
-            Assert.check(nameFilter.accepts(refSym.name), "incorrect name for symbol " + refSym);
-            Assert.check(!refSym.owner.isInterface() || interfaceOwner,
-                    interfaceOwner ?
-                            "interface owner expected for symbol ":
-                            "non interface owner expected for symbol " + refSym);
+
+            public abstract void check();
         }
-        //where
-                Filter<Name> nonInitFilter = n -> (n != n.table.names.init && n != n.table.names.clinit);
 
-                Filter<Name> initFilter = n -> n == n.table.names.init;
+        public static class DumbMethodHandleCheckHelper extends MethodHandleCheckHelper {
+            public DumbMethodHandleCheckHelper(int refKind, Symbol refSym) {
+                super(refKind, refSym);
+            }
+
+            @Override
+            public void check() {
+                // do nothing
+            }
+        }
+
+        public static class StrictMethodHandleCheckHelper extends MethodHandleCheckHelper {
+            public StrictMethodHandleCheckHelper(int refKind, Symbol refSym) {
+                super(refKind, refSym);
+            }
+
+            @Override
+            public void check() {
+                Assert.check(!refSym.isStatic() || staticOk, "incorrect static-ness for symbol " + refSym);
+                Assert.check(refSym.kind == expectedKind, "unexpected kind for symbol " + refSym +". \n"
+                        + "Expected = " + expectedKind + "\n"
+                        + "Found = " + refSym.kind);
+                Assert.check(nameFilter.accepts(refSym.name), "incorrect name for symbol " + refSym);
+                boolean isInterface = (refSym.owner.flags_field & INTERFACE) != 0;
+                Assert.check(!isInterface || interfaceOwner,
+                        interfaceOwner ?
+                                "interface owner expected for symbol ":
+                                "non interface owner expected for symbol " + refSym);
+            }
+        }
+
+        public static class WarnMethodHandleCheckHelper extends MethodHandleCheckHelper {
+            Log log;
+            DiagnosticPosition pos;
+            public WarnMethodHandleCheckHelper(Log log, DiagnosticPosition pos, int refKind, Symbol refSym) {
+                super(refKind, refSym);
+                this.log = log;
+                this.pos = pos;
+            }
+
+            @Override
+            public void check() {
+                if (refSym.isStatic() != staticOk) {
+                    log.warning(pos, Warnings.IncorrectStaticnessForSymbol(refSym));
+                }
+                if (refSym.kind != expectedKind) {
+                    log.warning(pos, Warnings.UnexpectedKindForSymbol(refSym, expectedKind, refSym.kind));
+                }
+                if (!nameFilter.accepts(refSym.name)) {
+                    log.warning(pos, Warnings.IncorrectNameForMethod(refSym, refKind));
+                }
+                boolean isInterface = (refSym.owner.flags_field & INTERFACE) != 0;
+                if (isInterface && !interfaceOwner) {
+                    if (interfaceOwner) {
+                        log.warning(pos, Warnings.InterfaceOwnerExpectedForSymbol(refSym));
+                    } else {
+                        log.warning(pos, Warnings.NonInterfaceOwnerExpectedForSymbol(refSym));
+                    }
+                }
+            }
+        }
     }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Oct 26 22:06:04 2017 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Oct 26 15:42:58 2017 -0700
@@ -3177,7 +3177,7 @@
     illegal argument for {0}: {1}
 
 ###
-# constant folding errors
+# constant folding errors and warnings
 
 # 0: type
 compiler.err.method.handle.not.suitable.indy=\
@@ -3207,3 +3207,33 @@
     error in reflective call\n\
     while trying to invoke method \"{0}\" of class \"{1}\"\n\
     with error message: \"{2}\"
+
+# 0: symbol
+compiler.warn.class.not.found=\
+    could not find class file for class: {0}
+
+# 0: name, 1: symbol
+compiler.warn.member.not.found.at.class=\
+    could not find member {0} at class {1}
+
+# 0: symbol
+compiler.warn.incorrect.staticness.for.symbol=\
+    incorrect static-ness for symbol: {0}
+
+# 0: symbol, 1: symbol kind, 2: symbol kind
+compiler.warn.unexpected.kind.for.symbol=\
+    unexpected kind for symbol: {0}\n\
+    expected: {1}\n\
+    found: {2}
+
+# 0: symbol, 1: number
+compiler.warn.incorrect.name.for.method=\
+    incorrect name or reference kind for method: {0}, with reference kind: {1}
+
+# 0: symbol
+compiler.warn.interface.owner.expected.for.symbol=\
+    interface owner expected for symbol: {0}
+
+# 0: symbol
+compiler.warn.non.interface.owner.expected.for.symbol=\
+    non interface owner expected for symbol : {0}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Constables.java	Thu Oct 26 22:06:04 2017 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Constables.java	Thu Oct 26 15:42:58 2017 -0700
@@ -32,10 +32,10 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.nio.charset.Charset;
-import java.util.Map;
 
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.CompletionFailure;
 import com.sun.tools.javac.code.Symbol.MethodSymbol;
 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
 import com.sun.tools.javac.code.Symbol.VarSymbol;
@@ -50,18 +50,23 @@
 import com.sun.tools.javac.comp.ConstablesVisitor;
 import com.sun.tools.javac.comp.Env;
 import com.sun.tools.javac.comp.Resolve;
+import com.sun.tools.javac.comp.Resolve.*;
+//import com.sun.tools.javac.comp.Resolve.BasicLookupHelper;
 import com.sun.tools.javac.jvm.ClassFile;
 import com.sun.tools.javac.jvm.Pool;
+import com.sun.tools.javac.jvm.Pool.MethodHandle.MethodHandleCheckHelper;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.JCExpression;
 import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
 import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 
+import static com.sun.tools.javac.code.Flags.INTERFACE;
 import static com.sun.tools.javac.code.Flags.STATIC;
 import static com.sun.tools.javac.code.TypeTag.ARRAY;
-import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
 import static com.sun.tools.javac.tree.JCTree.Tag.SELECT;
 
 /** This class is a support tool to parse a method descriptor and obtain a list of the types
@@ -278,7 +283,19 @@
             MethodType mType = (MethodType)descriptorToType(
                     methodTypeDesc, currentModule, true);
             Symbol refSymbol = getReferenceSymbol(refKind, ownerType.tsym, name, mType);
-            return new Pool.MethodHandle(refKind, refSymbol, types);
+            boolean ownerFound = true;
+            try {
+                refSymbol.owner.complete();
+            } catch (CompletionFailure ex) {
+                log.warning(tree, Warnings.ClassNotFound(refSymbol.owner));
+                ownerFound = false;
+            }
+            if (ownerFound) {
+                checkIfMemberExists(tree, attrEnv, names.fromString(name), ownerType, mType.argtypes, refKind);
+            }
+            Pool.MethodHandle mHandle = new Pool.MethodHandle(refKind, refSymbol, types,
+                    new Pool.MethodHandle.DumbMethodHandleCheckHelper(refKind, refSymbol));
+            return mHandle;
         } else if (methodTypeRefClass.isInstance(constant)) {
             String descriptor = (String)invokeReflectiveMethod(methodTypeRefClass, constant, "descriptorString");
             return types.erasure(descriptorToType(descriptor, currentModule, true));
@@ -293,6 +310,13 @@
                 }
             }
             Type type = descriptorToType(descriptor, currentModule, false);
+            if (!type.hasTag(ARRAY)) {
+                try {
+                    type.tsym.complete();
+                } catch (CompletionFailure ex) {
+                    log.warning(tree, Warnings.ClassNotFound(type.tsym));
+                }
+            }
             return type.hasTag(ARRAY) ? type : type.tsym;
         } else if (dynamicConstantClass.isInstance(constant)) {
             Object classRef =
@@ -325,6 +349,32 @@
             }
         }
 
+        private void checkIfMemberExists(DiagnosticPosition pos, Env<AttrContext> attrEnv, Name name, Type qual, List<Type> args, int refKind) {
+            Symbol refSym = resolveConstableMethod(pos, attrEnv, qual, name, args, List.nil());
+            if (refSym.kind.isResolutionError()) {
+                try {
+                    refSym = rs.resolveInternalField(pos, attrEnv, qual, name);
+                } catch (Throwable t) {
+                    log.warning(pos, Warnings.MemberNotFoundAtClass(name, qual.tsym));
+                    return;
+                }
+            }
+            Pool.MethodHandle.WarnMethodHandleCheckHelper mhCheckHelper = new Pool.MethodHandle.WarnMethodHandleCheckHelper(log, pos, refKind, refSym);
+            mhCheckHelper.check();
+        }
+
+        public Symbol resolveConstableMethod(DiagnosticPosition pos, Env<AttrContext> env,
+                                    Type site, Name name,
+                                    List<Type> argtypes,
+                                    List<Type> typeargtypes) {
+            MethodResolutionContext resolveContext = rs.new MethodResolutionContext();
+            resolveContext.internalResolution = true;
+            resolveContext.silentFail = true;
+            Symbol sym = rs.resolveQualifiedMethod(resolveContext, pos, env, site.tsym,
+                    site, name, argtypes, typeargtypes);
+            return sym;
+        }
+
     public Object[] convertConstants(JCTree tree, Env<AttrContext> attrEnv, Object[] constants, ModuleSymbol currentModule, boolean bsmArgs) {
         if (constants == null || constants.length == 0) {
             return constants;
--- a/test/langtools/tools/javac/specialConstantFolding/IndyCrashTest.out	Thu Oct 26 22:06:04 2017 +0200
+++ b/test/langtools/tools/javac/specialConstantFolding/IndyCrashTest.out	Thu Oct 26 15:42:58 2017 -0700
@@ -1,2 +1,4 @@
+IndyCrashTest.java:26:57: compiler.warn.member.not.found.at.class: foo, IndyCrashTest.IntrinsicTestHelper
 IndyCrashTest.java:26:58: compiler.err.method.handle.not.suitable.indy: ()java.lang.invoke.CallSite
 1 error
+1 warning
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/specialConstantFolding/warningNotFoundOrIncorrect/WarningIfClassOrMemberNotFound.java	Thu Oct 26 15:42:58 2017 -0700
@@ -0,0 +1,28 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary warn if a class or member is not found at compile time
+ * @compile/fail/ref=WarningIfClassOrMemberNotFound.out -XDdoConstantFold -Werror -XDrawDiagnostics WarningIfClassOrMemberNotFound.java
+ */
+
+import java.lang.invoke.*;
+import static java.lang.invoke.Intrinsics.*;
+
+class WarningIfClassOrMemberNotFound {
+    void m() {
+        final MethodTypeRef mt1 = MethodTypeRef.of(ClassRef.ofDescriptor("Ljava/lang/String;"));
+        MethodHandle mh1 = ldc(MethodHandleRef.of(MethodHandleRef.Kind.STATIC, ClassRef.ofDescriptor("LNonExistentClass1;"), "foo", mt1));
+
+        ClassRef cr = ClassRef.ofDescriptor("LNonExistentClass2;");
+        Class<?> c = ldc(cr);
+
+        final MethodTypeRef mt2 = MethodTypeRef.of(ClassRef.ofDescriptor("Ljava/lang/String;"));
+        // now the class exists but the method doesn't
+        MethodHandle mh2 = ldc(MethodHandleRef.of(MethodHandleRef.Kind.STATIC, ClassRef.ofDescriptor("LWarningIfClassOrMemberNotFound;"), "bar", mt2));
+
+        final MethodTypeRef mt3 = MethodTypeRef.of(ClassRef.ofDescriptor("Ljava/lang/String;"));
+        // now the class exists and so is the method but the arguments are incorrect
+        MethodHandle mh3 = ldc(MethodHandleRef.of(MethodHandleRef.Kind.STATIC, ClassRef.ofDescriptor("LWarningIfClassOrMemberNotFound;"), "foo", mt3));
+    }
+
+    String foo(String s) { return s; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/specialConstantFolding/warningNotFoundOrIncorrect/WarningIfClassOrMemberNotFound.out	Thu Oct 26 15:42:58 2017 -0700
@@ -0,0 +1,7 @@
+WarningIfClassOrMemberNotFound.java:13:31: compiler.warn.class.not.found: NonExistentClass1
+WarningIfClassOrMemberNotFound.java:16:25: compiler.warn.class.not.found: NonExistentClass2
+WarningIfClassOrMemberNotFound.java:20:31: compiler.warn.member.not.found.at.class: bar, WarningIfClassOrMemberNotFound
+WarningIfClassOrMemberNotFound.java:24:31: compiler.warn.member.not.found.at.class: foo, WarningIfClassOrMemberNotFound
+- compiler.err.warnings.and.werror
+1 error
+4 warnings
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/specialConstantFolding/warningNotFoundOrIncorrect/WarningIfMemberIncorrect.java	Thu Oct 26 15:42:58 2017 -0700
@@ -0,0 +1,33 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary warn if a member is incorrect at compile time
+ * @compile/fail/ref=WarningIfMemberIncorrect.out -XDdoConstantFold -Werror -XDrawDiagnostics WarningIfMemberIncorrect.java
+ */
+
+import java.lang.invoke.*;
+import static java.lang.invoke.Intrinsics.*;
+
+class WarningIfMemberIncorrect {
+    interface I {
+        String foo();
+    }
+
+    void m() {
+        MethodTypeRef mtReturnString = MethodTypeRef.of(ClassRef.ofDescriptor("Ljava/lang/String;"));
+
+        // warn: the method is not static
+        MethodHandle mh1 = ldc(MethodHandleRef.of(MethodHandleRef.Kind.STATIC, ClassRef.ofDescriptor("LWarningIfMemberIncorrect;"), "foo", mtReturnString));
+
+        // warn: referring to a field not to a method plus a warning because the symbol has the wrong staticness
+        MethodHandle mh2 = ldc(MethodHandleRef.of(MethodHandleRef.Kind.STATIC, ClassRef.ofDescriptor("LWarningIfMemberIncorrect;"), "bar", mtReturnString));
+
+        // warn: wrong kind to refer to a constructor
+        MethodHandle mhConstructor = ldc(MethodHandleRef.of(MethodHandleRef.Kind.VIRTUAL, ClassRef.ofDescriptor("LWarningIfMemberIncorrect;"), "<init>",
+                                                                             MethodTypeRef.of(ClassRef.CR_void)));
+
+        MethodHandle mh3 = ldc(MethodHandleRef.of(MethodHandleRef.Kind.VIRTUAL, ClassRef.ofDescriptor("LWarningIfMemberIncorrect$I;"), "foo", mtReturnString));
+    }
+
+    String foo() { return null; }
+    String bar;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/specialConstantFolding/warningNotFoundOrIncorrect/WarningIfMemberIncorrect.out	Thu Oct 26 15:42:58 2017 -0700
@@ -0,0 +1,8 @@
+WarningIfMemberIncorrect.java:19:31: compiler.warn.incorrect.staticness.for.symbol: foo()
+WarningIfMemberIncorrect.java:22:31: compiler.warn.incorrect.staticness.for.symbol: bar
+WarningIfMemberIncorrect.java:22:31: compiler.warn.unexpected.kind.for.symbol: bar, MTH, VAR
+WarningIfMemberIncorrect.java:25:41: compiler.warn.incorrect.name.for.method: WarningIfMemberIncorrect(), 5
+WarningIfMemberIncorrect.java:28:31: compiler.warn.non.interface.owner.expected.for.symbol: foo()
+- compiler.err.warnings.and.werror
+1 error
+5 warnings