1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-07 09:46:02 +02:00

BUg 508254 - Move the recursion protection set in CPPVariable.getInitialValue() to EvalUtil.getVariableValue()

This catches recursion along paths in EvalUtil.getVariableValue() that don't
go through CPPVariabble.getInitialValue().

The patch also improves caching in EvalInitList.

Change-Id: I343bbf1bb7493b2c83771de3659209e5d512fd80
This commit is contained in:
Nathan Ridge 2016-12-03 20:03:50 -05:00
parent cf2e9fe3c8
commit db9dea4408
4 changed files with 88 additions and 60 deletions

View file

@ -1970,7 +1970,27 @@ public class IndexCPPBindingResolutionTest extends IndexBindingResolutionTestBas
// constexpr S waldo = { nullptr, waldo.a }; // constexpr S waldo = { nullptr, waldo.a };
// // empty file // // empty file
public void testVariableInitializerThatReferencesVariable_508254() throws Exception { public void testVariableInitializerThatReferencesVariable_508254a() throws Exception {
checkBindings();
}
// struct S {
// int* a;
// int* b;
// };
//
// constexpr S waldo = { nullptr, waldo.a };
//
// struct T {
// int *pBlock;
// };
//
// static const constexpr T greebo[] = {
// { waldo.a },
// };
// // empty file
public void testVariableInitializerThatReferencesVariable_508254b() throws Exception {
checkBindings(); checkBindings();
} }

View file

@ -17,9 +17,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 java.util.HashSet;
import java.util.Set;
import org.eclipse.cdt.core.dom.ILinkage; import org.eclipse.cdt.core.dom.ILinkage;
import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
@ -59,17 +56,6 @@ public class CPPVariable extends PlatformObject implements ICPPInternalVariable
private IType fType; private IType fType;
private boolean fAllResolved; private boolean fAllResolved;
/**
* The set of CPPVariable objects for which initial value computation is in progress on each thread.
* This is used to guard against recursion during initial value computation.
*/
private static final ThreadLocal<Set<CPPVariable>> fInitialValueInProgress = new ThreadLocal<Set<CPPVariable>>() {
@Override
protected Set<CPPVariable> initialValue() {
return new HashSet<>();
}
};
public CPPVariable(IASTName name) { public CPPVariable(IASTName name) {
boolean isDef = name != null && name.isDefinition(); boolean isDef = name != null && name.isDefinition();
if (name instanceof ICPPASTQualifiedName) { if (name instanceof ICPPASTQualifiedName) {
@ -237,27 +223,19 @@ public class CPPVariable extends PlatformObject implements ICPPInternalVariable
@Override @Override
public IValue getInitialValue() { public IValue getInitialValue() {
Set<CPPVariable> recursionProtectionSet = fInitialValueInProgress.get(); IValue initialValue = null;
if (!recursionProtectionSet.add(this)) { final IType nestedType = SemanticUtil.getNestedType(getType(), TDEF | REF | CVTYPE);
return IntegralValue.UNKNOWN; if (nestedType instanceof ICPPClassType || (initialValue = VariableHelpers.getInitialValue(fDefinition, fDeclarations, getType())) == IntegralValue.UNKNOWN) {
} ICPPEvaluation initEval = getInitializerEvaluation();
try { if (initEval == null) {
IValue initialValue = null; return null;
final IType nestedType = SemanticUtil.getNestedType(getType(), TDEF | REF | CVTYPE);
if (nestedType instanceof ICPPClassType || (initialValue = VariableHelpers.getInitialValue(fDefinition, fDeclarations, getType())) == IntegralValue.UNKNOWN) {
ICPPEvaluation initEval = getInitializerEvaluation();
if (initEval == null) {
return null;
}
if (!initEval.isValueDependent() ) {
return initEval.getValue(fDefinition);
}
return DependentValue.create(initEval);
} }
return initialValue; if (!initEval.isValueDependent() ) {
} finally { return initEval.getValue(fDefinition);
recursionProtectionSet.remove(this); }
return DependentValue.create(initEval);
} }
return initialValue;
} }
private IASTDeclarator findDeclarator() { private IASTDeclarator findDeclarator() {

View file

@ -33,6 +33,8 @@ import org.eclipse.core.runtime.CoreException;
*/ */
public class EvalInitList extends CPPDependentEvaluation { public class EvalInitList extends CPPDependentEvaluation {
private final ICPPEvaluation[] fClauses; private final ICPPEvaluation[] fClauses;
private boolean fCheckedIsValueDependent;
private boolean fIsValueDependent;
private boolean fCheckedIsConstantExpression; private boolean fCheckedIsConstantExpression;
private boolean fIsConstantExpression; private boolean fIsConstantExpression;
@ -66,7 +68,11 @@ public class EvalInitList extends CPPDependentEvaluation {
@Override @Override
public boolean isValueDependent() { public boolean isValueDependent() {
return containsDependentValue(fClauses); if (!fCheckedIsValueDependent) {
fCheckedIsValueDependent = true;
fIsValueDependent = containsDependentValue(fClauses);
}
return fIsValueDependent;
} }
@Override @Override
@ -147,8 +153,10 @@ public class EvalInitList extends CPPDependentEvaluation {
clauses[i] = clause; clauses[i] = clause;
} }
} }
EvalInitList evalInit = new EvalInitList(clauses, this.getTemplateDefinition()); if (clauses == fClauses) {
return evalInit; return this;
}
return new EvalInitList(clauses, this.getTemplateDefinition());
} }
@Override @Override

View file

@ -12,6 +12,9 @@ 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 java.util.HashSet;
import java.util.Set;
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.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IBinding;
@ -29,6 +32,17 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecution;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecutionOwner; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecutionOwner;
public class EvalUtil { public class EvalUtil {
/**
* The set of ICPPVariable objects for which initial value computation is in progress on each thread.
* This is used to guard against recursion during initial value computation.
*/
private static final ThreadLocal<Set<ICPPVariable>> fInitialValueInProgress = new ThreadLocal<Set<ICPPVariable>>() {
@Override
protected Set<ICPPVariable> initialValue() {
return new HashSet<>();
}
};
public static IValue getConditionExprValue(ICPPEvaluation conditionExprEval, ActivationRecord record, ConstexprEvaluationContext context) { public static IValue getConditionExprValue(ICPPEvaluation conditionExprEval, ActivationRecord record, ConstexprEvaluationContext context) {
return conditionExprEval.computeForFunctionCall(record, context.recordStep()).getValue(context.getPoint()); return conditionExprEval.computeForFunctionCall(record, context.recordStep()).getValue(context.getPoint());
} }
@ -137,31 +151,39 @@ public class EvalUtil {
* the given activation record. * the given activation record.
*/ */
public static ICPPEvaluation getVariableValue(ICPPVariable variable, ActivationRecord record) { public static ICPPEvaluation getVariableValue(ICPPVariable variable, ActivationRecord record) {
IType type = variable.getType(); Set<ICPPVariable> recursionProtectionSet = fInitialValueInProgress.get();
IType nestedType = SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE); if (!recursionProtectionSet.add(variable)) {
IValue initialValue = variable.getInitialValue(); return EvalFixed.INCOMPLETE;
ICPPEvaluation valueEval = null; }
try {
if ((initialValue != null && initialValue.getEvaluation() != null) || IType type = variable.getType();
(initialValue == null && nestedType instanceof ICPPClassType)) { IType nestedType = SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE);
final ICPPEvaluation initializerEval = initialValue == null ? null : initialValue.getEvaluation(); IValue initialValue = variable.getInitialValue();
if (initializerEval == EvalFixed.INCOMPLETE) { ICPPEvaluation valueEval = null;
if ((initialValue != null && initialValue.getEvaluation() != null) ||
(initialValue == null && nestedType instanceof ICPPClassType)) {
final ICPPEvaluation initializerEval = initialValue == null ? null : initialValue.getEvaluation();
if (initializerEval == EvalFixed.INCOMPLETE) {
return null;
}
ExecDeclarator declaratorExec = new ExecDeclarator(variable, initializerEval);
ConstexprEvaluationContext context = new ConstexprEvaluationContext(null);
if (declaratorExec.executeForFunctionCall(record, context) != ExecIncomplete.INSTANCE) {
valueEval = record.getVariable(declaratorExec.getDeclaredBinding());
}
} else if (initialValue != null) {
valueEval = new EvalFixed(type, ValueCategory.LVALUE, initialValue);
}
if (valueEval != null && (valueEval == EvalFixed.INCOMPLETE ||
valueEval.getValue(null) == IntegralValue.UNKNOWN)) {
return null; return null;
} }
ExecDeclarator declaratorExec = new ExecDeclarator(variable, initializerEval); return valueEval;
} finally {
ConstexprEvaluationContext context = new ConstexprEvaluationContext(null); recursionProtectionSet.remove(variable);
if (declaratorExec.executeForFunctionCall(record, context) != ExecIncomplete.INSTANCE) {
valueEval = record.getVariable(declaratorExec.getDeclaredBinding());
}
} else if (initialValue != null) {
valueEval = new EvalFixed(type, ValueCategory.LVALUE, initialValue);
} }
if (valueEval != null && (valueEval == EvalFixed.INCOMPLETE ||
valueEval.getValue(null) == IntegralValue.UNKNOWN)) {
return null;
}
return valueEval;
} }
} }