mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 429891 - Do not attempt to evaluate a constexpr function call if the
arguments are not constant expressions Change-Id: I7f7e5cfd1e581c168bfcc65222e9ef87a15a8e4f Signed-off-by: Nathan Ridge <zeratul976@hotmail.com> Reviewed-on: https://git.eclipse.org/r/23744 Reviewed-by: Sergey Prigogin <eclipse.sprigogin@gmail.com> IP-Clean: Sergey Prigogin <eclipse.sprigogin@gmail.com> Tested-by: Sergey Prigogin <eclipse.sprigogin@gmail.com>
This commit is contained in:
parent
8be981a088
commit
6d82f0f7a4
19 changed files with 220 additions and 33 deletions
|
@ -8454,4 +8454,27 @@ public class AST2TemplateTests extends AST2TestBase {
|
|||
ICPPVariable waldo = helper.assertNonProblem("waldo");
|
||||
assertEquals(2, waldo.getInitialValue().numericalValue().longValue());
|
||||
}
|
||||
|
||||
// struct Test {
|
||||
// static constexpr unsigned calc_sig(const char *s, unsigned n) {
|
||||
// return (n == 0 || *s == '\0' ? 0 :
|
||||
// n > 1 && *s == '%' && s[1] == '%' ?
|
||||
// calc_sig(s + 2, n - 2) :
|
||||
// calc_sig(s + 1, n - 1));
|
||||
// }
|
||||
//
|
||||
// template<unsigned sig, class ... T>
|
||||
// static void validate_sig();
|
||||
//
|
||||
// template<class ... T>
|
||||
// static inline constexpr bool validate(const char *s, unsigned n) {
|
||||
// constexpr auto sig = calc_sig(s, n);
|
||||
// validate_sig<sig, T...>();
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// };
|
||||
public void testConstexprFunctionCallWithNonConstexprArguments_429891() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,13 @@ public interface ICPPEvaluation extends ISerializableEvaluation {
|
|||
* Returns {@code true} if the value of the expression depends on template parameters.
|
||||
*/
|
||||
boolean isValueDependent();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the expression is a compile-time constant expression.
|
||||
*
|
||||
* @param point the point of instantiation, determines the scope for name lookups
|
||||
*/
|
||||
boolean isConstantExpression(IASTNode point);
|
||||
|
||||
/**
|
||||
* Returns the type of the expression, or a {@code FunctionSetType} if the expression evaluates
|
||||
|
|
|
@ -15,7 +15,9 @@ import org.eclipse.cdt.core.CCorePlugin;
|
|||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IValue;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
|
||||
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.ICPPTemplateParameterMap;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
||||
|
@ -74,7 +76,7 @@ public abstract class CPPEvaluation implements ICPPEvaluation {
|
|||
return binding;
|
||||
}
|
||||
|
||||
public static boolean containsDependentType(ICPPEvaluation[] evaluations) {
|
||||
protected static boolean containsDependentType(ICPPEvaluation[] evaluations) {
|
||||
for (ICPPEvaluation eval : evaluations) {
|
||||
if (eval.isTypeDependent())
|
||||
return true;
|
||||
|
@ -82,11 +84,35 @@ public abstract class CPPEvaluation implements ICPPEvaluation {
|
|||
return false;
|
||||
}
|
||||
|
||||
public static boolean containsDependentValue(ICPPEvaluation[] evaluations) {
|
||||
protected static boolean containsDependentValue(ICPPEvaluation[] evaluations) {
|
||||
for (ICPPEvaluation eval : evaluations) {
|
||||
if (eval.isValueDependent())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static boolean areAllConstantExpressions(ICPPEvaluation[] evaluations, IASTNode point) {
|
||||
for (ICPPEvaluation eval : evaluations) {
|
||||
if (!eval.isConstantExpression(point)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static boolean isConstexprValue(IValue value, IASTNode point) {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
ICPPEvaluation innerEval = value.getEvaluation();
|
||||
if (innerEval == null) {
|
||||
return value.numericalValue() != null;
|
||||
}
|
||||
return innerEval.isConstantExpression(point);
|
||||
}
|
||||
|
||||
protected static boolean isConstexprFuncOrNull(ICPPFunction function) {
|
||||
return function == null || function.isConstexpr();
|
||||
}
|
||||
}
|
|
@ -186,6 +186,13 @@ public class EvalBinary extends CPPDependentEvaluation {
|
|||
public boolean isValueDependent() {
|
||||
return fArg1.isValueDependent() || fArg2.isValueDependent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return fArg1.isConstantExpression(point)
|
||||
&& fArg2.isConstantExpression(point)
|
||||
&& isConstexprFuncOrNull(getOverload(point));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueCategory getValueCategory(IASTNode point) {
|
||||
|
|
|
@ -102,6 +102,11 @@ public class EvalBinaryTypeId extends CPPDependentEvaluation {
|
|||
}
|
||||
return fIsValueDependent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueCategory getValueCategory(IASTNode point) {
|
||||
|
|
|
@ -237,6 +237,13 @@ public class EvalBinding extends CPPDependentEvaluation {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return fBinding instanceof IEnumerator
|
||||
|| fBinding instanceof ICPPFunction
|
||||
|| (fBinding instanceof IVariable && isConstexprValue(((IVariable) fBinding).getInitialValue(), point));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType getTypeOrFunctionSet(IASTNode point) {
|
||||
|
|
|
@ -72,6 +72,19 @@ public class EvalComma extends CPPDependentEvaluation {
|
|||
public boolean isValueDependent() {
|
||||
return containsDependentValue(fArguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
if (!areAllConstantExpressions(fArguments, point)) {
|
||||
return false;
|
||||
}
|
||||
for (ICPPFunction overload : fOverloads) {
|
||||
if (!isConstexprFuncOrNull(overload)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public ICPPFunction[] getOverloads(IASTNode point) {
|
||||
if (fOverloads == null) {
|
||||
|
|
|
@ -64,6 +64,11 @@ public class EvalCompound extends CPPDependentEvaluation {
|
|||
public boolean isValueDependent() {
|
||||
return fDelegate.isValueDependent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return fDelegate.isConstantExpression(point);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType getTypeOrFunctionSet(IASTNode point) {
|
||||
|
|
|
@ -147,6 +147,13 @@ public class EvalConditional extends CPPDependentEvaluation {
|
|||
|| fNegative.isValueDependent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return fCondition.isConstantExpression(point)
|
||||
&& (fPositive == null || fPositive.isConstantExpression(point))
|
||||
&& fNegative.isConstantExpression(point);
|
||||
}
|
||||
|
||||
private void evaluate(IASTNode point) {
|
||||
if (fValueCategory != null)
|
||||
return;
|
||||
|
|
|
@ -97,6 +97,11 @@ public class EvalFixed extends CPPEvaluation {
|
|||
}
|
||||
return fIsValueDependent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return isConstexprValue(fValue, point);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType getTypeOrFunctionSet(IASTNode point) {
|
||||
|
|
|
@ -84,6 +84,12 @@ public class EvalFunctionCall extends CPPDependentEvaluation {
|
|||
return containsDependentValue(fArguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return areAllConstantExpressions(fArguments, point)
|
||||
&& isConstexprFuncOrNull(getOverload(point));
|
||||
}
|
||||
|
||||
public ICPPFunction getOverload(IASTNode point) {
|
||||
if (fOverload == CPPFunction.UNINITIALIZED_FUNCTION) {
|
||||
fOverload= computeOverload(point);
|
||||
|
@ -223,6 +229,10 @@ public class EvalFunctionCall extends CPPDependentEvaluation {
|
|||
private ICPPEvaluation computeForFunctionCall(int maxdepth, IASTNode point) {
|
||||
if (isValueDependent())
|
||||
return this;
|
||||
// If the arguments are not all constant expressions, there is
|
||||
// no point trying to substitute them into the return expression.
|
||||
if (!areAllConstantExpressions(fArguments, point))
|
||||
return this;
|
||||
ICPPFunction function = getOverload(point);
|
||||
if (function == null) {
|
||||
if (fArguments[0] instanceof EvalBinding) {
|
||||
|
|
|
@ -131,6 +131,16 @@ public class EvalFunctionSet extends CPPDependentEvaluation {
|
|||
public boolean isValueDependent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
for (ICPPFunction f : fFunctionSet.getBindings()) {
|
||||
if (!f.isConstexpr()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType getTypeOrFunctionSet(IASTNode point) {
|
||||
|
|
|
@ -132,6 +132,11 @@ public class EvalID extends CPPDependentEvaluation {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType getTypeOrFunctionSet(IASTNode point) {
|
||||
return new TypeOfDependentExpression(this);
|
||||
|
|
|
@ -57,20 +57,17 @@ public class EvalInitList extends CPPDependentEvaluation {
|
|||
|
||||
@Override
|
||||
public boolean isTypeDependent() {
|
||||
for (ICPPEvaluation clause : fClauses) {
|
||||
if (clause.isTypeDependent())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return containsDependentType(fClauses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueDependent() {
|
||||
for (ICPPEvaluation clause : fClauses) {
|
||||
if (clause.isValueDependent())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return containsDependentValue(fClauses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return areAllConstantExpressions(fClauses, point);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -139,7 +139,7 @@ public class EvalMemberAccess extends CPPDependentEvaluation {
|
|||
}
|
||||
return fIsValueDependent;
|
||||
}
|
||||
|
||||
|
||||
private boolean computeIsValueDependent() {
|
||||
if (fMember instanceof ICPPUnknownBinding) {
|
||||
return true;
|
||||
|
@ -156,6 +156,15 @@ public class EvalMemberAccess extends CPPDependentEvaluation {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
// TODO(nathanridge):
|
||||
// This could be a constant expression if the field owner
|
||||
// is a constant expression, but we don't have access to
|
||||
// the field owner's evaluation, only its type.
|
||||
return false;
|
||||
}
|
||||
|
||||
public static IType getFieldOwnerType(IType fieldOwnerExpressionType, boolean isDeref, IASTNode point, Collection<ICPPFunction> functionBindings,
|
||||
boolean returnUnnamed) {
|
||||
IType type= fieldOwnerExpressionType;
|
||||
|
|
|
@ -66,6 +66,11 @@ public class EvalParameterPack extends CPPDependentEvaluation {
|
|||
return fExpansionPattern.isValueDependent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType getTypeOrFunctionSet(IASTNode point) {
|
||||
if (fType == null) {
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
|
|||
import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.Value;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
||||
|
@ -43,6 +44,10 @@ public class EvalTypeId extends CPPDependentEvaluation {
|
|||
private final ICPPEvaluation[] fArguments;
|
||||
private final boolean fRepresentsNewExpression;
|
||||
private IType fOutputType;
|
||||
|
||||
private ICPPFunction fConstructor = CPPFunction.UNINITIALIZED_FUNCTION;
|
||||
private boolean fCheckedIsTypeDependent;
|
||||
private boolean fIsTypeDependent;
|
||||
|
||||
public EvalTypeId(IType type, IASTNode pointOfDefinition, ICPPEvaluation... arguments) {
|
||||
this(type, findEnclosingTemplate(pointOfDefinition), false, arguments);
|
||||
|
@ -93,7 +98,7 @@ public class EvalTypeId extends CPPDependentEvaluation {
|
|||
}
|
||||
|
||||
private IType computeType() {
|
||||
if (CPPTemplates.isDependentType(fInputType) || containsDependentType(fArguments))
|
||||
if (isTypeDependent())
|
||||
return new TypeOfDependentExpression(this);
|
||||
|
||||
IType type = typeFromReturnType(fInputType);
|
||||
|
@ -121,10 +126,11 @@ public class EvalTypeId extends CPPDependentEvaluation {
|
|||
|
||||
@Override
|
||||
public boolean isTypeDependent() {
|
||||
if (fOutputType == null) {
|
||||
fOutputType= computeType();
|
||||
if (!fCheckedIsTypeDependent) {
|
||||
fCheckedIsTypeDependent = true;
|
||||
fIsTypeDependent = CPPTemplates.isDependentType(fInputType) || containsDependentType(fArguments);
|
||||
}
|
||||
return fOutputType instanceof TypeOfDependentExpression;
|
||||
return fIsTypeDependent;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -136,10 +142,47 @@ public class EvalTypeId extends CPPDependentEvaluation {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return !fRepresentsNewExpression
|
||||
&& areAllConstantExpressions(fArguments, point)
|
||||
&& isConstexprFuncOrNull(getConstructor(point));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueCategory getValueCategory(IASTNode point) {
|
||||
return valueCategoryFromReturnType(fInputType);
|
||||
}
|
||||
|
||||
public ICPPFunction getConstructor(IASTNode point) {
|
||||
if (fConstructor == CPPFunction.UNINITIALIZED_FUNCTION) {
|
||||
fConstructor = computeConstructor(point);
|
||||
}
|
||||
return fConstructor;
|
||||
}
|
||||
|
||||
private ICPPFunction computeConstructor(IASTNode point) {
|
||||
if (isTypeDependent())
|
||||
return null;
|
||||
|
||||
IType simplifiedType = SemanticUtil.getNestedType(fInputType, SemanticUtil.TDEF);
|
||||
if (simplifiedType instanceof ICPPClassType) {
|
||||
ICPPClassType classType = (ICPPClassType) simplifiedType;
|
||||
LookupData data = new LookupData(classType.getNameCharArray(), null, point);
|
||||
ICPPConstructor[] constructors = ClassTypeHelper.getConstructors(classType, point);
|
||||
data.foundItems = constructors;
|
||||
data.setFunctionArguments(false, fArguments);
|
||||
try {
|
||||
IBinding binding = CPPSemantics.resolveFunction(data, constructors, true);
|
||||
if (binding instanceof ICPPFunction) {
|
||||
return (ICPPFunction) binding;
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
CCorePlugin.log(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
|
||||
|
@ -177,30 +220,22 @@ public class EvalTypeId extends CPPDependentEvaluation {
|
|||
IType type = CPPTemplates.instantiateType(fInputType, tpMap, packOffset, within, point);
|
||||
if (args == fArguments && type == fInputType)
|
||||
return this;
|
||||
|
||||
if (!CPPTemplates.isDependentType(type) && !containsDependentType(args)) {
|
||||
|
||||
EvalTypeId result = new EvalTypeId(type, getTemplateDefinition(), fRepresentsNewExpression, args);
|
||||
|
||||
if (!result.isTypeDependent()) {
|
||||
IType simplifiedType = SemanticUtil.getNestedType(type, SemanticUtil.TDEF);
|
||||
if (simplifiedType instanceof ICPPClassType) {
|
||||
// Check the constructor call and return EvalFixed.INCOMPLETE to indicate a substitution
|
||||
// failure if the call cannot be resolved.
|
||||
ICPPClassType classType = (ICPPClassType) type;
|
||||
LookupData data = new LookupData(classType.getNameCharArray(), null, point);
|
||||
ICPPConstructor[] constructors = ClassTypeHelper.getConstructors(classType, point);
|
||||
data.foundItems = constructors;
|
||||
data.setFunctionArguments(false, args);
|
||||
try {
|
||||
IBinding binding = CPPSemantics.resolveFunction(data, constructors, true);
|
||||
if (binding == null || binding instanceof IProblemBinding ||
|
||||
binding instanceof ICPPFunction && ((ICPPFunction) binding).isDeleted()) {
|
||||
return EvalFixed.INCOMPLETE;
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
CCorePlugin.log(e);
|
||||
ICPPFunction constructor = result.getConstructor(point);
|
||||
if (constructor == null || constructor instanceof IProblemBinding || constructor.isDeleted()) {
|
||||
return EvalFixed.INCOMPLETE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new EvalTypeId(type, getTemplateDefinition(), fRepresentsNewExpression, args);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -144,6 +144,12 @@ public class EvalUnary extends CPPDependentEvaluation {
|
|||
return fArgument.isValueDependent();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return fArgument.isConstantExpression(point)
|
||||
&& isConstexprFuncOrNull(getOverload(point));
|
||||
}
|
||||
|
||||
public ICPPFunction getOverload(IASTNode point) {
|
||||
if (fOverload == CPPFunction.UNINITIALIZED_FUNCTION) {
|
||||
|
|
|
@ -126,6 +126,11 @@ public class EvalUnaryTypeID extends CPPDependentEvaluation {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression(IASTNode point) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType getTypeOrFunctionSet(IASTNode point) {
|
||||
if (fType == null)
|
||||
|
|
Loading…
Add table
Reference in a new issue