diff options
author | Nathan Ridge | 2018-02-09 04:40:47 +0000 |
---|---|---|
committer | Nathan Ridge | 2018-02-12 00:13:28 +0000 |
commit | ae8b4e25da919d069db7b595c9fc9741ffa62f86 (patch) | |
tree | 21cf2917872b38499f19842b2c41171aa8ef2d4d | |
parent | a8cf65fa75e32249bb753f44a058da024e8af6ee (diff) | |
download | org.eclipse.cdt-ae8b4e25da919d069db7b595c9fc9741ffa62f86.tar.gz org.eclipse.cdt-ae8b4e25da919d069db7b595c9fc9741ffa62f86.tar.xz org.eclipse.cdt-ae8b4e25da919d069db7b595c9fc9741ffa62f86.zip |
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
6 files changed, 68 insertions, 9 deletions
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java index f172faccb84..c5c65d39bfa 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java @@ -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(); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java index 3ac22c11d96..845a3256fdb 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java @@ -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(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java index cef11e192a3..44c0bc953a9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java @@ -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 diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalMemberAccess.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalMemberAccess.java index 6e49cc6b1d0..af5622c8d36 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalMemberAccess.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalMemberAccess.java @@ -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) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecDeclarator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecDeclarator.java index 63d40248ec5..dcddf9ac317 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecDeclarator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecDeclarator.java @@ -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 = diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecRangeBasedFor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecRangeBasedFor.java index 863fd7b218b..53de3ded8bb 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecRangeBasedFor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecRangeBasedFor.java @@ -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 && |