From e2e8b4439d6730803bf32bc45de685a49558a923 Mon Sep 17 00:00:00 2001 From: Andrew Niefer Date: Tue, 10 May 2005 14:40:37 +0000 Subject: [PATCH] handle template explicit instantiations. fixes bug 90689 also fix small bug in template argument deduction --- .../tests/ast2/AST2CPPSpecFailingTest.java | 91 ------------------- .../parser/tests/ast2/AST2CPPSpecTest.java | 84 +++++++++++++++++ .../parser/tests/ast2/AST2TemplateTests.java | 54 ++++++++++- .../core/dom/parser/cpp/CPPTemplates.java | 66 +++++++++++--- .../core/dom/parser/cpp/CPPVisitor.java | 5 +- 5 files changed, 192 insertions(+), 108 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecFailingTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecFailingTest.java index cf89a300259..f42f190628e 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecFailingTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecFailingTest.java @@ -587,97 +587,6 @@ public class AST2CPPSpecFailingTest extends AST2SpecBaseTest { } } - /** - [--Start Example(CPP 14.7.2-2): - template class Array { void mf(); }; - template class Array; - template void Array::mf(); - template void sort(Array& v) { } - template void sort(Array&); // argument is deduced here - namespace N { - template void f(T&) { } - } - template void N::f(int&); - --End Example] - */ - public void test14_7_2s2() throws Exception { - StringBuffer buffer = new StringBuffer(); - buffer.append("template class Array { void mf(); };\n"); //$NON-NLS-1$ - buffer.append("template class Array;\n"); //$NON-NLS-1$ - buffer.append("template void Array::mf();\n"); //$NON-NLS-1$ - buffer.append("template void sort(Array& v) { }\n"); //$NON-NLS-1$ - buffer.append("template void sort(Array&); // argument is deduced here\n"); //$NON-NLS-1$ - buffer.append("namespace N {\n"); //$NON-NLS-1$ - buffer.append("template void f(T&) { }\n"); //$NON-NLS-1$ - buffer.append("}\n"); //$NON-NLS-1$ - buffer.append("template void N::f(int&);\n"); //$NON-NLS-1$ - parse(buffer.toString(), ParserLanguage.CPP, true, 3); - } - - /** - [--Start Example(CPP 14.7.2-6): - template class Array { }; - template void sort(Array& v); - // instantiate sort(Array&) - templateargument deduced - template void sort<>(Array&); - --End Example] - */ - public void test14_7_2s6() { // TODO raised bug 90689 - StringBuffer buffer = new StringBuffer(); - buffer.append("template class Array { };\n"); //$NON-NLS-1$ - buffer.append("template void sort(Array& v);\n"); //$NON-NLS-1$ - buffer.append("// instantiate sort(Array&) - templateargument deduced\n"); //$NON-NLS-1$ - buffer.append("template void sort<>(Array&);\n"); //$NON-NLS-1$ - try { - parse(buffer.toString(), ParserLanguage.CPP, true, 0); - assertTrue(false); - } catch (Exception e) { - } - } - - /** - [--Start Example(CPP 14.7.3-1): - template class stream; - template<> class stream { }; - template class Array { }; - template void sort(Array& v) { } - template<> void sort(Array&) ; - --End Example] - */ - public void test14_7_3s1() { // TODO have similar bug - StringBuffer buffer = new StringBuffer(); - buffer.append("template class stream;\n"); //$NON-NLS-1$ - buffer.append("template<> class stream { };\n"); //$NON-NLS-1$ - buffer.append("template class Array { };\n"); //$NON-NLS-1$ - buffer.append("template void sort(Array& v) { }\n"); //$NON-NLS-1$ - buffer.append("template<> void sort(Array&) ;\n"); //$NON-NLS-1$ - try { - parse(buffer.toString(), ParserLanguage.CPP, true, 0); - assertTrue(false); - } catch (Exception e) { - } - } - - - /** - [--Start Example(CPP 14.7.3-11): - template class Array { }; - template void sort(Array& v); - // explicit specialization for sort(Array&) - // with deduces templateargument of type int - template<> void sort(Array&); - --End Example] - */ - public void test14_7_3s11() throws Exception { - StringBuffer buffer = new StringBuffer(); - buffer.append("template class Array { };\n"); //$NON-NLS-1$ - buffer.append("template void sort(Array& v);\n"); //$NON-NLS-1$ - buffer.append("// explicit specialization for sort(Array&)\n"); //$NON-NLS-1$ - buffer.append("// with deduces templateargument of type int\n"); //$NON-NLS-1$ - buffer.append("template<> void sort(Array&);\n"); //$NON-NLS-1$ - parse(buffer.toString(), ParserLanguage.CPP, true, 1); - } - /** [--Start Example(CPP 14.8.2-2b): template int f(typename T::B*); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java index fb9de73c259..f0719fa6bb4 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java @@ -10224,6 +10224,33 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { parse(buffer.toString(), ParserLanguage.CPP, true, 0); } + /** + [--Start Example(CPP 14.7.2-2): + template class Array { void mf(); }; + template class Array; + template void Array::mf(); + template void sort(Array& v) { } + template void sort(Array&); // argument is deduced here + namespace N { + template void f(T&) { } + } + template void N::f(int&); + --End Example] + */ + public void test14_7_2s2() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("template class Array { void mf(); };\n"); //$NON-NLS-1$ + buffer.append("template class Array;\n"); //$NON-NLS-1$ + buffer.append("template void Array::mf();\n"); //$NON-NLS-1$ + buffer.append("template void sort(Array& v) { }\n"); //$NON-NLS-1$ + buffer.append("template void sort(Array&); // argument is deduced here\n"); //$NON-NLS-1$ + buffer.append("namespace N {\n"); //$NON-NLS-1$ + buffer.append("template void f(T&) { }\n"); //$NON-NLS-1$ + buffer.append("}\n"); //$NON-NLS-1$ + buffer.append("template void N::f(int&);\n"); //$NON-NLS-1$ + parse(buffer.toString(), ParserLanguage.CPP, true, 0); + } + /** [--Start Example(CPP 14.7.2-5): namespace N { @@ -10253,6 +10280,24 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { parse(buffer.toString(), ParserLanguage.CPP, false, 0); } + /** + [--Start Example(CPP 14.7.2-6): + template class Array { }; + template void sort(Array& v); + // instantiate sort(Array&) - templateargument deduced + template void sort<>(Array&); + --End Example] + */ + public void test14_7_2s6() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("template class Array { };\n"); //$NON-NLS-1$ + buffer.append("template void sort(Array& v);\n"); //$NON-NLS-1$ + buffer.append("// instantiate sort(Array&) - templateargument deduced\n"); //$NON-NLS-1$ + buffer.append("template void sort<>(Array&);\n"); //$NON-NLS-1$ + + parse(buffer.toString(), ParserLanguage.CPP, true, 0); + } + /** [--Start Example(CPP 14.7.2-9): char* p = 0; @@ -10268,6 +10313,26 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { parse(buffer.toString(), ParserLanguage.CPP, true, 0); } + /** + [--Start Example(CPP 14.7.3-1): + template class stream; + template<> class stream { }; + template class Array { }; + template void sort(Array& v) { } + template<> void sort(Array&) ; + --End Example] + */ + public void test14_7_3s1() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("template class stream;\n"); //$NON-NLS-1$ + buffer.append("template<> class stream { };\n"); //$NON-NLS-1$ + buffer.append("template class Array { };\n"); //$NON-NLS-1$ + buffer.append("template void sort(Array& v) { }\n"); //$NON-NLS-1$ + buffer.append("template<> void sort(Array&) ;\n"); //$NON-NLS-1$ + + parse(buffer.toString(), ParserLanguage.CPP, true, 0); + } + /** [--Start Example(CPP 14.7.3-3): template<> class X { }; // error: X not a template @@ -10378,6 +10443,25 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { parse(buffer.toString(), ParserLanguage.CPP, true, 0); } + /** + [--Start Example(CPP 14.7.3-11): + template class Array { }; + template void sort(Array& v); + // explicit specialization for sort(Array&) + // with deduces templateargument of type int + template<> void sort(Array&); + --End Example] + */ + public void test14_7_3s11() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("template class Array { };\n"); //$NON-NLS-1$ + buffer.append("template void sort(Array& v);\n"); //$NON-NLS-1$ + buffer.append("// explicit specialization for sort(Array&)\n"); //$NON-NLS-1$ + buffer.append("// with deduces templateargument of type int\n"); //$NON-NLS-1$ + buffer.append("template<> void sort(Array&);\n"); //$NON-NLS-1$ + parse(buffer.toString(), ParserLanguage.CPP, true, 0 ); + } + /** [--Start Example(CPP 14.7.3-17): template class A { 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 10a43745e55..b00f8c0e634 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 @@ -27,6 +27,7 @@ import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPDelegate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; @@ -38,7 +39,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateScope; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable; @@ -1473,4 +1473,56 @@ public class AST2TemplateTests extends AST2BaseTest { CR = (ICPPTemplateParameter) col.getName(14).resolveBinding(); assertSame( CR, T ); } + + public void testBug90689_ExplicitInstantiation() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("template class Array {}; \n"); //$NON-NLS-1$ + buffer.append("template void sort( Array & ); \n"); //$NON-NLS-1$ + buffer.append("template void sort<>( Array & ); \n"); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse( buffer.toString(), ParserLanguage.CPP ); + CPPNameCollector col = new CPPNameCollector(); + tu.accept( col ); + + ICPPClassTemplate A = (ICPPClassTemplate) col.getName(1).resolveBinding(); + ICPPFunctionTemplate s = (ICPPFunctionTemplate) col.getName(3).resolveBinding(); + + ICPPClassType A2 = (ICPPClassType) col.getName(4).resolveBinding(); + assertTrue( A2 instanceof ICPPTemplateInstance ); + assertSame( ((ICPPTemplateInstance)A2).getTemplateDefinition(), A ); + + ICPPFunction s2 = (ICPPFunction) col.getName(8).resolveBinding(); + assertTrue( s2 instanceof ICPPTemplateInstance ); + assertSame( ((ICPPTemplateInstance)s2).getTemplateDefinition(), s ); + + ICPPClassType A3 = (ICPPClassType) col.getName(10).resolveBinding(); + assertTrue( A3 instanceof ICPPTemplateInstance ); + assertSame( ((ICPPTemplateInstance)A3).getTemplateDefinition(), A ); + assertNotSame( A2, A3 ); + } + + public void test14_7_2s2_ExplicitInstantiation() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("template class Array { }; \n"); //$NON-NLS-1$ + buffer.append("template class Array; \n"); //$NON-NLS-1$ + buffer.append("template void sort(Array& v) { } \n"); //$NON-NLS-1$ + buffer.append("template void sort(Array&); // argument is deduced here \n"); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse( buffer.toString(), ParserLanguage.CPP ); + CPPNameCollector col = new CPPNameCollector(); + tu.accept( col ); + + ICPPClassTemplate A1 = (ICPPClassTemplate) col.getName(1).resolveBinding(); + ICPPClassType A2 = (ICPPClassType) col.getName(2).resolveBinding(); + assertTrue( A2 instanceof ICPPTemplateInstance ); + assertSame( ((ICPPTemplateInstance)A2).getTemplateDefinition(), A1 ); + + ICPPFunctionTemplate s1 = (ICPPFunctionTemplate) col.getName(5).resolveBinding(); + ICPPFunction s2 = (ICPPFunction) col.getName(10).resolveBinding(); + assertTrue( s2 instanceof ICPPTemplateInstance ); + assertSame( ((ICPPTemplateInstance)s2).getTemplateDefinition(), s1 ); + + ICPPClassType A3 = (ICPPClassType) col.getName(11).resolveBinding(); + assertSame( A2, A3 ); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplates.java index 4ca76f2da87..33363ca3c88 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplates.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplates.java @@ -42,6 +42,7 @@ import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.cpp.CPPASTVisitor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; @@ -207,7 +208,11 @@ public class CPPTemplates { parent = parent.getParent(); } - if( parent instanceof ICPPASTCompositeTypeSpecifier && segment == 1 ){ + if( parent instanceof ICPPASTElaboratedTypeSpecifier && parent.getParent() instanceof IASTSimpleDeclaration + && segment != 0 ) + { + return createClassExplicitInstantiation( (ICPPASTElaboratedTypeSpecifier) parent ); + } else if( parent instanceof ICPPASTCompositeTypeSpecifier && segment != 0 ){ return createClassSpecialization( (ICPPASTCompositeTypeSpecifier) parent ); } else if( parent instanceof ICPPASTFunctionDeclarator && segment != 0 ){ return createFunctionSpecialization( id ); @@ -247,6 +252,25 @@ public class CPPTemplates { return template; } + protected static IBinding createClassExplicitInstantiation( ICPPASTElaboratedTypeSpecifier elabSpec ){ + IASTName name = elabSpec.getName(); + if( name instanceof ICPPASTQualifiedName ){ + IASTName [] ns = ((ICPPASTQualifiedName)name).getNames(); + name = ns[ ns.length - 1 ]; + } + ICPPASTTemplateId id = (ICPPASTTemplateId) name; + IBinding template = id.getTemplateName().resolveBinding(); + if( !(template instanceof ICPPClassTemplate) ) + return null; //TODO: problem? + + ICPPClassTemplate classTemplate = (ICPPClassTemplate) template; + IType [] args = createTypeArray( id.getTemplateArguments() ); + if( classTemplate instanceof ICPPInternalTemplate ){ + IBinding binding = ((ICPPInternalTemplate)classTemplate).instantiate( args ); + return binding; + } + return null; + } protected static IBinding createClassSpecialization( ICPPASTCompositeTypeSpecifier compSpec ){ IASTName name = compSpec.getName(); if( name instanceof ICPPASTQualifiedName ){ @@ -321,10 +345,10 @@ public class CPPTemplates { protected static IBinding createFunctionSpecialization( IASTName name ){ CPPSemantics.LookupData data = new CPPSemantics.LookupData( name ); data.forceQualified = true; - IScope scope = CPPVisitor.getContainingScope( name ); + ICPPScope scope = (ICPPScope) CPPVisitor.getContainingScope( name ); if( scope instanceof ICPPTemplateScope ){ try { - scope = scope.getParent(); + scope = (ICPPScope) scope.getParent(); } catch (DOMException e) { } } @@ -355,19 +379,25 @@ public class CPPTemplates { return e.getProblem(); } if( map_types != null ){ - ICPPSpecialization spec = null; - if( function instanceof ICPPMethod ) - spec = new CPPMethodSpecialization( function, (ICPPScope) scope, (ObjectMap) map_types[0] ); - else - spec = new CPPFunctionSpecialization( function, (ICPPScope) scope, (ObjectMap) map_types[0] ); - ((ICPPInternalTemplate)function).addSpecialization( (IType[]) map_types[1], spec ); - while( !(parent instanceof IASTDeclaration ) ) + while( !(parent instanceof IASTDeclaration ) ) parent = parent.getParent(); - if( parent instanceof IASTSimpleDeclaration ) - ((ICPPInternalBinding)spec).addDeclaration( name ); - else if( parent instanceof IASTFunctionDefinition ) - ((ICPPInternalBinding)spec).addDefinition( name ); - return spec; + + ICPPSpecialization spec = null; + if( parent.getParent() instanceof ICPPASTExplicitTemplateInstantiation ){ + spec = (ICPPSpecialization) CPPTemplates.createInstance( scope, function, (ObjectMap)map_types[0], (IType[])map_types[1] ); + } else { + if( function instanceof ICPPMethod ) + spec = new CPPMethodSpecialization( function, scope, (ObjectMap) map_types[0] ); + else + spec = new CPPFunctionSpecialization( function, scope, (ObjectMap) map_types[0] ); + + if( parent instanceof IASTSimpleDeclaration ) + ((ICPPInternalBinding)spec).addDeclaration( name ); + else if( parent instanceof IASTFunctionDefinition ) + ((ICPPInternalBinding)spec).addDefinition( name ); + } + ((ICPPInternalTemplate)function).addSpecialization( (IType[]) map_types[1], spec ); + return spec; } //TODO problem? return null; @@ -992,6 +1022,12 @@ public class CPPTemplates { * @return */ static private IType getArgumentTypeForDeduction( IType aType, boolean pIsAReferenceType ) { + if( aType instanceof ICPPReferenceType ){ + try { + aType = ((ICPPReferenceType)aType).getType(); + } catch ( DOMException e ) { + } + } IType result = aType; if( !pIsAReferenceType ){ try { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java index fb009629632..a37bbc43f9b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java @@ -80,6 +80,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression; @@ -445,7 +446,9 @@ public class CPPVisitor { if( parent instanceof IASTTypeId ) return CPPSemantics.resolveBinding( name ); - else if( parent.getPropertyInParent() == ICPPASTTemplateSpecialization.OWNED_DECLARATION ){ + else if( parent.getPropertyInParent() == ICPPASTTemplateSpecialization.OWNED_DECLARATION || + parent.getPropertyInParent() == ICPPASTExplicitTemplateInstantiation.OWNED_DECLARATION ) + { return CPPTemplates.createFunctionSpecialization( name ); }