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:
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 };
|
// 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue