1
0
Fork 0
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:
Nathan Ridge 2014-03-22 02:55:38 -04:00 committed by Sergey Prigogin
parent 8be981a088
commit 6d82f0f7a4
19 changed files with 220 additions and 33 deletions

View file

@ -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();
}
}

View file

@ -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

View file

@ -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();
}
}

View file

@ -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) {

View file

@ -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) {

View file

@ -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) {

View file

@ -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) {

View file

@ -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) {

View file

@ -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;

View file

@ -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) {

View file

@ -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) {

View file

@ -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) {

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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) {

View file

@ -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

View file

@ -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) {

View file

@ -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)