mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-03 23:25:26 +02:00
Bug 519091 - Do not bypass the caching mechanism for class member specializations
Direct calls to CPPTemplates.createSpecialization() bypass the caching mechanism, resulting in the violation of invariants such as every binding being represented by a unique (AST-derived) binding object. ICPPClassSpecialization.specializeMember() should be used instead. Change-Id: I10ddb06d087d97cf05c6bed0d9f14a15440b87fe
This commit is contained in:
parent
a8cf65fa75
commit
ae8b4e25da
6 changed files with 68 additions and 9 deletions
|
@ -3167,4 +3167,35 @@ public class IndexCPPTemplateResolutionTest extends IndexBindingResolutionTestBa
|
||||||
public void testSpecializationOfAnonymousClass_528456() throws Exception {
|
public void testSpecializationOfAnonymousClass_528456() throws Exception {
|
||||||
checkBindings();
|
checkBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // empty file
|
||||||
|
|
||||||
|
// namespace std {
|
||||||
|
// template <class E>
|
||||||
|
// struct initializer_list {
|
||||||
|
// const E* array;
|
||||||
|
// int len;
|
||||||
|
// constexpr const E* begin() const { return array; }
|
||||||
|
// constexpr const E* end() const { return array + len; }
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// template <typename Enum>
|
||||||
|
// struct QFlags {
|
||||||
|
// int i;
|
||||||
|
// constexpr QFlags(std::initializer_list<Enum> flags)
|
||||||
|
// : i(initializer_list_helper(flags.begin(), flags.end())) {}
|
||||||
|
// constexpr static int initializer_list_helper(const Enum* it, const Enum* end) {
|
||||||
|
// return it == end ? 0 : (int(*it) | initializer_list_helper(it + 1, end));
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// enum Option {
|
||||||
|
// ShowMessageBox = 0x02,
|
||||||
|
// Log = 0x04
|
||||||
|
// };
|
||||||
|
// struct MessageFunctionPrivate {
|
||||||
|
// QFlags<Option> Options{ShowMessageBox, Log};
|
||||||
|
// };
|
||||||
|
public void testConstexprInitListConstructor_519091() throws Exception {
|
||||||
|
checkBindings();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -978,6 +978,16 @@ public class CPPTemplates {
|
||||||
return newVariable;
|
return newVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IMPORTANT: Do NOT call this method directly, at least when (owner instanceof ICPPClassSpecialization).
|
||||||
|
* Use ICPPClassSpecialization.specializeMember(decl) instead.
|
||||||
|
*
|
||||||
|
* This ensures that the caching mechanism for member specializations implemented by
|
||||||
|
* ICPPClassSpecialization.specializeMember() is not bypassed.
|
||||||
|
*
|
||||||
|
* TODO: Implement a caching mechanism for non-class owners, too, and make specializeMember()
|
||||||
|
* a method of ICPPSpecialization itself.
|
||||||
|
*/
|
||||||
public static IBinding createSpecialization(ICPPSpecialization owner, IBinding decl) {
|
public static IBinding createSpecialization(ICPPSpecialization owner, IBinding decl) {
|
||||||
IBinding spec = null;
|
IBinding spec = null;
|
||||||
final ICPPTemplateParameterMap tpMap= owner.getTemplateParameterMap();
|
final ICPPTemplateParameterMap tpMap= owner.getTemplateParameterMap();
|
||||||
|
|
|
@ -264,10 +264,10 @@ public class EvalFunctionSet extends CPPDependentEvaluation {
|
||||||
ICPPFunction[] originalFunctions = fFunctionSet.getBindings();
|
ICPPFunction[] originalFunctions = fFunctionSet.getBindings();
|
||||||
ICPPFunction[] functions = originalFunctions;
|
ICPPFunction[] functions = originalFunctions;
|
||||||
if (owner instanceof ICPPClassSpecialization && owner != originalOwner) {
|
if (owner instanceof ICPPClassSpecialization && owner != originalOwner) {
|
||||||
|
ICPPClassSpecialization ownerClass = (ICPPClassSpecialization) owner;
|
||||||
functions = new ICPPFunction[originalFunctions.length];
|
functions = new ICPPFunction[originalFunctions.length];
|
||||||
for (int i = 0; i < originalFunctions.length; i++) {
|
for (int i = 0; i < originalFunctions.length; i++) {
|
||||||
functions[i] = (ICPPFunction) CPPTemplates.createSpecialization((ICPPClassSpecialization) owner,
|
functions[i] = (ICPPFunction) ownerClass.specializeMember(originalFunctions[i]);
|
||||||
originalFunctions[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No need to instantiate the implied object type. An EvalFunctioNSet should only be created
|
// No need to instantiate the implied object type. An EvalFunctioNSet should only be created
|
||||||
|
|
|
@ -388,7 +388,7 @@ public class EvalMemberAccess extends CPPDependentEvaluation {
|
||||||
IBinding member = fMember;
|
IBinding member = fMember;
|
||||||
IType ownerClass = SemanticUtil.getNestedType(ownerType, ALLCVQ);
|
IType ownerClass = SemanticUtil.getNestedType(ownerType, ALLCVQ);
|
||||||
if (ownerClass instanceof ICPPClassSpecialization) {
|
if (ownerClass instanceof ICPPClassSpecialization) {
|
||||||
member = CPPTemplates.createSpecialization((ICPPClassSpecialization) ownerClass, fMember);
|
member = ((ICPPClassSpecialization) ownerClass).specializeMember(fMember);
|
||||||
}
|
}
|
||||||
ICPPEvaluation ownerEval = fOwnerEval;
|
ICPPEvaluation ownerEval = fOwnerEval;
|
||||||
if (ownerEval != null) {
|
if (ownerEval != null) {
|
||||||
|
|
|
@ -20,8 +20,10 @@ import org.eclipse.cdt.core.dom.ast.IQualifierType;
|
||||||
import org.eclipse.cdt.core.dom.ast.IType;
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
import org.eclipse.cdt.core.dom.ast.IValue;
|
import org.eclipse.cdt.core.dom.ast.IValue;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.CompositeValue;
|
import org.eclipse.cdt.internal.core.dom.parser.CompositeValue;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
|
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
|
||||||
|
@ -222,8 +224,15 @@ public final class ExecDeclarator implements ICPPExecution {
|
||||||
ICPPVariable declaredVariable = (ICPPVariable) declaredBinding;
|
ICPPVariable declaredVariable = (ICPPVariable) declaredBinding;
|
||||||
newDeclaredBinding = CPPTemplates.createVariableSpecialization(context, declaredVariable);
|
newDeclaredBinding = CPPTemplates.createVariableSpecialization(context, declaredVariable);
|
||||||
} else {
|
} else {
|
||||||
newDeclaredBinding = (ICPPBinding) CPPTemplates.createSpecialization(
|
ICPPSpecialization owner = context.getContextSpecialization();
|
||||||
context.getContextSpecialization(), declaredBinding);
|
if (owner instanceof ICPPClassSpecialization) {
|
||||||
|
newDeclaredBinding = (ICPPBinding)
|
||||||
|
((ICPPClassSpecialization) owner).specializeMember(declaredBinding);
|
||||||
|
} else {
|
||||||
|
// TODO: Non-class owners should also have a specializeMember() function which
|
||||||
|
// implements a caching mechanism.
|
||||||
|
newDeclaredBinding = (ICPPBinding) CPPTemplates.createSpecialization(owner, declaredBinding);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ICPPEvaluation newInitializerEval =
|
ICPPEvaluation newInitializerEval =
|
||||||
|
|
|
@ -20,10 +20,12 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
import org.eclipse.cdt.core.dom.ast.IType;
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
import org.eclipse.cdt.core.dom.ast.IVariable;
|
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
|
||||||
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.cpp.ICPPEvaluation;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation.ConstexprEvaluationContext;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation.ConstexprEvaluationContext;
|
||||||
|
@ -167,10 +169,17 @@ public class ExecRangeBasedFor implements ICPPExecution {
|
||||||
// Alternatively, we could lower the range-based for loop into a regular for loop as
|
// Alternatively, we could lower the range-based for loop into a regular for loop as
|
||||||
// described in the standard (by constructing the corresponding executions and evaluations),
|
// described in the standard (by constructing the corresponding executions and evaluations),
|
||||||
// and the above instantiations will fall out of that automatically.
|
// and the above instantiations will fall out of that automatically.
|
||||||
ICPPFunction newBegin = begin != null ? (ICPPFunction)CPPTemplates.createSpecialization(
|
ICPPSpecialization owner = context.getContextSpecialization();
|
||||||
context.getContextSpecialization(), begin) : null;
|
ICPPFunction newBegin = null;
|
||||||
ICPPFunction newEnd = end != null ? (ICPPFunction)CPPTemplates.createSpecialization(
|
ICPPFunction newEnd = null;
|
||||||
context.getContextSpecialization(), end) : null;
|
if (owner instanceof ICPPClassSpecialization) {
|
||||||
|
if (begin != null) {
|
||||||
|
newBegin = (ICPPFunction) ((ICPPClassSpecialization) owner).specializeMember(begin);
|
||||||
|
}
|
||||||
|
if (end != null) {
|
||||||
|
newEnd = (ICPPFunction) ((ICPPClassSpecialization) owner).specializeMember(end);
|
||||||
|
}
|
||||||
|
}
|
||||||
ICPPExecution newBodyExec = bodyExec.instantiate(context, maxDepth);
|
ICPPExecution newBodyExec = bodyExec.instantiate(context, maxDepth);
|
||||||
|
|
||||||
if (newDeclarationExec == declarationExec &&
|
if (newDeclarationExec == declarationExec &&
|
||||||
|
|
Loading…
Add table
Reference in a new issue