From d9550199f882e71343e3e2caa1e2c12360b84c64 Mon Sep 17 00:00:00 2001 From: Hannes Vogt Date: Thu, 28 Mar 2019 08:10:34 +0100 Subject: [PATCH] Bug 545756 - Aggregate: init char array from literal Implement [dcl.init.string] in aggregate initialization Change-Id: Ib6cf51cf08885dbfc281814c6521da3579301492 Signed-off-by: Hannes Vogt --- .../core/parser/tests/ast2/AST2CPPTests.java | 39 ++++++++++ .../semantics/AggregateInitialization.java | 72 +++++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index a1bdad7bcc1..fc1f30c02c7 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -13049,4 +13049,43 @@ public class AST2CPPTests extends AST2CPPTestBase { BindingAssertionHelper bh = getAssertionHelper(); bh.assertImplicitName("b{v};", 1, IProblemBinding.class); } + + // struct type { + // char data[2]; + // }; + // + // type foo{"s"}; + public void testCharArrayInitFromStringLiteral_545756() throws Exception { + parseAndCheckImplicitNameBindings(); + } + + // struct type { + // char data[3]; + // }; + // + // type foo{"big"}; + public void testCharArrayInitFromTooLargeStringLiteral_545756() throws Exception { + BindingAssertionHelper bh = getAssertionHelper(); + bh.assertImplicitName("foo", 3, IProblemBinding.class); + } + + // struct type { + // char data[2]; + // }; + // + // type foo{L"s"}; + public void testCharArrayInitFromWrongTypeStringLiteral_545756() throws Exception { + BindingAssertionHelper bh = getAssertionHelper(); + bh.assertImplicitName("foo", 3, IProblemBinding.class); + } + + // struct type { + // const char data[]; + // }; + // + // type foo{"s"}; + public void testUnknownSizeCharArrayInitFromStringLiteral_545756() throws Exception { + BindingAssertionHelper bh = getAssertionHelper(); + bh.assertImplicitName("foo", 3, IProblemBinding.class); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/AggregateInitialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/AggregateInitialization.java index 292a6886bf7..64648a5231e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/AggregateInitialization.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/AggregateInitialization.java @@ -11,12 +11,15 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IArrayType; +import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.parser.util.ArrayUtil; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode; @@ -60,6 +63,7 @@ class AggregateInitialization { * else recurses into the subaggregate. */ private Cost checkElement(IType type, IValue initialValue, Cost worstCost) throws DOMException { + assert !CPPTemplates.isDependentType(type); IType nestedType = SemanticUtil.getNestedType(type, SemanticUtil.TDEF); if (fIndex >= fInitializers.length) // TODO for arrays we could short-circuit default init instead of trying to init each element @@ -67,6 +71,30 @@ class AggregateInitialization { worstCost = new Cost(fInitializers[fIndex].getType(), nestedType, Rank.IDENTITY); ICPPEvaluation initializer = fInitializers[fIndex]; + if (initFromStringLiteral(nestedType, initializer)) { + // [dcl.init.string] + fIndex++; + Number sizeOfCharArrayNumber = getArraySize(nestedType); + long sizeofCharArray = 0; // will error in case we cannot determine the size + if (sizeOfCharArrayNumber != null) { + sizeofCharArray = sizeOfCharArrayNumber.longValue(); + } + Number sizeofStringLiteralNumber = getArraySize(initializer.getType()); + long sizeofStringLiteral = Long.MAX_VALUE; // will error in case we cannot determine the size + if (sizeofStringLiteralNumber != null) { + sizeofStringLiteral = sizeofStringLiteralNumber.longValue(); + } + IType targetCharType = getBasicTypeFromArray(nestedType); + IType literalCharType = getBasicTypeFromArray(initializer.getType()); + Cost cost; + if (sizeofCharArray >= sizeofStringLiteral && targetCharType.isSameType(literalCharType)) { + cost = new Cost(initializer.getType(), nestedType, Rank.CONVERSION); + } else { + cost = Cost.NO_CONVERSION; + } + return cost; + } + Cost costWithoutElision = Conversions.checkImplicitConversionSequence(nestedType, initializer.getType(), initializer.getValueCategory(), UDCMode.ALLOWED, Context.ORDINARY); if (costWithoutElision.converts()) { @@ -179,4 +207,48 @@ class AggregateInitialization { return ArrayUtil.trim(result); } + /** + * @param type + * @return CPPBasicType of element; null if type is not IArrayType or element is not CPPBasicType + */ + private static ICPPBasicType getBasicTypeFromArray(IType type) { + if (type instanceof IArrayType) { + IType nested = SemanticUtil.getNestedType(((IArrayType) type).getType(), SemanticUtil.ALLCVQ); + if (nested instanceof ICPPBasicType) { + return (ICPPBasicType) nested; + } + } + return null; + } + + private static boolean isCharArray(IType target) { + ICPPBasicType t = getBasicTypeFromArray(target); + if (t != null) { + Kind k = t.getKind(); + return k == Kind.eChar || k == Kind.eChar16 || k == Kind.eChar32 || k == Kind.eWChar; + } + return false; + } + + private static boolean fromStringLiteral(ICPPEvaluation initializer) { + ICPPBasicType t = getBasicTypeFromArray(initializer.getType()); + if (t != null && t instanceof CPPBasicType) { + return ((CPPBasicType) t).isFromStringLiteral(); + } + return false; + } + + private static boolean initFromStringLiteral(IType target, ICPPEvaluation initializer) { + return isCharArray(target) && fromStringLiteral(initializer); + } + + private static Number getArraySize(IType type) { + if (((IArrayType) type).getSize() != null) { + IValue size = ((IArrayType) type).getSize(); + if (size.numberValue() != null) { + return ((IArrayType) type).getSize().numberValue(); + } + } + return null; + } } \ No newline at end of file