1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 513429 - Defer instantiation of variable templates with dependent arguments

Change-Id: Ic5875b19b384ae2726fe000fe5ab2b8cf5dd45a7
This commit is contained in:
Nathan Ridge 2017-03-13 03:20:02 -04:00
parent d35f9e1a60
commit 9742e45559
12 changed files with 367 additions and 14 deletions

View file

@ -340,6 +340,27 @@ public class AST2VariableTemplateTests extends AST2TestBase {
assertEquals(1, args.length);
assertValue(args[0].getNonTypeValue(), 1);
}
// template<typename T, typename = class _, typename... P>
// constexpr bool type_in_pack{type_in_pack<T, P...>};
//
// template<typename T, typename... P>
// constexpr bool type_in_pack<T, T, P...>{true};
//
// template<typename T>
// constexpr bool type_in_pack<T>{false};
//
// constexpr bool waldo1 = type_in_pack<int, int, char>;
// constexpr bool waldo2 = type_in_pack<int, float, char>;
public void testStackOverflow_513429() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper ah = getAssertionHelper(ParserLanguage.CPP);
ICPPVariable waldo1 = ah.assertNonProblem("waldo1");
assertVariableValue(waldo1, 1);
ICPPVariable waldo2 = ah.assertNonProblem("waldo2");
assertVariableValue(waldo2, 0);
}
private IASTTranslationUnit parseAndCheckBindings() throws Exception {
return parseAndCheckBindings(getAboveComment(), ParserLanguage.CPP);

View file

@ -43,7 +43,8 @@ public interface ITypeMarshalBuffer {
TYPE_TRANSFORMATION = 0x0F,
UNKNOWN_MEMBER_TYPE = 0x10,
INITIALIZER_LIST_TYPE = 0x11,
DEFERRED_FUNCTION = 0x12;
DEFERRED_FUNCTION = 0x12,
DEFERRED_VARIABLE_INSTANCE = 0x13;
// Can add more types up to 0x1C, after that it will collide with TypeMarshalBuffer.UNSTORABLE_TYPE.
final static byte

View file

@ -0,0 +1,146 @@
/*******************************************************************************
* Copyright (c) 2017 Nathan Ridge.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableTemplate;
import org.eclipse.cdt.internal.core.dom.parser.ISerializableType;
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates;
import org.eclipse.cdt.internal.core.index.IIndexFragment;
import org.eclipse.cdt.internal.core.pdom.dom.cpp.PDOMCPPDeferredVariableInstance;
import org.eclipse.core.runtime.CoreException;
/**
* AST implementation of ICPPDeferredVariableInstance.
*/
public class CPPDeferredVariableInstance extends CPPUnknownBinding implements ICPPDeferredVariableInstance,
ISerializableType {
private final ICPPVariableTemplate fTemplate;
private final ICPPTemplateArgument[] fArguments;
public CPPDeferredVariableInstance(ICPPVariableTemplate template, ICPPTemplateArgument[] arguments) {
super(template.getNameCharArray());
fTemplate = template;
fArguments = arguments;
}
@Override
public IBinding getOwner() {
return fTemplate.getOwner();
}
@Override
public ICPPVariableTemplate getSpecializedBinding() {
return fTemplate;
}
@Override
public ICPPTemplateParameterMap getTemplateParameterMap() {
ICPPTemplateParameter[] params = fTemplate.getTemplateParameters();
int size = Math.min(fArguments.length, params.length);
CPPTemplateParameterMap map = new CPPTemplateParameterMap(size);
for (int i = 0; i < size; i++) {
map.put(params[i], fArguments[i]);
}
return map;
}
@Override
public IType getType() {
// The type cannot vary in partial specializations, so it's safe to use the primary template's type.
InstantiationContext context = new InstantiationContext(getTemplateParameterMap(), null);
return CPPTemplates.instantiateType(fTemplate.getType(), context);
}
@Override
public IValue getInitialValue() {
// Partial specializations can have different initial values, so we can't compute the initial value
// until we have concrete template arguments and can select a partial specialization or the
// primary template.
return IntegralValue.UNKNOWN;
}
@Override
public boolean isStatic() {
return fTemplate.isStatic();
}
@Override
public boolean isExtern() {
return fTemplate.isExtern();
}
@Override
public boolean isAuto() {
return fTemplate.isAuto();
}
@Override
public boolean isRegister() {
return fTemplate.isRegister();
}
@Override
public boolean isMutable() {
return false;
}
@Override
public boolean isConstexpr() {
return fTemplate.isConstexpr();
}
@Override
public boolean isExternC() {
return fTemplate.isExternC();
}
@Override
public ICPPVariableTemplate getTemplateDefinition() {
return fTemplate;
}
@Override
public ICPPTemplateArgument[] getTemplateArguments() {
return fArguments;
}
@Override
public boolean isExplicitSpecialization() {
return false;
}
@Override
public void marshal(ITypeMarshalBuffer buffer) throws CoreException {
short firstBytes = ITypeMarshalBuffer.DEFERRED_VARIABLE_INSTANCE;
buffer.putShort(firstBytes);
buffer.marshalBinding(fTemplate);
buffer.putInt(fArguments.length);
for (ICPPTemplateArgument arg : fArguments) {
buffer.marshalTemplateArgument(arg);
}
}
public static ICPPDeferredVariableInstance unmarshal(IIndexFragment fragment, short firstBytes,
ITypeMarshalBuffer buffer) throws CoreException {
IBinding template= buffer.unmarshalBinding();
int argcount= buffer.getInt();
ICPPTemplateArgument[] args = new ICPPTemplateArgument[argcount];
for (int i = 0; i < argcount; i++) {
args[i]= buffer.unmarshalTemplateArgument();
}
return new PDOMCPPDeferredVariableInstance(fragment, (ICPPVariableTemplate) template, args);
}
}

View file

@ -0,0 +1,19 @@
/*******************************************************************************
* Copyright (c) 2017 Nathan Ridge.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableInstance;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableTemplate;
/**
* Represents an instantiation of a variable template that cannot be performed because of dependent arguments.
*/
public interface ICPPDeferredVariableInstance extends ICPPUnknownBinding, ICPPVariableInstance {
@Override
ICPPVariableTemplate getTemplateDefinition();
}

View file

@ -146,6 +146,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructorSpecialization
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructorTemplateSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredVariableInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumerationSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFieldInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFieldSpecialization;
@ -184,6 +185,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariableTemplatePartialSp
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPASTInternalTemplateDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPComputableFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredVariableInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecution;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInstanceCache;
@ -240,9 +242,9 @@ public class CPPTemplates {
};
/**
* Instantiates a class template with the given arguments. May return {@code null}.
* Instantiates a class or variable template with the given arguments. May return {@code null}.
*/
public static IBinding instantiate(ICPPClassTemplate template, ICPPTemplateArgument[] args, IASTNode point) {
public static IBinding instantiate(ICPPPartiallySpecializable template, ICPPTemplateArgument[] args, IASTNode point) {
return instantiate(template, args, false, false, point);
}
@ -517,14 +519,8 @@ public class CPPTemplates {
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,
IntegralValue.MAX_RECURSION_DEPTH);
instance = new CPPVariableInstance(template, template.getOwner(), tpMap, arguments, type, value);
instance = new CPPDeferredVariableInstance((ICPPVariableTemplate) template, arguments);
addInstance(template, arguments, instance);
}
return instance;
}
@ -2960,6 +2956,9 @@ public class CPPTemplates {
if (unknown instanceof ICPPDeferredClassInstance) {
return resolveDeferredClassInstance((ICPPDeferredClassInstance) unknown, context);
}
if (unknown instanceof ICPPDeferredVariableInstance) {
return resolveDeferredVariableInstance((ICPPDeferredVariableInstance) unknown, context);
}
if (unknown instanceof ICPPUnknownMember) {
return resolveUnknownMember((ICPPUnknownMember) unknown, context);
}
@ -3060,6 +3059,32 @@ public class CPPTemplates {
}
return dci;
}
private static IBinding resolveDeferredVariableInstance(ICPPDeferredVariableInstance dvi,
InstantiationContext context) {
ICPPVariableTemplate variableTemplate = dvi.getTemplateDefinition();
ICPPTemplateArgument[] arguments = dvi.getTemplateArguments();
ICPPTemplateArgument[] newArgs;
try {
newArgs = instantiateArguments(arguments, context, true);
} catch (DOMException e) {
return e.getProblem();
}
if (newArgs == null) {
return createProblem(variableTemplate, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS,
context.getPoint());
}
// Unlike class templates, variable templates cannot be passed as template template arguments,
// so there is no need to instantiate the template itself.
if (arguments != newArgs) {
IBinding inst = instantiate(variableTemplate, newArgs, context.getPoint());
if (inst != null)
return inst;
}
return dvi;
}
public static boolean haveSameArguments(ICPPTemplateInstance i1, ICPPTemplateInstance i2) {
final ICPPTemplateArgument[] m1= i1.getTemplateArguments();

View file

@ -46,6 +46,7 @@ import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameter;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredVariableInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext;
@ -231,12 +232,12 @@ public class EvalBinding extends CPPDependentEvaluation {
if (fBinding instanceof ICPPTemplateNonTypeParameter) {
return true;
}
if (fBinding instanceof IVariable) {
return IntegralValue.isDependentValue(((IVariable) fBinding).getInitialValue());
}
if (fBinding instanceof ICPPUnknownBinding) {
return true;
}
if (fBinding instanceof IVariable) {
return IntegralValue.isDependentValue(((IVariable) fBinding).getInitialValue());
}
if (fBinding instanceof IFunction) {
return false;
}

View file

@ -55,6 +55,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredVariableInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalEnumerator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
@ -222,6 +223,11 @@ public class EvalID extends CPPDependentEvaluation {
return new EvalFunctionSet((CPPFunctionSet) binding, qualified, isAddressOf(expr), null, expr);
}
if (binding instanceof ICPPUnknownBinding) {
// If the id-expression names a variable template, there is no need to defer name lookup.
if (binding instanceof ICPPDeferredVariableInstance) {
return new EvalBinding(binding, null, expr);
}
ICPPTemplateArgument[] templateArgs = null;
final IASTName lastName = name.getLastName();
if (lastName instanceof ICPPASTTemplateId) {

View file

@ -72,4 +72,5 @@ public interface IIndexCPPBindingConstants {
int CPP_FIELD_INSTANCE = IIndexBindingConstants.LAST_CONSTANT + 58;
int CPP_VARIABLE_TEMPLATE_PARTIAL_SPECIALIZATION = IIndexBindingConstants.LAST_CONSTANT + 59;
int CPP_FIELD_TEMPLATE_PARTIAL_SPECIALIZATION = IIndexBindingConstants.LAST_CONSTANT + 60;
int CPP_DEFERRED_VARIABLE_INSTANCE = IIndexBindingConstants.LAST_CONSTANT + 61;
}

View file

@ -78,6 +78,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnaryTypeTransformation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMember;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPClassSpecializationScope;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredVariableInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalEnumerator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
@ -557,6 +558,15 @@ public class CPPCompositesFactory extends AbstractCompositeFactory {
ICPPClassTemplate t= (ICPPClassTemplate) getCompositeType(t0);
ICPPTemplateArgument[] args = TemplateInstanceUtil.convert(this, args0);
return new CompositeCPPDeferredClassInstance(t, args);
} else if (binding instanceof ICPPDeferredVariableInstance) {
ICPPDeferredVariableInstance def= (ICPPDeferredVariableInstance) binding;
ICPPVariableTemplate t0= def.getTemplateDefinition();
ICPPTemplateArgument[] args0= def.getTemplateArguments();
ICPPVariableTemplate t=
(ICPPVariableTemplate) getCompositeBinding((IIndexFragmentBinding) t0);
ICPPTemplateArgument[] args = TemplateInstanceUtil.convert(this, args0);
return new CompositeCPPDeferredVariableInstance(t, args);
} else {
if (binding instanceof ICPPClassType) {
return new CompositeCPPClassInstance(this, (ICPPClassType) findOneBinding(binding));

View file

@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2017 Nathan Ridge.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.cdt.internal.core.index.composite.cpp;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableTemplate;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredVariableInstance;
import org.eclipse.core.runtime.CoreException;
public class CompositeCPPDeferredVariableInstance extends CPPDeferredVariableInstance
implements IIndexBinding {
public CompositeCPPDeferredVariableInstance(ICPPVariableTemplate template,
ICPPTemplateArgument[] arguments) {
super(template, arguments);
}
@Override
public boolean isFileLocal() throws CoreException {
return false;
}
@Override
public IIndexFile getLocalToFile() throws CoreException {
return null;
}
@Override
public IIndexBinding getOwner() {
return (IIndexBinding) super.getOwner();
}
}

View file

@ -0,0 +1,82 @@
/*******************************************************************************
* Copyright (c) 2017 Nathan Ridge.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom.cpp;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableTemplate;
import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredVariableInstance;
import org.eclipse.cdt.internal.core.index.IIndexCPPBindingConstants;
import org.eclipse.cdt.internal.core.index.IIndexFragment;
import org.eclipse.cdt.internal.core.index.IIndexFragmentBinding;
import org.eclipse.cdt.internal.core.index.IIndexScope;
import org.eclipse.core.runtime.CoreException;
/**
* PDOM implementation of ICPPDeferredVariableInstance.
*/
public class PDOMCPPDeferredVariableInstance extends CPPDeferredVariableInstance
implements IIndexFragmentBinding {
private final IIndexFragment fFragment;
public PDOMCPPDeferredVariableInstance(IIndexFragment fragment, ICPPVariableTemplate template,
ICPPTemplateArgument[] arguments) {
super(template, arguments);
fFragment = fragment;
}
@Override
public boolean isFileLocal() throws CoreException {
return false;
}
@Override
public IIndexFile getLocalToFile() throws CoreException {
return null;
}
@Override
public IIndexFragment getFragment() {
return fFragment;
}
@Override
public boolean hasDefinition() throws CoreException {
return false;
}
@Override
public boolean hasDeclaration() throws CoreException {
return true;
}
@Override
public int getBindingConstant() {
return IIndexCPPBindingConstants.CPP_DEFERRED_VARIABLE_INSTANCE;
}
@Override
public IIndexScope getScope() {
try {
return (IIndexScope) super.getScope();
} catch (DOMException e) {
return null;
}
}
@Override
public IIndexFragmentBinding getOwner() {
return (IIndexFragmentBinding) super.getOwner();
}
@Override
public long getBindingID() {
return 0;
}
}

View file

@ -95,6 +95,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClosureType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredVariableInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitMethod;
@ -1559,6 +1560,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
return CPPDeferredClassInstance.unmarshal(getPDOM(), firstBytes, buffer);
case ITypeMarshalBuffer.DEFERRED_FUNCTION:
return CPPDeferredFunction.unmarshal(firstBytes, buffer);
case ITypeMarshalBuffer.DEFERRED_VARIABLE_INSTANCE:
return CPPDeferredVariableInstance.unmarshal(getPDOM(), firstBytes, buffer);
case ITypeMarshalBuffer.DEPENDENT_EXPRESSION_TYPE:
IType type= TypeOfDependentExpression.unmarshal(firstBytes, buffer);
if (type instanceof IBinding)