mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 14:42:11 +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:
parent
cf2e9fe3c8
commit
db9dea4408
4 changed files with 88 additions and 60 deletions
|
@ -1970,7 +1970,27 @@ public class IndexCPPBindingResolutionTest extends IndexBindingResolutionTestBas
|
|||
// constexpr S waldo = { nullptr, waldo.a };
|
||||
|
||||
// // 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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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.TDEF;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ILinkage;
|
||||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||
|
@ -59,17 +56,6 @@ public class CPPVariable extends PlatformObject implements ICPPInternalVariable
|
|||
private IType fType;
|
||||
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) {
|
||||
boolean isDef = name != null && name.isDefinition();
|
||||
if (name instanceof ICPPASTQualifiedName) {
|
||||
|
@ -237,27 +223,19 @@ public class CPPVariable extends PlatformObject implements ICPPInternalVariable
|
|||
|
||||
@Override
|
||||
public IValue getInitialValue() {
|
||||
Set<CPPVariable> recursionProtectionSet = fInitialValueInProgress.get();
|
||||
if (!recursionProtectionSet.add(this)) {
|
||||
return IntegralValue.UNKNOWN;
|
||||
}
|
||||
try {
|
||||
IValue initialValue = 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);
|
||||
IValue initialValue = 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;
|
||||
}
|
||||
return initialValue;
|
||||
} finally {
|
||||
recursionProtectionSet.remove(this);
|
||||
if (!initEval.isValueDependent() ) {
|
||||
return initEval.getValue(fDefinition);
|
||||
}
|
||||
return DependentValue.create(initEval);
|
||||
}
|
||||
return initialValue;
|
||||
}
|
||||
|
||||
private IASTDeclarator findDeclarator() {
|
||||
|
|
|
@ -33,6 +33,8 @@ import org.eclipse.core.runtime.CoreException;
|
|||
*/
|
||||
public class EvalInitList extends CPPDependentEvaluation {
|
||||
private final ICPPEvaluation[] fClauses;
|
||||
private boolean fCheckedIsValueDependent;
|
||||
private boolean fIsValueDependent;
|
||||
private boolean fCheckedIsConstantExpression;
|
||||
private boolean fIsConstantExpression;
|
||||
|
||||
|
@ -66,7 +68,11 @@ public class EvalInitList extends CPPDependentEvaluation {
|
|||
|
||||
@Override
|
||||
public boolean isValueDependent() {
|
||||
return containsDependentValue(fClauses);
|
||||
if (!fCheckedIsValueDependent) {
|
||||
fCheckedIsValueDependent = true;
|
||||
fIsValueDependent = containsDependentValue(fClauses);
|
||||
}
|
||||
return fIsValueDependent;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -147,8 +153,10 @@ public class EvalInitList extends CPPDependentEvaluation {
|
|||
clauses[i] = clause;
|
||||
}
|
||||
}
|
||||
EvalInitList evalInit = new EvalInitList(clauses, this.getTemplateDefinition());
|
||||
return evalInit;
|
||||
if (clauses == fClauses) {
|
||||
return this;
|
||||
}
|
||||
return new EvalInitList(clauses, this.getTemplateDefinition());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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.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.IASTStatement;
|
||||
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;
|
||||
|
||||
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) {
|
||||
return conditionExprEval.computeForFunctionCall(record, context.recordStep()).getValue(context.getPoint());
|
||||
}
|
||||
|
@ -137,31 +151,39 @@ public class EvalUtil {
|
|||
* the given activation record.
|
||||
*/
|
||||
public static ICPPEvaluation getVariableValue(ICPPVariable variable, ActivationRecord record) {
|
||||
IType type = variable.getType();
|
||||
IType nestedType = SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE);
|
||||
IValue initialValue = variable.getInitialValue();
|
||||
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) {
|
||||
Set<ICPPVariable> recursionProtectionSet = fInitialValueInProgress.get();
|
||||
if (!recursionProtectionSet.add(variable)) {
|
||||
return EvalFixed.INCOMPLETE;
|
||||
}
|
||||
try {
|
||||
IType type = variable.getType();
|
||||
IType nestedType = SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE);
|
||||
IValue initialValue = variable.getInitialValue();
|
||||
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;
|
||||
}
|
||||
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);
|
||||
return valueEval;
|
||||
} finally {
|
||||
recursionProtectionSet.remove(variable);
|
||||
}
|
||||
|
||||
if (valueEval != null && (valueEval == EvalFixed.INCOMPLETE ||
|
||||
valueEval.getValue(null) == IntegralValue.UNKNOWN)) {
|
||||
return null;
|
||||
}
|
||||
return valueEval;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue