mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-08 10:16:03 +02:00
Bug 486426 - Constexpr evaluation of function call with an argument requiring user-defined conversion
Change-Id: I1110b76d3520666a980100f6cd17689911a16759
This commit is contained in:
parent
57a47fe461
commit
36f16ba1b9
4 changed files with 55 additions and 21 deletions
|
@ -8803,6 +8803,22 @@ public class AST2TemplateTests extends AST2TestBase {
|
||||||
parseAndCheckBindings();
|
parseAndCheckBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// constexpr bool negate(bool arg) {
|
||||||
|
// return !arg;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// template <bool B>
|
||||||
|
// struct boolean {
|
||||||
|
// constexpr operator bool() { return B; }
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// constexpr bool waldo = negate(boolean<true>());
|
||||||
|
public void testDependentConversionOperator_486426() throws Exception {
|
||||||
|
BindingAssertionHelper helper = getAssertionHelper();
|
||||||
|
ICPPVariable waldo = helper.assertNonProblem("waldo");
|
||||||
|
assertConstantValue(0, waldo);
|
||||||
|
}
|
||||||
|
|
||||||
// template <typename>
|
// template <typename>
|
||||||
// struct C {
|
// struct C {
|
||||||
// friend bool operator==(C, C);
|
// friend bool operator==(C, C);
|
||||||
|
|
|
@ -13,9 +13,12 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
import org.eclipse.cdt.core.dom.ast.IValue;
|
import org.eclipse.cdt.core.dom.ast.IValue;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
|
||||||
|
@ -115,4 +118,34 @@ public abstract class CPPEvaluation implements ICPPEvaluation {
|
||||||
protected static boolean isNullOrConstexprFunc(ICPPFunction function) {
|
protected static boolean isNullOrConstexprFunc(ICPPFunction function) {
|
||||||
return function == null || function.isConstexpr();
|
return function == null || function.isConstexpr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a user-defined conversion is required to convert 'argument' to type 'targetType',
|
||||||
|
* return 'argument' wrapped in an evaluation representing the conversion.
|
||||||
|
* Otherwise, return 'argument' unmodified.
|
||||||
|
* @param point point of instantiation for name lookups
|
||||||
|
*/
|
||||||
|
protected static ICPPEvaluation maybeApplyConversion(ICPPEvaluation argument, IType targetType,
|
||||||
|
IASTNode point) {
|
||||||
|
IType type = argument.getType(point);
|
||||||
|
ValueCategory valueCategory = argument.getValueCategory(point);
|
||||||
|
ICPPFunction conversion = null;
|
||||||
|
if (type instanceof ICPPClassType) {
|
||||||
|
try {
|
||||||
|
Cost cost = Conversions.initializationByConversion(valueCategory, type, (ICPPClassType) type,
|
||||||
|
targetType, false, point);
|
||||||
|
conversion = cost.getUserDefinedConversion();
|
||||||
|
} catch (DOMException e) {
|
||||||
|
CCorePlugin.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (conversion != null) {
|
||||||
|
if (!conversion.isConstexpr()) {
|
||||||
|
return EvalFixed.INCOMPLETE;
|
||||||
|
}
|
||||||
|
ICPPEvaluation eval = new EvalBinding(conversion, null, (IBinding) null);
|
||||||
|
argument = new EvalFunctionCall(new ICPPEvaluation[] {eval, argument}, (IBinding) null);
|
||||||
|
}
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -247,11 +247,11 @@ public class EvalFunctionCall extends CPPDependentEvaluation {
|
||||||
ICPPEvaluation eval = CPPFunction.getReturnExpression(function, context.getPoint());
|
ICPPEvaluation eval = CPPFunction.getReturnExpression(function, context.getPoint());
|
||||||
if (eval == null)
|
if (eval == null)
|
||||||
return EvalFixed.INCOMPLETE;
|
return EvalFixed.INCOMPLETE;
|
||||||
CPPFunctionParameterMap parameterMap = buildParameterMap(function);
|
CPPFunctionParameterMap parameterMap = buildParameterMap(function, context.getPoint());
|
||||||
return eval.computeForFunctionCall(parameterMap, context.recordStep());
|
return eval.computeForFunctionCall(parameterMap, context.recordStep());
|
||||||
}
|
}
|
||||||
|
|
||||||
private CPPFunctionParameterMap buildParameterMap(ICPPFunction function) {
|
private CPPFunctionParameterMap buildParameterMap(ICPPFunction function, IASTNode point) {
|
||||||
ICPPParameter[] parameters = function.getParameters();
|
ICPPParameter[] parameters = function.getParameters();
|
||||||
CPPFunctionParameterMap map = new CPPFunctionParameterMap(parameters.length);
|
CPPFunctionParameterMap map = new CPPFunctionParameterMap(parameters.length);
|
||||||
int j = 1;
|
int j = 1;
|
||||||
|
@ -262,7 +262,8 @@ public class EvalFunctionCall extends CPPDependentEvaluation {
|
||||||
j = fArguments.length;
|
j = fArguments.length;
|
||||||
} else {
|
} else {
|
||||||
if (j < fArguments.length) {
|
if (j < fArguments.length) {
|
||||||
map.put(i, fArguments[j++]);
|
ICPPEvaluation argument = maybeApplyConversion(fArguments[j++], param.getType(), point);
|
||||||
|
map.put(i, argument);
|
||||||
} else if (param.hasDefaultValue()) {
|
} else if (param.hasDefaultValue()) {
|
||||||
IValue value = param.getDefaultValue();
|
IValue value = param.getDefaultValue();
|
||||||
ICPPEvaluation eval = value.getEvaluation();
|
ICPPEvaluation eval = value.getEvaluation();
|
||||||
|
|
|
@ -37,7 +37,6 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF;
|
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF;
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
|
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
|
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
|
@ -47,7 +46,6 @@ import org.eclipse.cdt.core.dom.ast.IPointerType;
|
||||||
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
|
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
|
||||||
import org.eclipse.cdt.core.dom.ast.IType;
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
import org.eclipse.cdt.core.dom.ast.IValue;
|
import org.eclipse.cdt.core.dom.ast.IValue;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
|
||||||
|
@ -285,22 +283,8 @@ public class EvalUnary extends CPPDependentEvaluation {
|
||||||
if (overload != null) {
|
if (overload != null) {
|
||||||
ICPPFunctionType functionType = overload.getType();
|
ICPPFunctionType functionType = overload.getType();
|
||||||
IType targetType = functionType.getParameterTypes()[0];
|
IType targetType = functionType.getParameterTypes()[0];
|
||||||
ValueCategory valueCategory = fArgument.getValueCategory(point);
|
arg = maybeApplyConversion(arg, targetType, point);
|
||||||
IType type = fArgument.getType(point);
|
|
||||||
ICPPFunction conversion = null;
|
|
||||||
try {
|
|
||||||
Cost cost = Conversions.initializationByConversion(valueCategory, type, (ICPPClassType) type, targetType, false, point);
|
|
||||||
conversion = cost.getUserDefinedConversion();
|
|
||||||
} catch (DOMException e) {
|
|
||||||
CCorePlugin.log(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conversion != null) {
|
|
||||||
if (!conversion.isConstexpr())
|
|
||||||
return Value.ERROR;
|
|
||||||
ICPPEvaluation eval = new EvalBinding(conversion, null, (IBinding) null);
|
|
||||||
arg = new EvalFunctionCall(new ICPPEvaluation[] {eval, arg}, (IBinding) null);
|
|
||||||
}
|
|
||||||
if (!(overload instanceof CPPImplicitFunction)) {
|
if (!(overload instanceof CPPImplicitFunction)) {
|
||||||
if (!overload.isConstexpr())
|
if (!overload.isConstexpr())
|
||||||
return Value.ERROR;
|
return Value.ERROR;
|
||||||
|
|
Loading…
Add table
Reference in a new issue