1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 14:42:11 +02:00

Bug 528846 - Handle id-expression that instantiates to pseudo-destructor name of built-in type

The pseudo-destructor is represented as a CPPImplicitFunction, computed
lazily and stored by CPPBasicType.

This commit also adds support for alias templates to
CPPTemplates.getTemplateName().

Change-Id: I6774556b2493cb68d32c3007d6ce48c7805595f4
This commit is contained in:
Nathan Ridge 2017-12-16 19:10:14 -05:00
parent 3e66e22aed
commit 89ec7fe8b8
6 changed files with 80 additions and 11 deletions

View file

@ -10525,4 +10525,16 @@ public class AST2TemplateTests extends AST2CPPTestBase {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertProblem("generate<400>", "generate<400>");
}
// template <typename T> T declval();
//
// template <class T>
// using destructor_expr_t = decltype(declval<T>().~T());
//
// typedef destructor_expr_t<int> Waldo;
public void testDestructorExpressionType_528846() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
IType waldo = helper.assertNonProblem("Waldo");
assertSameType(CommonCPPTypes.void_, waldo);
}
}

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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) {
@ -3235,6 +3238,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).
* Only destructor names require instantiation, e.g. the name "~T", when instantiated
@ -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();
}
}
}

View file

@ -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());
}
}
}