1
0
Fork 0
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:
Nathan Ridge 2018-02-08 23:40:47 -05:00
parent a8cf65fa75
commit ae8b4e25da
6 changed files with 68 additions and 9 deletions

View file

@ -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();
}
}

View file

@ -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();

View file

@ -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

View file

@ -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) {

View file

@ -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 =

View file

@ -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 &&