From 0ccfe853dc0adcaea4419a211c864ed307cd367f Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Sat, 8 Jul 2023 19:23:27 +1000 Subject: [PATCH] [#457] Fix partial specialisation matching for deduced primitive types Current partial specialisation selection matches deduced type by IBinding, not by IType, meaning that it can't work for types (such as primitive types) that aren't represented by an IBinding. Fix that by wrapping the result of resolution in a type which can handle either. --- .../parser/tests/ast2/AST2TemplateTests.java | 31 ++++++++ .../parser/cpp/semantics/CPPTemplates.java | 74 ++++++++++++++----- .../semantics/TemplateArgumentDeduction.java | 10 ++- 3 files changed, 93 insertions(+), 22 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index 69d883daa88..2886f6a8ce3 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -6903,6 +6903,37 @@ public void testSfinae_c() throws Exception { assertTrue(varIp.getType().isSameType(varJp.getType())); } + // template + // struct C { + // }; + // + // template + // struct C { + // int ccc1; + // using t = int; + // }; + // + // template + // struct C { + // int ccc2; + // }; + // + // struct marker { + // using t1 = int; + // using t2 = long; + // }; + // + // int b1 = C().ccc1; + // C::t b2; + public void testSfinae_d() throws Exception { + BindingAssertionHelper bh = getAssertionHelper(); + + IVariable varB1 = bh.assertNonProblem("b1"); + IVariable varB2 = bh.assertNonProblem("b2"); + assertFalse(varB1.getInitialValue() instanceof IProblemBinding); + assertTrue(varB1.getType().isSameType(varB2.getType())); + } + // template // struct is_pod { // static const bool value = __is_pod(T); 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 3f08893f8ba..70ee9da0122 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 @@ -1614,19 +1614,23 @@ public static IType instantiateType(final IType type, InstantiationContext conte } } } else if (type instanceof TypeOfUnknownMember) { - IBinding binding = resolveUnknown(((TypeOfUnknownMember) type).getUnknownMember(), context); - if (binding instanceof IType) { - return (IType) binding; - } else if (binding instanceof IVariable) { - return ((IVariable) binding).getType(); - } else if (binding instanceof IFunction) { - return ((IFunction) binding).getType(); + BindingOrType bindingType = resolveUnknownBindingOrType( + ((TypeOfUnknownMember) type).getUnknownMember(), context); + if (bindingType.getType() != null) { + return bindingType.getType(); + } else { + IBinding binding = bindingType.getBinding(); + if (binding instanceof IVariable) { + return ((IVariable) binding).getType(); + } else if (binding instanceof IFunction) { + return ((IFunction) binding).getType(); + } } return type; } else { - IBinding binding = resolveUnknown((ICPPUnknownBinding) type, context); - if (binding instanceof IType) - return (IType) binding; + BindingOrType bindingType = resolveUnknownBindingOrType((ICPPUnknownBinding) type, context); + if (bindingType.getType() != null) + return bindingType.getType(); return type; } @@ -3116,29 +3120,63 @@ public static boolean containsDependentArg(ObjectMap tpMap) { /** * Attempts to (partially) resolve an unknown binding with the given arguments. + * Cannot resolved types that are not representable as a binding. */ public static IBinding resolveUnknown(ICPPUnknownBinding unknown, InstantiationContext context) throws DOMException { + BindingOrType bindingType = resolveUnknownBindingOrType(unknown, context); + if (bindingType.getBinding() != null) + return bindingType.getBinding(); + return unknown; + } + + public static class BindingOrType { + Object bindingOrType; + + BindingOrType(IBinding binding) { + bindingOrType = binding; + } + + BindingOrType(IType type) { + bindingOrType = type; + } + + IType getType() { + if (bindingOrType instanceof IType) + return (IType) bindingOrType; + return null; + } + + IBinding getBinding() { + if (bindingOrType instanceof IBinding) + return (IBinding) bindingOrType; + return null; + } + } + + /** + * Attempts to (partially) resolve an unknown binding with the given arguments. + */ + public static BindingOrType resolveUnknownBindingOrType(ICPPUnknownBinding unknown, InstantiationContext context) + throws DOMException { if (unknown instanceof ICPPDeferredClassInstance) { - return resolveDeferredClassInstance((ICPPDeferredClassInstance) unknown, context); + return new BindingOrType(resolveDeferredClassInstance((ICPPDeferredClassInstance) unknown, context)); } if (unknown instanceof ICPPDeferredVariableInstance) { - return resolveDeferredVariableInstance((ICPPDeferredVariableInstance) unknown, context); + return new BindingOrType(resolveDeferredVariableInstance((ICPPDeferredVariableInstance) unknown, context)); } if (unknown instanceof ICPPUnknownMember) { - return resolveUnknownMember((ICPPUnknownMember) unknown, context); + return new BindingOrType(resolveUnknownMember((ICPPUnknownMember) unknown, context)); } if (unknown instanceof ICPPTemplateParameter && unknown instanceof IType) { IType type = resolveTemplateTypeParameter((ICPPTemplateParameter) unknown, context); - if (type instanceof IBinding) - return (IBinding) type; + return new BindingOrType(type); } if (unknown instanceof TypeOfDependentExpression) { IType type = instantiateType((IType) unknown, context); - if (type instanceof IBinding) - return (IBinding) type; + return new BindingOrType(type); } - return unknown; + return new BindingOrType(unknown); } private static IBinding resolveUnknownMember(ICPPUnknownMember unknown, InstantiationContext context) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java index e290be9b3ed..c5aea790721 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java @@ -1044,11 +1044,13 @@ private boolean fromType(IType p, IType a, boolean allowCVQConversion, boolean v // Verify that the resolved binding matches the argument type. InstantiationContext context = InstantiationContext.forDeduction(fDeducedArgs); - IBinding binding = CPPTemplates.resolveUnknown((ICPPUnknownBinding) p, context); - if (binding instanceof ICPPUnknownBinding) + CPPTemplates.BindingOrType bindingType = CPPTemplates + .resolveUnknownBindingOrType((ICPPUnknownBinding) p, context); + if (bindingType.getBinding() instanceof ICPPUnknownBinding) return true; // An unknown type may match anything. - - return binding instanceof IType && ((IType) binding).isSameType(a); + if (bindingType.getType() != null) { + return bindingType.getType().isSameType(a); + } } else { return p.isSameType(a); }