From c180a3e7982577ab8ec5e28ca6a5917daa69d0cb Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Mon, 13 Jun 2016 12:21:23 -0400 Subject: [PATCH] Bug 494216 - Instantiation of variable templates with dependent arguments Change-Id: If9c27267d25ce8cccb89e7a5404bf5e3e6480dcb --- .../tests/ast2/AST2VariableTemplateTests.java | 32 +++++++++++++++++++ .../core/testplugin/util/BaseTestCase.java | 11 +++++-- .../parser/cpp/semantics/CPPTemplates.java | 32 +++++++++++++++++-- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2VariableTemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2VariableTemplateTests.java index 396c624ef7a..cbf0efbd67e 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2VariableTemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2VariableTemplateTests.java @@ -12,14 +12,18 @@ package org.eclipse.cdt.core.parser.tests.ast2; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel; import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFieldTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPPartialSpecialization; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableInstance; import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableTemplate; import org.eclipse.cdt.core.parser.ParserLanguage; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFieldTemplateSpecialization; import junit.framework.TestSuite; @@ -309,6 +313,34 @@ public class AST2VariableTemplateTests extends AST2TestBase { assertEquals(template, bInst.getSpecializedBinding()); } + // template + // struct meta { + // static const bool value = true; + // }; + // + // template + // constexpr bool var = meta::value; + // + // template struct S {}; + // + // template + // S> foo(); + // + // void bar() { + // auto waldo = foo(); + // } + public void test_bug494216() throws Exception { + parseAndCheckBindings(); + + BindingAssertionHelper ah = getAssertionHelper(ParserLanguage.CPP); + ICPPVariable waldo = ah.assertNonProblem("waldo"); + IType type = waldo.getType(); + assertInstance(type, CPPClassInstance.class); + ICPPTemplateArgument[] args = ((CPPClassInstance) type).getTemplateArguments(); + assertEquals(1, args.length); + assertValue(args[0].getNonTypeValue(), 1); + } + private IASTTranslationUnit parseAndCheckBindings() throws Exception { return parseAndCheckBindings(getAboveComment(), ParserLanguage.CPP); } diff --git a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase.java b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase.java index 461661c3b7a..385e81a5da3 100644 --- a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase.java +++ b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase.java @@ -32,6 +32,7 @@ import junit.framework.TestResult; import junit.framework.TestSuite; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.model.CoreModel; @@ -358,9 +359,13 @@ public class BaseTestCase extends TestCase { return clazz.cast(o); } + protected static void assertValue(IValue value, long expectedValue) { + assertNotNull(value); + assertNotNull(value.numericalValue()); + assertEquals(expectedValue, value.numericalValue().longValue()); + } + protected static void assertVariableValue(IVariable var, long expectedValue) { - assertNotNull(var.getInitialValue()); - assertNotNull(var.getInitialValue().numberValue()); - assertEquals(expectedValue, var.getInitialValue().numberValue().longValue()); + assertValue(var.getInitialValue(), expectedValue); } } 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 949c46bd8e2..248edff5210 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 @@ -112,6 +112,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTypeSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUnaryTypeTransformation; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableInstance; import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableTemplate; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.parser.util.ArrayUtil; @@ -254,7 +255,7 @@ public class CPPTemplates { return createProblem(template, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, point); if (template instanceof ICPPTemplateTemplateParameter || hasDependentArgument(arguments)) { - return deferredInstance(template, arguments); + return deferredInstance(template, arguments, point); } if (template instanceof ICPPClassTemplatePartialSpecialization) { @@ -500,7 +501,8 @@ public class CPPTemplates { } } - private static IBinding deferredInstance(ICPPPartiallySpecializable template, ICPPTemplateArgument[] arguments) throws DOMException { + private static IBinding deferredInstance(ICPPPartiallySpecializable template, + ICPPTemplateArgument[] arguments, IASTNode point) throws DOMException { ICPPTemplateInstance instance= getInstance(template, arguments, false); if (instance != null) return instance; @@ -509,6 +511,16 @@ public class CPPTemplates { instance = new CPPDeferredClassInstance((ICPPClassTemplate) template, arguments); addInstance(template, arguments, instance); } + if (template instanceof ICPPVariableTemplate) { + // TODO(nathanridge): Do we need a CPPDeferredVariableInstance? + ICPPVariableTemplate variableTemplate = ((ICPPVariableTemplate) template); + CPPTemplateParameterMap tpMap = createParameterMap(template, arguments, point); + InstantiationContext context = new InstantiationContext(tpMap, point); + IType type = instantiateType(variableTemplate.getType(), context); + IValue value = instantiateValue(variableTemplate.getInitialValue(), context, + Value.MAX_RECURSION_DEPTH); + instance = new CPPVariableInstance(template, template.getOwner(), tpMap, arguments, type, value); + } return instance; } @@ -1712,6 +1724,22 @@ public class CPPTemplates { result.setParameters(specializeParameters(origInstance.getParameters(), result, context, maxDepth)); return result; } + } else if (binding instanceof ICPPVariableInstance) { + // TODO(nathanridge): + // Similar to the ICPPFunctionInstance case above, perhaps we should have an + // ICPPDeferredVariableInstance. + ICPPVariableInstance origInstance = (ICPPVariableInstance) binding; + ICPPTemplateArgument[] origArgs = origInstance.getTemplateArguments(); + ICPPTemplateArgument[] newArgs = instantiateArguments(origArgs, context, false); + if (origArgs != newArgs) { + CPPTemplateParameterMap newMap = instantiateArgumentMap( + origInstance.getTemplateParameterMap(), context); + IType newType = instantiateType(origInstance.getType(), context); + IValue newValue = instantiateValue(origInstance.getInitialValue(), context, + Value.MAX_RECURSION_DEPTH); + return new CPPVariableInstance(origInstance.getTemplateDefinition(), origInstance.getOwner(), + newMap, newArgs, newType, newValue); + } } return binding; }