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 {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
IBinding spec = null;
|
||||
final ICPPTemplateParameterMap tpMap= owner.getTemplateParameterMap();
|
||||
|
|
|
@ -264,10 +264,10 @@ public class EvalFunctionSet extends CPPDependentEvaluation {
|
|||
ICPPFunction[] originalFunctions = fFunctionSet.getBindings();
|
||||
ICPPFunction[] functions = originalFunctions;
|
||||
if (owner instanceof ICPPClassSpecialization && owner != originalOwner) {
|
||||
ICPPClassSpecialization ownerClass = (ICPPClassSpecialization) owner;
|
||||
functions = new ICPPFunction[originalFunctions.length];
|
||||
for (int i = 0; i < originalFunctions.length; i++) {
|
||||
functions[i] = (ICPPFunction) CPPTemplates.createSpecialization((ICPPClassSpecialization) owner,
|
||||
originalFunctions[i]);
|
||||
functions[i] = (ICPPFunction) ownerClass.specializeMember(originalFunctions[i]);
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
IType ownerClass = SemanticUtil.getNestedType(ownerType, ALLCVQ);
|
||||
if (ownerClass instanceof ICPPClassSpecialization) {
|
||||
member = CPPTemplates.createSpecialization((ICPPClassSpecialization) ownerClass, fMember);
|
||||
member = ((ICPPClassSpecialization) ownerClass).specializeMember(fMember);
|
||||
}
|
||||
ICPPEvaluation ownerEval = fOwnerEval;
|
||||
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.IValue;
|
||||
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.ICPPReferenceType;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
|
||||
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.ITypeMarshalBuffer;
|
||||
|
@ -222,8 +224,15 @@ public final class ExecDeclarator implements ICPPExecution {
|
|||
ICPPVariable declaredVariable = (ICPPVariable) declaredBinding;
|
||||
newDeclaredBinding = CPPTemplates.createVariableSpecialization(context, declaredVariable);
|
||||
} else {
|
||||
newDeclaredBinding = (ICPPBinding) CPPTemplates.createSpecialization(
|
||||
context.getContextSpecialization(), declaredBinding);
|
||||
ICPPSpecialization owner = context.getContextSpecialization();
|
||||
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 =
|
||||
|
|
|
@ -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.IVariable;
|
||||
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.ICPPFunction;
|
||||
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.ICPPSpecialization;
|
||||
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.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
|
||||
// described in the standard (by constructing the corresponding executions and evaluations),
|
||||
// and the above instantiations will fall out of that automatically.
|
||||
ICPPFunction newBegin = begin != null ? (ICPPFunction)CPPTemplates.createSpecialization(
|
||||
context.getContextSpecialization(), begin) : null;
|
||||
ICPPFunction newEnd = end != null ? (ICPPFunction)CPPTemplates.createSpecialization(
|
||||
context.getContextSpecialization(), end) : null;
|
||||
ICPPSpecialization owner = context.getContextSpecialization();
|
||||
ICPPFunction newBegin = null;
|
||||
ICPPFunction newEnd = 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);
|
||||
|
||||
if (newDeclarationExec == declarationExec &&
|
||||
|
|
Loading…
Add table
Reference in a new issue