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 1e9b3073fc6..a6cff09c463 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 @@ -10525,4 +10525,16 @@ public class AST2TemplateTests extends AST2CPPTestBase { BindingAssertionHelper helper = getAssertionHelper(); helper.assertProblem("generate<400>", "generate<400>"); } + + // template T declval(); + // + // template + // using destructor_expr_t = decltype(declval().~T()); + // + // typedef destructor_expr_t Waldo; + public void testDestructorExpressionType_528846() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + IType waldo = helper.assertNonProblem("Waldo"); + assertSameType(CommonCPPTypes.void_, waldo); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPBasicType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPBasicType.java index 3093eaab649..3aa121f5bc8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPBasicType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPBasicType.java @@ -46,4 +46,12 @@ public interface ICPPBasicType extends IBasicType { */ @Deprecated public static final int t_wchar_t = ICPPASTSimpleDeclSpecifier.t_wchar_t; + + /** + * Get the built-in type's pseudo-destructor. + * The pseudo-destructor is the function named by e.g. an id-expression + * of the form "T().~T" when instantiated with T mapped to a built-in type. + * @since 6.5 + */ + public ICPPFunction getPseudoDestructor(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPBasicType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPBasicType.java index 4b16b3731d9..f1a7e8c6e79 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPBasicType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPBasicType.java @@ -12,19 +12,24 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; +import static org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter.EMPTY_CPPPARAMETER_ARRAY; + import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IBasicType; +import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; 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.ValueFactory; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.core.runtime.CoreException; /** @@ -52,6 +57,7 @@ public class CPPBasicType implements ICPPBasicType, ISerializableType { private final Kind fKind; private final int fModifiers; private Long fAssociatedValue; + private ICPPFunction fPseudoDestructor; public CPPBasicType(Kind kind, int qualifiers, IASTExpression expression) { if (kind == Kind.eUnspecified) { @@ -321,4 +327,15 @@ public class CPPBasicType implements ICPPBasicType, ISerializableType { public IASTExpression getValue() { return null; } + + @Override + public ICPPFunction getPseudoDestructor() { + if (fPseudoDestructor == null) { + char[] dtorName = ("~" + toString()).toCharArray(); //$NON-NLS-1$ + IScope globalScope = CPPSemantics.getCurrentLookupPoint().getTranslationUnit().getScope(); + fPseudoDestructor = new CPPImplicitFunction(dtorName, globalScope, + CPPClassScope.DESTRUCTOR_FUNCTION_TYPE, EMPTY_CPPPARAMETER_ARRAY, true, false); + } + return fPseudoDestructor; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java index 573d645a556..5814303663b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java @@ -19,7 +19,7 @@ import static org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter.EMPTY_CPPPARAMETER_ import static org.eclipse.cdt.core.parser.util.ArrayUtil.addAll; import static org.eclipse.cdt.core.parser.util.ArrayUtil.appendAt; import static org.eclipse.cdt.core.parser.util.ArrayUtil.trim; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType.UNSPECIFIED_TYPE; +import static org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType.VOID; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; import java.util.Arrays; @@ -69,8 +69,10 @@ import org.eclipse.core.runtime.IStatus; * Base implementation for C++ scopes. */ public class CPPClassScope extends CPPScope implements ICPPClassScope { - private static final ICPPFunctionType DESTRUCTOR_FUNCTION_TYPE = - CPPVisitor.createImplicitFunctionType(UNSPECIFIED_TYPE, EMPTY_CPPPARAMETER_ARRAY, false, false); + // Destructors don't have a return type, but the type of a destructor call expression + // is void, so it's simpler to model them as having a void return type. + public static final ICPPFunctionType DESTRUCTOR_FUNCTION_TYPE = + CPPVisitor.createImplicitFunctionType(VOID, EMPTY_CPPPARAMETER_ARRAY, false, false); private ICPPMethod[] implicits; 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 12346969e22..b575b455836 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 @@ -80,6 +80,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplatedTypeTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplateInstance; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; @@ -2180,6 +2181,8 @@ public class CPPTemplates { IASTDeclarator declarator = ((IASTFunctionDefinition) nestedDecl).getDeclarator(); declarator= ASTQueries.findInnermostDeclarator(declarator); name = declarator.getName(); + } else if (nestedDecl instanceof ICPPASTAliasDeclaration) { + name = ((ICPPASTAliasDeclaration) nestedDecl).getAlias(); } if (name != null) { if (name instanceof ICPPASTQualifiedName) { @@ -3234,6 +3237,17 @@ public class CPPTemplates { } return exec; } + + /** + * If 'name' is a destructor-name, return the name of the type (i.e. the + * portion following the '~'). Otherwise return null. + */ + public static String unwrapDestructorName(char[] name) { + if (name == null || name.length == 0 || name[0] != '~') { + return null; + } + return new String(name).substring(1).trim(); + } /** * Instantiate a plain name (simple-id). @@ -3251,10 +3265,10 @@ public class CPPTemplates { * instantiation context's parameter map, the provided name is returned unchanged. */ public static char[] instantiateName(char[] name, InstantiationContext context, IBinding enclosingTemplate) { - if (name == null || name.length == 0 || name[0] != '~') { + String typename = unwrapDestructorName(name); + if (typename == null) { // not a destructor-name return name; } - String typename = new String(name).substring(1); ICPPTemplateParameterMap map = context.getParameterMap(); IBinding enclosing = enclosingTemplate; while (enclosing != null) { @@ -3267,10 +3281,17 @@ public class CPPTemplates { IType argType = arg.getTypeValue(); argType = SemanticUtil.getNestedType(argType, CVTYPE | TDEF); if (argType instanceof ICPPClassType) { + // Destructor for class type. StringBuilder result = new StringBuilder(); result.append('~'); result.append(((ICPPClassType) argType).getName()); return result.toString().toCharArray(); + } else if (argType instanceof ICPPBasicType) { + // Pseudo-destructor for builtin type. + StringBuilder result = new StringBuilder(); + result.append('~'); + ASTTypeUtil.appendType(argType, true, result); + return result.toString().toCharArray(); } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java index 718e96c0d78..4e1f201b7b1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java @@ -19,6 +19,7 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; +import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; import org.eclipse.cdt.core.dom.ast.IASTExpression; @@ -39,6 +40,7 @@ import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; @@ -400,15 +402,22 @@ public class EvalID extends CPPDependentEvaluation { return EvalFixed.INCOMPLETE; } } - IType fieldOwnerClassTypeCV = SemanticUtil.getNestedType(fieldOwnerType, TDEF | REF); - IType fieldOwnerClassType = SemanticUtil.getNestedType(fieldOwnerClassTypeCV, CVTYPE); - if (fieldOwnerClassType instanceof ICPPClassType) { - ICPPEvaluation eval = resolveName(name, (ICPPClassType) fieldOwnerClassType, fieldOwner, - templateArgs, fieldOwnerClassTypeCV); + IType fieldOwnerTypeSimplifiedCV = SemanticUtil.getNestedType(fieldOwnerType, TDEF | REF); + IType fieldOwnerTypeSimplified = SemanticUtil.getNestedType(fieldOwnerTypeSimplifiedCV, CVTYPE); + if (fieldOwnerTypeSimplified instanceof ICPPClassType) { + ICPPEvaluation eval = resolveName(name, (ICPPClassType) fieldOwnerTypeSimplified, fieldOwner, + templateArgs, fieldOwnerTypeSimplifiedCV); if (eval != null) return eval; - if (!CPPTemplates.isDependentType(fieldOwnerClassType)) + if (!CPPTemplates.isDependentType(fieldOwnerTypeSimplified)) return EvalFixed.INCOMPLETE; + } else if (fieldOwnerTypeSimplified instanceof ICPPBasicType) { + // Handle pseudo-destructor of basic type, e.g. "T().~T" instantiated with [T = int]. + String typename = CPPTemplates.unwrapDestructorName(name); + if (typename != null && typename.equals(ASTTypeUtil.getType(fieldOwnerTypeSimplified))) { + ICPPFunction pseudoDestructor = ((ICPPBasicType) fieldOwnerTypeSimplified).getPseudoDestructor(); + return new EvalBinding(pseudoDestructor, null, getTemplateDefinition()); + } } }