diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 65939ef7e74..b2f01c2a8d9 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -658,6 +658,22 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record { throw new AutoClonetypeException(s"Unable to automatically infer cloneType on $clazz: $desc") } + def validateClone(clone: Bundle, equivDiagnostic: String): Unit = { + if (!clone.typeEquivalent(this)) { + autoClonetypeError(s"Automatically cloned $clone not type-equivalent to base $this. " + equivDiagnostic) + } + + for ((name, field) <- elements) { + if (clone.elements(name) eq field) { + autoClonetypeError(s"Automatically cloned $clone has field $name aliased with base $this." + + " In the future, this can be solved by wrapping the field in Field(...)," + + " see https://github.com/freechipsproject/chisel3/pull/909." + + " For now, ensure Chisel types used in the Bundle definition are passed through constructor arguments," + + " or wrapped in Input(...), Output(...), or Flipped(...) if appropriate.") + } + } + } + val mirror = runtimeMirror(clazz.getClassLoader) val classSymbolOption = try { Some(mirror.reflect(this).symbol) @@ -741,10 +757,7 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record { clone match { case Some(clone) => clone._outerInst = this._outerInst - if (!clone.typeEquivalent(this)) { - autoClonetypeError(s"automatically cloned $clone not type-equivalent to base." + - " Constructor argument values were not inferred, ensure constructor is deterministic.") - } + validateClone(clone, "Constructor argument values were not inferred, ensure constructor is deterministic.") return clone.asInstanceOf[this.type] case None => } @@ -781,6 +794,8 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record { try { val clone = ctors.head.newInstance(outerClassInstance.get._2).asInstanceOf[this.type] clone._outerInst = this._outerInst + + validateClone(clone, "Outer class instance was inferred, ensure constructor is deterministic.") return clone } catch { case e @ (_: java.lang.reflect.InvocationTargetException | _: IllegalArgumentException) => @@ -844,14 +859,11 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record { val clone = classMirror.reflectConstructor(ctor).apply(ctorParamsVals:_*).asInstanceOf[this.type] clone._outerInst = this._outerInst - if (!clone.typeEquivalent(this)) { - // scalastyle:off line.size.limit - autoClonetypeError(s"Automatically cloned $clone not type-equivalent to base $this." + - " Constructor argument values were inferred: ensure that variable names are consistent and have the same value throughout the constructor chain," + - " and that the constructor is deterministic.") - // scalastyle:on line.size.limit - } - + validateClone(clone, + "Constructor argument values were inferred:" + + " ensure that variable names are consistent and have the same value throughout the constructor chain," + + " and that the constructor is deterministic." + ) clone } diff --git a/src/test/scala/chiselTests/AutoClonetypeSpec.scala b/src/test/scala/chiselTests/AutoClonetypeSpec.scala index 75fb46b83bf..e533eb94e41 100644 --- a/src/test/scala/chiselTests/AutoClonetypeSpec.scala +++ b/src/test/scala/chiselTests/AutoClonetypeSpec.scala @@ -172,4 +172,29 @@ class AutoClonetypeSpec extends ChiselFlatSpec { val a = WireDefault(io) } } } + + "Aliased fields" should "be caught" in { + a [ChiselException] should be thrownBy { + elaborate { new Module { + val bundleFieldType = UInt(8.W) + val io = IO(Output(new Bundle { + val a = bundleFieldType + })) + io.a := 0.U + } } + } + } + + "Aliased fields from inadequate autoclonetype" should "be caught" in { + a [ChiselException] should be thrownBy { + class BadBundle(val typeTuple: (Data, Int)) extends Bundle { + val a = typeTuple._1 + } + + elaborate { new Module { + val io = IO(Output(new BadBundle(UInt(8.W), 1))) + io.a := 0.U + } } + } + } }