Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Amend list initialization sequence #581

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -576,10 +576,12 @@ public void testConstructorCall() throws Exception {
ba.assertNoImplicitName("e;", 1);
IASTImplicitName s = ba.assertImplicitName("s =", 1, ICPPConstructor.class);
assertSame(ctor1, s.resolveBinding());
ba.assertNoImplicitName("t;", 1);
IASTImplicitName t_static = ba.assertImplicitName("t;", 1, ICPPConstructor.class);
assertSame(ctor0, t_static.resolveBinding());
IASTImplicitName t = ba.assertImplicitName("t =", 1, ICPPConstructor.class);
assertSame(ctor1, t.resolveBinding());
ba.assertNoImplicitName("u;", 1);
IASTImplicitName u_member = ba.assertImplicitName("u;", 1, ICPPConstructor.class);
assertSame(ctor0, u_member.resolveBinding());
IASTImplicitName u = ba.assertImplicitName("u()", 1, ICPPConstructor.class);
assertSame(ctor0, u.resolveBinding());
IASTImplicitName v = ba.assertImplicitName("v(p)", 1, ICPPConstructor.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8848,7 +8848,7 @@ public void testListInitialization_302412b() throws Exception {
// h({ "foo" }); // OK: h(C(std::string("foo")))
// i({ { 1, 2 }, { "bar" } }); // OK: i(D(A(std::initializer_list<int>{1,2}),C(std::string("bar"))))
// X x1;
// x({x1}); // no matching constructor
// x({x1}); // OK, lvalue reference to x1
// }
public void testListInitialization_302412c() throws Exception {
String code = getAboveComment();
Expand All @@ -8859,7 +8859,7 @@ public void testListInitialization_302412c() throws Exception {
bh.assertProblem("f({ 'a', 'b' })", 1);
bh.assertNonProblem("h({", 1);
bh.assertNonProblem("i({ { 1, 2 }, {", 1);
bh.assertProblem("x({x1})", 1);
bh.assertNonProblem("x({x1})", 1);
}

// namespace std {
Expand Down Expand Up @@ -9073,6 +9073,76 @@ public void testAggregateInitialization_487555() throws Exception {
parseAndCheckBindings();
}

// namespace std {
// template<typename T> class initializer_list;
// }
// struct str {
// str();
// str(const char*, int); // #1
// str(std::initializer_list<char>); // #2
// };
// struct subclass : public str {
// };
// void g1(str);
// void g2(str);
// void test() {
// const str a{"test", 4}; // OK, #2 fails, uses #1 to initialize
// const subclass s;
// g1({a});
// g2({s});
// }
public void testListInitializationOfClass() throws Exception {
parseAndCheckImplicitNameBindings();
}

// namespace std {
// template<typename T> class initializer_list;
// }
// struct str {
// str();
// explicit str(const char*, int); // #1
// str(std::initializer_list<char>); // #2
// };
//
// str test(char *p, int i) {
// const str a{"test", 4}; // OK, #2 fails, uses #1 to initialize
// const str b = {"test", 4}; // ERROR, #2 fails, #1 is skipped explicit conversion
// return str{p, i}; // OK, uses #1 to initialize, explicit constructor is considered too
// }
public void testListInitializationWithExplicitConstructor() throws Exception {
IASTTranslationUnit tu = parse(getAboveComment(), CPP);
NameCollector collector = new NameCollector(true);
tu.accept(collector);

assertEquals(28, collector.size());
// 23th is implicit name for constructor for b
IASTImplicitName nameOfConstructorForB = (IASTImplicitName) collector.getName(23);
IProblemBinding problemConstructorForB = (IProblemBinding) nameOfConstructorForB.resolveBinding();
assertEquals(problemConstructorForB.getID(), IProblemBinding.SEMANTIC_NAME_NOT_FOUND);

// 25th is implicit name for constructor of object in return statement
IASTImplicitName nameOfConstructorForReturn = (IASTImplicitName) collector.getName(25);
ICPPConstructor constructorOfReturn = (ICPPConstructor) nameOfConstructorForReturn.resolveBinding();
}

// namespace std {
// template<typename T> class initializer_list;
// }
// struct str {
// str();
// str(const char*, int); // #1
// str(std::initializer_list<char>); // #2
// };
//
// str test(char *p, int i) {
// const str a{"test", 4}; // OK, #2 fails, uses #1 to initialize
// const str b = {"test", 4}; // OK, #2 fails, uses #1 to initialize
// return str{p, i}; // OK, uses #1 to initialize
// }
public void testListInitializationOfClassTypeId() throws Exception {
parseAndCheckImplicitNameBindings();
}

// namespace std {
// template<typename T> class initializer_list;
// }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11607,4 +11607,14 @@ public void testResolveFunctionTemplateInDeferredBaseArg() throws Exception {
public void testRecognizeConstructorWithSemicolonAfterBody() throws Exception {
parseAndCheckImplicitNameBindings();
}

// template<typename T>
// void f() {
// struct S {
// T t;
// } s {};
// };
public void testAllowAggregateInitializationInTemplateBody() throws Exception {
parseAndCheckImplicitNameBindings();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IArrayType;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
Expand Down Expand Up @@ -147,13 +148,24 @@ public static IValue create(EvalInitList initList, ICompositeType type) {
ICPPEvaluation[] values = new ICPPEvaluation[fields.length];
ICPPEvaluation[] clauses = initList.getClauses();
for (int i = 0; i < fields.length; i++) {
if (i == clauses.length)
break;
IField field = fields[i];
ICPPEvaluation eval = clauses[i];
IType fieldType = field.getType();
IValue value = getValue(fieldType, eval);
values[i] = new EvalFixed(fieldType, eval.getValueCategory(), value);
IValue value;
ValueCategory valueCategory;
if (i < clauses.length) {
ICPPEvaluation eval = clauses[i];
value = getValue(fieldType, eval);
valueCategory = eval.getValueCategory();
} else {
// (dcl.init.aggr-7) from brace-or-equal-initializer or from {}
value = field.getInitialValue();
// Writing IntegralValue.UNKNOWN to PDOM stores null, convert it back
if (value == null || value == IntegralValue.UNKNOWN) {
value = IntegralValue.create(0);
}
valueCategory = ValueCategory.PRVALUE;
}
values[i] = new EvalFixed(fieldType, valueCategory, value);
}
return new CompositeValue(initList, values);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ private Cost checkImpl(IType target, EvalInitList list) throws DOMException {
* else recurses into the subaggregate.
*/
private Cost checkElement(IType type, IValue initialValue, Cost worstCost) throws DOMException {
assert !CPPTemplates.isDependentType(type);
if (CPPTemplates.isDependentType(type)) {
// We can only get here looking for initialization constructor while scanning for implicit names.
// Return trivial conversion cost and no constructor because type is unknown at this point.
return new Cost(type, type, Rank.IDENTITY);
}
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
Expand Down Expand Up @@ -99,7 +103,7 @@ private Cost checkElement(IType type, IValue initialValue, Cost worstCost) throw
}

Cost costWithoutElision = Conversions.checkImplicitConversionSequence(nestedType, initializer.getType(),
initializer.getValueCategory(), UDCMode.ALLOWED, Context.ORDINARY);
initializer.getValueCategory(), UDCMode.ALLOWED, Context.ORDINARY, false);
if (costWithoutElision.converts()) {
// p3: The elements of the initializer list are taken as initializers for the elements
// of the aggregate, in order.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ protected static ICPPEvaluation maybeApplyConversion(ICPPEvaluation argument, IT
ValueCategory valueCategory = argument.getValueCategory();
if (uqType instanceof ICPPClassType) {
Cost cost = Conversions.initializationByConversion(valueCategory, type, (ICPPClassType) uqType,
targetType, false, allowContextualConversion);
targetType, false, allowContextualConversion, false);
ICPPFunction conversion = cost.getUserDefinedConversion();
if (conversion != null) {
if (onlyConstexprConversion && !conversion.isConstexpr()) {
Expand All @@ -210,7 +210,7 @@ protected static ICPPEvaluation maybeApplyConversion(ICPPEvaluation argument, IT
// Source type is not a class type, or is but a conversion operator wasn't used.
// Check for standard conversions.
Cost cost = Conversions.checkImplicitConversionSequence(targetType, type, valueCategory, UDCMode.FORBIDDEN,
Context.ORDINARY);
Context.ORDINARY, false);
if (!cost.converts()) {
return EvalFixed.INCOMPLETE;
} else if (cost.getRank() == Rank.CONVERSION) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3169,7 +3169,14 @@ public static IBinding resolveFunction(LookupData data, ICPPFunction[] fns, bool

if (potentialCosts != null) {
for (FunctionCost fnCost : potentialCosts) {
if (!fnCost.mustBeWorse(bestFnCost) && fnCost.performUDC()) {
if (!fnCost.mustBeWorse(bestFnCost) && fnCost.performUDC(data.fNoNarrowing)) {
if (data.fNoNarrowing) {
for (int i = 0; i < fnCost.getLength(); ++i) {
if (fnCost.getCost(i).isNarrowingConversion()) {
continue;
}
}
}
int cmp = fnCost.compareTo(tu, bestFnCost, data.getFunctionArgumentCount());
if (cmp < 0) {
bestFnCost = fnCost;
Expand Down Expand Up @@ -3473,7 +3480,7 @@ private static FunctionCost costForFunctionCall(ICPPFunction fn, UDCMode udc, Lo
Context context = ftype.hasRefQualifier() ? Context.IMPLICIT_OBJECT_FOR_METHOD_WITH_REF_QUALIFIER
: Context.IMPLICIT_OBJECT_FOR_METHOD_WITHOUT_REF_QUALIFIER;
cost = Conversions.checkImplicitConversionSequence(implicitParameterType, impliedObjectType,
impliedObjectValueCategory, UDCMode.FORBIDDEN, context);
impliedObjectValueCategory, UDCMode.FORBIDDEN, context, data.fNoNarrowing);
if (cost.converts()) {
cost.setImpliedObject();
} else {
Expand Down Expand Up @@ -3530,7 +3537,9 @@ private static FunctionCost costForFunctionCall(ICPPFunction fn, UDCMode udc, Lo
}
}
}
cost = Conversions.checkImplicitConversionSequence(paramType, argType, argValueCategory, udc, ctx);
cost = Conversions.checkImplicitConversionSequence(paramType, argType, argValueCategory, udc, ctx,
data.fNoNarrowing);
// TODO: see if isNarrowingConversion() is re-checked while performing UDC again later
if (data.fNoNarrowing && cost.isNarrowingConversion()) {
cost = Cost.NO_CONVERSION;
}
Expand Down Expand Up @@ -4118,10 +4127,16 @@ public static IBinding findImplicitlyCalledConstructor(final ICPPASTDeclarator d
if (initializer == null) {
IASTDeclSpecifier declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier();
parent = parent.getParent();
if (parent instanceof IASTCompositeTypeSpecifier
// (c++11:class.base.init 12.6.2-8) [..no initializer..]
// if the entity is an anonymous union or a variant member, no initialization is performed
// otherwise the entity is default-initialized
// (c++11:dcl.init 8.5-7)
// if T is a (possibly cv-qualified) class type .. the default constructor for T is called
if ((parent instanceof IASTCompositeTypeSpecifier compositeType
&& compositeType.getKey() == ICompositeType.k_union)
|| declSpec.getStorageClass() == IASTDeclSpecifier.sc_extern) {
// No initialization is performed for class members and extern declarations
// without an initializer.
// No initialization is performed for class members which are of union type,
// and for extern declarations without an initializer.
return null;
}
}
Expand Down Expand Up @@ -4182,6 +4197,20 @@ public static IBinding findImplicitlyCalledConstructor(ICPPASTNewExpression expr
return null;
}

public static IBinding findConstructorForDirectListInitialization(ICPPClassType type, EvalInitList eval,
IASTNode typeId) throws DOMException {
Cost c = Conversions.listInitializationSequence(eval, type, UDCMode.ALLOWED, true);
if (c.converts()) {
ICPPFunction f = c.getUserDefinedConversion();
if (f instanceof ICPPConstructor) {
return f;
}
} else {
return new ProblemBinding(null, typeId, ISemanticProblem.BINDING_NOT_FOUND, type.getConstructors());
}
return null;
}

private static IBinding findImplicitlyCalledConstructor(ICPPClassType type, IASTInitializer initializer,
IASTNode typeId) {
pushLookupPoint(typeId);
Expand All @@ -4207,10 +4236,10 @@ private static IBinding findImplicitlyCalledConstructor(ICPPClassType type, IAST
}
Cost c;
if (calculateInheritanceDepth(sourceType, type) >= 0) {
c = Conversions.copyInitializationOfClass(isLValue, sourceType, type, false);
c = Conversions.copyInitializationOfClass(isLValue, sourceType, type, false, false);
} else {
c = Conversions.checkImplicitConversionSequence(type, sourceType, isLValue, UDCMode.ALLOWED,
Context.ORDINARY);
Context.ORDINARY, false);
}
if (c.converts()) {
ICPPFunction f = c.getUserDefinedConversion();
Expand All @@ -4225,7 +4254,7 @@ private static IBinding findImplicitlyCalledConstructor(ICPPClassType type, IAST
} else if (initializer instanceof ICPPASTInitializerList) {
// List initialization.
ICPPEvaluation eval = ((ICPPASTInitializerClause) initializer).getEvaluation();
if (eval instanceof EvalInitList) {
if (eval instanceof EvalInitList evalInitList) {
if (CPPTemplates.isDependentType(eval.getType())) {
ICPPEvaluation[] clauses = ((EvalInitList) eval).getClauses();
IType[] tmp = new IType[clauses.length];
Expand All @@ -4235,14 +4264,9 @@ private static IBinding findImplicitlyCalledConstructor(ICPPClassType type, IAST
setTargetedFunctionsToUnknown(tmp);
return CPPDeferredFunction.createForCandidates(type.getConstructors());
}
Cost c = Conversions.listInitializationSequence((EvalInitList) eval, type, UDCMode.ALLOWED, true);
if (c.converts()) {
ICPPFunction f = c.getUserDefinedConversion();
if (f instanceof ICPPConstructor)
return f;
} else {
return new ProblemBinding(null, typeId, ISemanticProblem.BINDING_NOT_FOUND,
type.getConstructors());
IBinding b = findConstructorForDirectListInitialization(type, evalInitList, typeId);
if (b != null) {
return b;
}
}
} else if (initializer instanceof ICPPASTConstructorInitializer) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2983,7 +2983,8 @@ private static ICPPTemplateArgument convertNonTypeTemplateArgument(ICPPTemplateD
}
}

Cost cost = Conversions.checkImplicitConversionSequence(p, a, LVALUE, UDCMode.FORBIDDEN, Context.ORDINARY);
Cost cost = Conversions.checkImplicitConversionSequence(p, a, LVALUE, UDCMode.FORBIDDEN, Context.ORDINARY,
false);
if (cost == null || !cost.converts()) {
ICPPEvaluation eval = arg.getNonTypeEvaluation();
ICPPEvaluation newEval = CPPEvaluation.maybeApplyConversion(eval, p, false, true);
Expand Down
Loading
Loading