From ac121def1a55b343af2c205ca406d2a357ba8aed Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Sun, 24 May 2015 16:59:53 -0700 Subject: [PATCH] Bug 466362 - StackOverflowError involving self-referencing template definition Change-Id: I101dff395f6e58a6852010419045f583eebd47e8 --- .../core/parser/tests/ast2/AST2TemplateTests.java | 14 +++---- .../tests/IndexCPPTemplateResolutionTest.java | 35 ++++++++++++++++ .../cdt/core/dom/ast/cpp/ICPPFunctionInstance.java | 2 +- .../cdt/core/dom/ast/cpp/ICPPTemplateInstance.java | 15 +++---- .../core/dom/parser/cpp/CPPClassInstance.java | 17 +++++--- .../core/dom/parser/cpp/CPPFunctionInstance.java | 2 +- .../dom/parser/cpp/semantics/CPPSemantics.java | 2 +- .../composite/cpp/CompositeCPPClassInstance.java | 3 ++ .../cpp/CompositeCPPFunctionInstance.java | 3 ++ .../org/eclipse/cdt/internal/core/pdom/PDOM.java | 9 ++-- .../core/pdom/dom/cpp/PDOMCPPClassInstance.java | 8 +--- .../pdom/dom/cpp/PDOMCPPClassSpecialization.java | 48 ++++++++++++++++------ .../core/pdom/dom/cpp/PDOMCPPFunctionInstance.java | 2 +- 13 files changed, 110 insertions(+), 50 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 4c5c5fb..46bfdb7 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 @@ -5858,17 +5858,17 @@ public class AST2TemplateTests extends AST2TestBase { assertSame(template, inst.getTemplateDefinition()); } - // template class A{}; - // template class A{}; - // template class A{}; + // template class A {}; + // template class A {}; + // template class A {}; // template<> class A; // A fooA(); // - // template class B{}; - // template class B{}; - // template class B{}; + // template class B {}; + // template class B {}; + // template class B {}; // template<> class B {}; - // A fooB(); + // B fooB(); public void testExplicitSpecializationOfForbiddenAsImplicit_356818() throws Exception { parseAndCheckBindings(); } 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 6faf3af..69752c7 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 @@ -2533,6 +2533,22 @@ public class IndexCPPTemplateResolutionTest extends IndexBindingResolutionTestBa } // template + // struct A { + // static T* get(); + // }; + + // class B { + // friend class A; + // }; + // + // void test() { + // A::get(); + // } + public void testFriendClassSpecialization_466362() throws Exception { + checkBindings(); + } + + // template // constexpr T t(T) { // return 0; // } @@ -2626,6 +2642,25 @@ public class IndexCPPTemplateResolutionTest extends IndexBindingResolutionTestBa checkBindings(); } + // // Empty header file + + // typedef unsigned long size_t; + // + // template struct int_pack { typedef int_pack type; }; + // + // template struct append; + // + // template + // struct append, I> : int_pack {}; + // + // template + // struct make_int_pack : append::type, C - 1> {}; + // + // template <> struct make_int_pack<0> : int_pack<> {}; + public void testRecursiveInheritance_466362() throws Exception { + checkBindings(); + } + // template // struct Bar {}; // diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPFunctionInstance.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPFunctionInstance.java index fd21483..06506ea 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPFunctionInstance.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPFunctionInstance.java @@ -11,7 +11,7 @@ package org.eclipse.cdt.core.dom.ast.cpp; /** - * This interface represents an instantiation of a function template. + * This interface represents an instantiation or an explicit specialization of a function template. * * @noimplement This interface is not intended to be implemented by clients. * @noextend This interface is not intended to be extended by clients. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPTemplateInstance.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPTemplateInstance.java index 654a57f..eba7477 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPTemplateInstance.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPTemplateInstance.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2010 IBM Corporation and others. + * Copyright (c) 2005, 2015 IBM Corporation and others. * 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 @@ -14,20 +14,17 @@ package org.eclipse.cdt.core.dom.ast.cpp; import org.eclipse.cdt.core.dom.ast.IType; /** - * This interface represents an instantiation of a class or function template. - * An instantiated template is a specialization of that template. + * This interface represents an instantiation or an explicit specialization of a class or a function template. + * The {@link #isExplicitSpecialization()} method is used to distinguish between the two cases. * - * An instance of a class template will also implement ICPPClassType and similarly - * a function template instance will also implement ICPPFunction (or even ICPPMethod - * or ICPPConstructor as appropriate) + * An instance of a class template will also implement ICPPClassType and similarly a function template + * instance will also implement ICPPFunction (or even ICPPMethod or ICPPConstructor as appropriate). * * @noimplement This interface is not intended to be implemented by clients. * @noextend This interface is not intended to be extended by clients. */ public interface ICPPTemplateInstance extends ICPPSpecialization { - /** - * @since 5.1 - */ + /** @since 5.1 */ ICPPTemplateInstance[] EMPTY_TEMPLATE_INSTANCE_ARRAY = {}; /** diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassInstance.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassInstance.java index 35538ad..ff41984 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassInstance.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassInstance.java @@ -28,7 +28,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates; /** - * The result of instantiating a class template. + * The result of instantiating a class template or an explicit specialization of a class template. */ public class CPPClassInstance extends CPPClassSpecialization implements ICPPTemplateInstance { private final ICPPTemplateArgument[] arguments; @@ -50,20 +50,25 @@ public class CPPClassInstance extends CPPClassSpecialization implements ICPPTemp @Override protected ICPPClassSpecializationScope getSpecializationScope() { - // An instance with a declaration has no specialization scope. + // An instance with a definition has no specialization scope. checkForDefinition(); if (getDefinition() != null) return null; - final IASTNode[] decls = getDeclarations(); - if (decls != null && decls.length > 0 && decls[0] != null) - return null; return super.getSpecializationScope(); } @Override public boolean isExplicitSpecialization() { - return !(getCompositeScope() instanceof ICPPClassSpecializationScope); + // An instance with a declaration is an explicit specialization. + checkForDefinition(); + if (getDefinition() != null) + return true; + final IASTNode[] decls = getDeclarations(); + if (decls != null && decls.length > 0 && decls[0] != null) + return true; + + return false; } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionInstance.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionInstance.java index da48553..41ad1dd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionInstance.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionInstance.java @@ -25,7 +25,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates; /** - * The instantiation of a function template. + * An instantiation or an explicit specialization of a function template. */ public class CPPFunctionInstance extends CPPFunctionSpecialization implements ICPPFunctionInstance { private final ICPPTemplateArgument[] fArguments; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index ab80e3e..116dd13 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -83,12 +83,12 @@ import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTTypeIdInitializerExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; -import org.eclipse.cdt.core.dom.ast.IField; import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.ICompositeType; import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IEnumerator; +import org.eclipse.cdt.core.dom.ast.IField; import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.IPointerType; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPClassInstance.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPClassInstance.java index 1e2f71a..0b7636b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPClassInstance.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPClassInstance.java @@ -19,6 +19,9 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.internal.core.index.composite.ICompositesFactory; +/** + * The result of instantiating a class template or an explicit specialization of a class template. + */ public class CompositeCPPClassInstance extends CompositeCPPClassSpecialization implements ICPPTemplateInstance { public CompositeCPPClassInstance(ICompositesFactory cf, ICPPClassType rbinding) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPFunctionInstance.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPFunctionInstance.java index 9cdf57d..898deb6 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPFunctionInstance.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPFunctionInstance.java @@ -23,6 +23,9 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.core.parser.util.ObjectMap; import org.eclipse.cdt.internal.core.index.composite.ICompositesFactory; +/** + * An instantiation or an explicit specialization of a function template. + */ public class CompositeCPPFunctionInstance extends CompositeCPPFunction implements ICPPFunctionInstance { public CompositeCPPFunctionInstance(ICompositesFactory cf, ICPPFunction rbinding) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index d003131..ef27d6d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -257,14 +257,15 @@ public class PDOM extends PlatformObject implements IPDOM { * CDT 8.6 development (versions not supported on the 8.5.x branch) * 180.0 - Internal types of enumerators, bug 446711. * 180.1 - Storing types of unknown members, bug 447728. - * 180.2 - Do not apply significant macros to source files, bug 450888. + * 180.2 - Do not apply significant macros to source files, bug 450888. <> * * CDT 8.7 development (versions not supported on the 8.6.x branch) * 181.0 - C function type with varargs, bug 452416. + * 182.0 - A flag added to PDOMCPPClassSpecialization, bug 466362. */ - private static final int MIN_SUPPORTED_VERSION= version(181, 0); - private static final int MAX_SUPPORTED_VERSION= version(181, Short.MAX_VALUE); - private static final int DEFAULT_VERSION = version(181, 0); + private static final int MIN_SUPPORTED_VERSION= version(182, 0); + private static final int MAX_SUPPORTED_VERSION= version(182, Short.MAX_VALUE); + private static final int DEFAULT_VERSION = version(182, 0); private static int version(int major, int minor) { return (major << 16) + minor; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassInstance.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassInstance.java index 8256547..0c34117 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassInstance.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassInstance.java @@ -29,7 +29,7 @@ import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; import org.eclipse.core.runtime.CoreException; /** - * Result of instantiating a class template. + * The result of instantiating a class template or an explicit specialization of a class template. */ class PDOMCPPClassInstance extends PDOMCPPClassSpecialization implements ICPPTemplateInstance { private static final int ARGUMENTS = PDOMCPPClassSpecialization.RECORD_SIZE + 0; @@ -102,12 +102,6 @@ class PDOMCPPClassInstance extends PDOMCPPClassSpecialization implements ICPPTem } @Override - protected boolean hasOwnScope() throws CoreException { - // An instance with a declaration does not use the original template. - return hasDeclaration(); - } - - @Override public boolean isExplicitSpecialization() { return !(getCompositeScope() instanceof ICPPClassSpecializationScope); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassSpecialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassSpecialization.java index 0e3b704..0c3e42e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassSpecialization.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassSpecialization.java @@ -41,6 +41,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassSpecialization; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassSpecialization.RecursionResolvingBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPClassSpecializationScope; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates; import org.eclipse.cdt.internal.core.index.IIndexCPPBindingConstants; import org.eclipse.cdt.internal.core.pdom.dom.IPDOMMemberOwner; @@ -57,13 +58,16 @@ class PDOMCPPClassSpecialization extends PDOMCPPSpecialization implements ICPPClassSpecialization, IPDOMMemberOwner, IPDOMCPPClassType { private static final int FIRST_BASE = PDOMCPPSpecialization.RECORD_SIZE + 0; private static final int MEMBERLIST = FIRST_BASE + 4; - private static final int FINAL = MEMBERLIST + PDOMCPPMemberBlock.RECORD_SIZE; // byte + private static final int FLAGS = MEMBERLIST + PDOMCPPMemberBlock.RECORD_SIZE; // byte /** * The size in bytes of a PDOMCPPClassSpecialization record in the database. */ @SuppressWarnings("hiding") - protected static final int RECORD_SIZE = FINAL + 1; + protected static final int RECORD_SIZE = FLAGS + 1; + + private static final byte FLAGS_FINAL = 0x01; + private static final byte FLAGS_HAS_OWN_SCOPE = 0x02; private volatile ICPPClassScope fScope; private ObjectMap specializationMap; // Obtained from the synchronized PDOM cache. @@ -77,7 +81,7 @@ class PDOMCPPClassSpecialization extends PDOMCPPSpecialization public PDOMCPPClassSpecialization(PDOMCPPLinkage linkage, PDOMNode parent, ICPPClassType classType, PDOMBinding specialized) throws CoreException { super(linkage, parent, (ICPPSpecialization) classType, specialized); - setFinal(classType); + setFlags(classType); } public PDOMCPPClassSpecialization(PDOMLinkage linkage, long bindingRecord) { @@ -87,8 +91,8 @@ class PDOMCPPClassSpecialization extends PDOMCPPSpecialization @Override public void update(PDOMLinkage linkage, IBinding newBinding) throws CoreException { if (newBinding instanceof ICPPClassType) { - ICPPClassType ct= (ICPPClassType) newBinding; - setFinal(ct); + ICPPClassType classType= (ICPPClassType) newBinding; + setFlags(classType); super.update(linkage, newBinding); } } @@ -179,10 +183,6 @@ class PDOMCPPClassSpecialization extends PDOMCPPSpecialization return fScope; } - protected boolean hasOwnScope() throws CoreException { - return hasDefinition(); - } - public PDOMCPPBase getFirstBase() throws CoreException { long rec = getDB().getRecPtr(record + FIRST_BASE); return rec != 0 ? new PDOMCPPBase(getLinkage(), rec) : null; @@ -471,15 +471,37 @@ class PDOMCPPClassSpecialization extends PDOMCPPSpecialization @Override public boolean isFinal() { try { - return getDB().getByte(record + FINAL) != 0; - } catch (CoreException e){ + return (getFlags() & FLAGS_FINAL) != 0; + } catch (CoreException e) { CCorePlugin.log(e); return false; } } - private void setFinal(ICPPClassType ct) throws CoreException { - getDB().putByte(record + FINAL, (byte) (ct.isFinal() ? 1 : 0)); + private boolean hasOwnScope() throws CoreException { + return (getFlags() & FLAGS_HAS_OWN_SCOPE) != 0; + } + + private byte getFlags() throws CoreException { + return getDB().getByte(record + FLAGS); + } + + private void setFlags(ICPPClassType classType) throws CoreException { + byte flags = (byte) ((classType.isFinal() ? FLAGS_FINAL : 0) | (hasOwnScope(classType) ? FLAGS_HAS_OWN_SCOPE : 0)); + getDB().putByte(record + FLAGS, flags); + } + + /** + * Returns true if the given class is an explicit template specialization that has its own definition. + */ + private static boolean hasOwnScope(ICPPClassType classType) { + if (!(classType instanceof ICPPInternalBinding)) + return false; + + ICPPInternalBinding binding = (ICPPInternalBinding) classType; + if (binding.getDefinition() != null) + return true; + return false; } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPFunctionInstance.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPFunctionInstance.java index 8002981..7df19bd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPFunctionInstance.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPFunctionInstance.java @@ -29,7 +29,7 @@ import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; import org.eclipse.core.runtime.CoreException; /** - * Result of instantiating a function template. + * An instantiation or an explicit specialization of a function template. */ class PDOMCPPFunctionInstance extends PDOMCPPFunctionSpecialization implements ICPPFunctionInstance { private static final int ARGUMENTS = PDOMCPPFunctionSpecialization.RECORD_SIZE + 0; -- 2.7.4