1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-07 17:56: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"); ICPPVariable waldo = helper.assertNonProblem("waldo");
assertEquals(2, waldo.getInitialValue().numericalValue().longValue()); 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

@ -41,6 +41,13 @@ public interface ICPPEvaluation extends ISerializableEvaluation {
*/ */
boolean isValueDependent(); 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 * Returns the type of the expression, or a {@code FunctionSetType} if the expression evaluates
* to a function set. * to a function set.

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.DOMException;
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.IValue;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; 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.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
@ -74,7 +76,7 @@ public abstract class CPPEvaluation implements ICPPEvaluation {
return binding; return binding;
} }
public static boolean containsDependentType(ICPPEvaluation[] evaluations) { protected static boolean containsDependentType(ICPPEvaluation[] evaluations) {
for (ICPPEvaluation eval : evaluations) { for (ICPPEvaluation eval : evaluations) {
if (eval.isTypeDependent()) if (eval.isTypeDependent())
return true; return true;
@ -82,11 +84,35 @@ public abstract class CPPEvaluation implements ICPPEvaluation {
return false; return false;
} }
public static boolean containsDependentValue(ICPPEvaluation[] evaluations) { protected static boolean containsDependentValue(ICPPEvaluation[] evaluations) {
for (ICPPEvaluation eval : evaluations) { for (ICPPEvaluation eval : evaluations) {
if (eval.isValueDependent()) if (eval.isValueDependent())
return true; return true;
} }
return false; 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

@ -187,6 +187,13 @@ public class EvalBinary extends CPPDependentEvaluation {
return fArg1.isValueDependent() || fArg2.isValueDependent(); return fArg1.isValueDependent() || fArg2.isValueDependent();
} }
@Override
public boolean isConstantExpression(IASTNode point) {
return fArg1.isConstantExpression(point)
&& fArg2.isConstantExpression(point)
&& isConstexprFuncOrNull(getOverload(point));
}
@Override @Override
public ValueCategory getValueCategory(IASTNode point) { public ValueCategory getValueCategory(IASTNode point) {
if (isTypeDependent()) if (isTypeDependent())

View file

@ -103,6 +103,11 @@ public class EvalBinaryTypeId extends CPPDependentEvaluation {
return fIsValueDependent; return fIsValueDependent;
} }
@Override
public boolean isConstantExpression(IASTNode point) {
return true;
}
@Override @Override
public ValueCategory getValueCategory(IASTNode point) { public ValueCategory getValueCategory(IASTNode point) {
return PRVALUE; return PRVALUE;

View file

@ -238,6 +238,13 @@ public class EvalBinding extends CPPDependentEvaluation {
return false; return false;
} }
@Override
public boolean isConstantExpression(IASTNode point) {
return fBinding instanceof IEnumerator
|| fBinding instanceof ICPPFunction
|| (fBinding instanceof IVariable && isConstexprValue(((IVariable) fBinding).getInitialValue(), point));
}
@Override @Override
public IType getTypeOrFunctionSet(IASTNode point) { public IType getTypeOrFunctionSet(IASTNode point) {
if (fType == null) { if (fType == null) {

View file

@ -73,6 +73,19 @@ public class EvalComma extends CPPDependentEvaluation {
return containsDependentValue(fArguments); 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) { public ICPPFunction[] getOverloads(IASTNode point) {
if (fOverloads == null) { if (fOverloads == null) {
fOverloads= computeOverloads(point); fOverloads= computeOverloads(point);

View file

@ -65,6 +65,11 @@ public class EvalCompound extends CPPDependentEvaluation {
return fDelegate.isValueDependent(); return fDelegate.isValueDependent();
} }
@Override
public boolean isConstantExpression(IASTNode point) {
return fDelegate.isConstantExpression(point);
}
@Override @Override
public IType getTypeOrFunctionSet(IASTNode point) { public IType getTypeOrFunctionSet(IASTNode point) {
return fDelegate.getTypeOrFunctionSet(point); return fDelegate.getTypeOrFunctionSet(point);

View file

@ -147,6 +147,13 @@ public class EvalConditional extends CPPDependentEvaluation {
|| fNegative.isValueDependent(); || 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) { private void evaluate(IASTNode point) {
if (fValueCategory != null) if (fValueCategory != null)
return; return;

View file

@ -98,6 +98,11 @@ public class EvalFixed extends CPPEvaluation {
return fIsValueDependent; return fIsValueDependent;
} }
@Override
public boolean isConstantExpression(IASTNode point) {
return isConstexprValue(fValue, point);
}
@Override @Override
public IType getTypeOrFunctionSet(IASTNode point) { public IType getTypeOrFunctionSet(IASTNode point) {
return fType; return fType;

View file

@ -84,6 +84,12 @@ public class EvalFunctionCall extends CPPDependentEvaluation {
return containsDependentValue(fArguments); return containsDependentValue(fArguments);
} }
@Override
public boolean isConstantExpression(IASTNode point) {
return areAllConstantExpressions(fArguments, point)
&& isConstexprFuncOrNull(getOverload(point));
}
public ICPPFunction getOverload(IASTNode point) { public ICPPFunction getOverload(IASTNode point) {
if (fOverload == CPPFunction.UNINITIALIZED_FUNCTION) { if (fOverload == CPPFunction.UNINITIALIZED_FUNCTION) {
fOverload= computeOverload(point); fOverload= computeOverload(point);
@ -223,6 +229,10 @@ public class EvalFunctionCall extends CPPDependentEvaluation {
private ICPPEvaluation computeForFunctionCall(int maxdepth, IASTNode point) { private ICPPEvaluation computeForFunctionCall(int maxdepth, IASTNode point) {
if (isValueDependent()) if (isValueDependent())
return this; 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); ICPPFunction function = getOverload(point);
if (function == null) { if (function == null) {
if (fArguments[0] instanceof EvalBinding) { if (fArguments[0] instanceof EvalBinding) {

View file

@ -132,6 +132,16 @@ public class EvalFunctionSet extends CPPDependentEvaluation {
return false; return false;
} }
@Override
public boolean isConstantExpression(IASTNode point) {
for (ICPPFunction f : fFunctionSet.getBindings()) {
if (!f.isConstexpr()) {
return false;
}
}
return true;
}
@Override @Override
public IType getTypeOrFunctionSet(IASTNode point) { public IType getTypeOrFunctionSet(IASTNode point) {
return new FunctionSetType(fFunctionSet, fAddressOf); return new FunctionSetType(fFunctionSet, fAddressOf);

View file

@ -132,6 +132,11 @@ public class EvalID extends CPPDependentEvaluation {
return true; return true;
} }
@Override
public boolean isConstantExpression(IASTNode point) {
return false;
}
@Override @Override
public IType getTypeOrFunctionSet(IASTNode point) { public IType getTypeOrFunctionSet(IASTNode point) {
return new TypeOfDependentExpression(this); return new TypeOfDependentExpression(this);

View file

@ -57,20 +57,17 @@ public class EvalInitList extends CPPDependentEvaluation {
@Override @Override
public boolean isTypeDependent() { public boolean isTypeDependent() {
for (ICPPEvaluation clause : fClauses) { return containsDependentType(fClauses);
if (clause.isTypeDependent())
return true;
}
return false;
} }
@Override @Override
public boolean isValueDependent() { public boolean isValueDependent() {
for (ICPPEvaluation clause : fClauses) { return containsDependentValue(fClauses);
if (clause.isValueDependent())
return true;
} }
return false;
@Override
public boolean isConstantExpression(IASTNode point) {
return areAllConstantExpressions(fClauses, point);
} }
@Override @Override

View file

@ -156,6 +156,15 @@ public class EvalMemberAccess extends CPPDependentEvaluation {
return false; 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, public static IType getFieldOwnerType(IType fieldOwnerExpressionType, boolean isDeref, IASTNode point, Collection<ICPPFunction> functionBindings,
boolean returnUnnamed) { boolean returnUnnamed) {
IType type= fieldOwnerExpressionType; IType type= fieldOwnerExpressionType;

View file

@ -66,6 +66,11 @@ public class EvalParameterPack extends CPPDependentEvaluation {
return fExpansionPattern.isValueDependent(); return fExpansionPattern.isValueDependent();
} }
@Override
public boolean isConstantExpression(IASTNode point) {
return false;
}
@Override @Override
public IType getTypeOrFunctionSet(IASTNode point) { public IType getTypeOrFunctionSet(IASTNode point) {
if (fType == null) { 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.ISerializableEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; 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.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.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
@ -44,6 +45,10 @@ public class EvalTypeId extends CPPDependentEvaluation {
private final boolean fRepresentsNewExpression; private final boolean fRepresentsNewExpression;
private IType fOutputType; private IType fOutputType;
private ICPPFunction fConstructor = CPPFunction.UNINITIALIZED_FUNCTION;
private boolean fCheckedIsTypeDependent;
private boolean fIsTypeDependent;
public EvalTypeId(IType type, IASTNode pointOfDefinition, ICPPEvaluation... arguments) { public EvalTypeId(IType type, IASTNode pointOfDefinition, ICPPEvaluation... arguments) {
this(type, findEnclosingTemplate(pointOfDefinition), false, arguments); this(type, findEnclosingTemplate(pointOfDefinition), false, arguments);
} }
@ -93,7 +98,7 @@ public class EvalTypeId extends CPPDependentEvaluation {
} }
private IType computeType() { private IType computeType() {
if (CPPTemplates.isDependentType(fInputType) || containsDependentType(fArguments)) if (isTypeDependent())
return new TypeOfDependentExpression(this); return new TypeOfDependentExpression(this);
IType type = typeFromReturnType(fInputType); IType type = typeFromReturnType(fInputType);
@ -121,10 +126,11 @@ public class EvalTypeId extends CPPDependentEvaluation {
@Override @Override
public boolean isTypeDependent() { public boolean isTypeDependent() {
if (fOutputType == null) { if (!fCheckedIsTypeDependent) {
fOutputType= computeType(); fCheckedIsTypeDependent = true;
fIsTypeDependent = CPPTemplates.isDependentType(fInputType) || containsDependentType(fArguments);
} }
return fOutputType instanceof TypeOfDependentExpression; return fIsTypeDependent;
} }
@Override @Override
@ -136,11 +142,48 @@ public class EvalTypeId extends CPPDependentEvaluation {
return false; return false;
} }
@Override
public boolean isConstantExpression(IASTNode point) {
return !fRepresentsNewExpression
&& areAllConstantExpressions(fArguments, point)
&& isConstexprFuncOrNull(getConstructor(point));
}
@Override @Override
public ValueCategory getValueCategory(IASTNode point) { public ValueCategory getValueCategory(IASTNode point) {
return valueCategoryFromReturnType(fInputType); 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 @Override
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException { public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
short firstBytes = ITypeMarshalBuffer.EVAL_TYPE_ID; short firstBytes = ITypeMarshalBuffer.EVAL_TYPE_ID;
@ -178,29 +221,21 @@ public class EvalTypeId extends CPPDependentEvaluation {
if (args == fArguments && type == fInputType) if (args == fArguments && type == fInputType)
return this; 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); IType simplifiedType = SemanticUtil.getNestedType(type, SemanticUtil.TDEF);
if (simplifiedType instanceof ICPPClassType) { if (simplifiedType instanceof ICPPClassType) {
// Check the constructor call and return EvalFixed.INCOMPLETE to indicate a substitution // Check the constructor call and return EvalFixed.INCOMPLETE to indicate a substitution
// failure if the call cannot be resolved. // failure if the call cannot be resolved.
ICPPClassType classType = (ICPPClassType) type; ICPPFunction constructor = result.getConstructor(point);
LookupData data = new LookupData(classType.getNameCharArray(), null, point); if (constructor == null || constructor instanceof IProblemBinding || constructor.isDeleted()) {
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);
return EvalFixed.INCOMPLETE; return EvalFixed.INCOMPLETE;
} }
} }
} }
return new EvalTypeId(type, getTemplateDefinition(), fRepresentsNewExpression, args);
return result;
} }
@Override @Override

View file

@ -145,6 +145,12 @@ public class EvalUnary extends CPPDependentEvaluation {
} }
} }
@Override
public boolean isConstantExpression(IASTNode point) {
return fArgument.isConstantExpression(point)
&& isConstexprFuncOrNull(getOverload(point));
}
public ICPPFunction getOverload(IASTNode point) { public ICPPFunction getOverload(IASTNode point) {
if (fOverload == CPPFunction.UNINITIALIZED_FUNCTION) { if (fOverload == CPPFunction.UNINITIALIZED_FUNCTION) {
fOverload= computeOverload(point); fOverload= computeOverload(point);

View file

@ -126,6 +126,11 @@ public class EvalUnaryTypeID extends CPPDependentEvaluation {
return false; return false;
} }
@Override
public boolean isConstantExpression(IASTNode point) {
return true;
}
@Override @Override
public IType getTypeOrFunctionSet(IASTNode point) { public IType getTypeOrFunctionSet(IASTNode point) {
if (fType == null) if (fType == null)