mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-08 18:26:01 +02:00
Bug 528072 - Implement evaluation of __is_trivially_constructible
Change-Id: I331ea5c2f5203a87290d4ef537a8a75dab384c34
This commit is contained in:
parent
f8cd850957
commit
2ac7089288
9 changed files with 266 additions and 7 deletions
|
@ -12500,4 +12500,19 @@ public class AST2CPPTests extends AST2CPPTestBase {
|
|||
public void test_ElabTypeSpecInNewExprInConditional_526134() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
|
||||
// constexpr bool waldo1 = __is_trivially_constructible(int, short);
|
||||
// struct S { int fMem; S(int mem) : fMem(mem) {} };
|
||||
// constexpr bool waldo2 = __is_trivially_constructible(S);
|
||||
// constexpr bool waldo3 = __is_trivially_constructible(S, const S&);
|
||||
// constexpr bool waldo4 = __is_trivially_constructible(S, int);
|
||||
// constexpr bool waldo5 = __is_trivially_constructible(S, const S&, float);
|
||||
public void testIsTriviallyConstructible_528072() throws Exception {
|
||||
BindingAssertionHelper helper = getAssertionHelper();
|
||||
helper.assertVariableValue("waldo1", 1);
|
||||
helper.assertVariableValue("waldo2", 0);
|
||||
helper.assertVariableValue("waldo3", 1);
|
||||
helper.assertVariableValue("waldo4", 0);
|
||||
helper.assertVariableValue("waldo5", 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,8 @@ public interface ITypeMarshalBuffer {
|
|||
EVAL_CONSTRUCTOR = 0x11,
|
||||
EVAL_REFERENCE = 0x12,
|
||||
EVAL_POINTER = 0x13,
|
||||
EVAL_COMPOSITE_ACCESS = 0x14;
|
||||
EVAL_COMPOSITE_ACCESS = 0x14,
|
||||
EVAL_NARY_TYPE_ID = 0x15;
|
||||
// Can add more evaluations up to 0x1C, after that it will collide with TypeMarshalBuffer.UNSTORABLE_TYPE.
|
||||
|
||||
final static byte
|
||||
|
|
|
@ -37,6 +37,8 @@ import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_typeof;
|
|||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
|
||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTBinaryTypeIdExpression;
|
||||
|
@ -57,6 +59,8 @@ import org.eclipse.cdt.core.dom.ast.IVariable;
|
|||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTBinaryExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionCallExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNaryTypeIdExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNaryTypeIdExpression.Operator;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||
|
@ -267,6 +271,14 @@ public class ValueFactory {
|
|||
return IntegralValue.UNKNOWN;
|
||||
return val;
|
||||
}
|
||||
|
||||
public static IValue evaluateNaryTypeIdExpression(Operator operator, IType[] operands,
|
||||
IBinding pointOfDefinition) {
|
||||
IValue val = applyNaryTypeIdOperator(operator, operands, pointOfDefinition);
|
||||
if (isInvalidValue(val))
|
||||
return IntegralValue.UNKNOWN;
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the canonical representation of the value of the expression.
|
||||
|
@ -595,6 +607,21 @@ public class ValueFactory {
|
|||
}
|
||||
return IntegralValue.UNKNOWN;
|
||||
}
|
||||
|
||||
private static IValue applyNaryTypeIdOperator(ICPPASTNaryTypeIdExpression.Operator operator,
|
||||
IType[] operands, IBinding pointOfDefinition) {
|
||||
switch (operator) {
|
||||
case __is_trivially_constructible:
|
||||
if (operands.length == 0) {
|
||||
return IntegralValue.UNKNOWN;
|
||||
}
|
||||
IType typeToConstruct = operands[0];
|
||||
IType[] argumentTypes = Arrays.copyOfRange(operands, 1, operands.length);
|
||||
return IntegralValue.create(TypeTraits.isTriviallyConstructible(typeToConstruct, argumentTypes,
|
||||
pointOfDefinition) ? 1 : 0);
|
||||
}
|
||||
return IntegralValue.UNKNOWN;
|
||||
}
|
||||
|
||||
private static boolean isInvalidValue(IValue value) {
|
||||
return value == null || value == IntegralValue.UNKNOWN || value == IntegralValue.ERROR;
|
||||
|
|
|
@ -16,11 +16,15 @@ import org.eclipse.cdt.core.dom.ast.IType;
|
|||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNaryTypeIdExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPEvaluation;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalNaryTypeId;
|
||||
|
||||
public class CPPASTNaryTypeIdExpression extends ASTNode implements ICPPASTNaryTypeIdExpression {
|
||||
private Operator fOperator;
|
||||
private ICPPASTTypeId[] fOperands;
|
||||
private ICPPEvaluation fEvaluation;
|
||||
|
||||
public CPPASTNaryTypeIdExpression(Operator operator, ICPPASTTypeId[] operands) {
|
||||
fOperator = operator;
|
||||
|
@ -81,14 +85,23 @@ public class CPPASTNaryTypeIdExpression extends ASTNode implements ICPPASTNaryTy
|
|||
|
||||
@Override
|
||||
public ICPPEvaluation getEvaluation() {
|
||||
// TODO: Implement. This will need a new evaluation type, EvalNaryTypeId.
|
||||
return EvalFixed.INCOMPLETE;
|
||||
if (fEvaluation == null) {
|
||||
IType[] types = new IType[fOperands.length];
|
||||
for (int i = 0; i < fOperands.length; i++) {
|
||||
types[i] = CPPVisitor.createType(fOperands[i]);
|
||||
if (types[i] == null) {
|
||||
fEvaluation = EvalFixed.INCOMPLETE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fEvaluation = new EvalNaryTypeId(fOperator, types, this);
|
||||
}
|
||||
return fEvaluation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType getExpressionType() {
|
||||
// TODO: When getEvaluation() is implemented, delegate to getEvaluation().getType().
|
||||
return CPPBasicType.BOOLEAN;
|
||||
return CPPEvaluation.getType(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext;
|
|||
import org.eclipse.core.runtime.CoreException;
|
||||
|
||||
/**
|
||||
* Performs evaluation of an expression.
|
||||
* Evaluation for a binary type-id expression.
|
||||
*/
|
||||
public class EvalBinaryTypeId extends CPPDependentEvaluation {
|
||||
private final Operator fOperator;
|
||||
|
@ -153,6 +153,6 @@ public class EvalBinaryTypeId extends CPPDependentEvaluation {
|
|||
|
||||
@Override
|
||||
public boolean referencesTemplateParameter() {
|
||||
return CPPTemplates.isDependentType(fType1) || CPPTemplates.isDependentType(fType2);
|
||||
return isValueDependent();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
/*******************************************************************************
|
||||
* 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.semantics;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
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.ICPPASTNaryTypeIdExpression.Operator;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.DependentValue;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ValueFactory;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
||||
/**
|
||||
* Evaluation for a n-ary type-id expression.
|
||||
*/
|
||||
public class EvalNaryTypeId extends CPPDependentEvaluation {
|
||||
private final Operator fOperator;
|
||||
private final IType[] fOperands;
|
||||
|
||||
private boolean fCheckedValueDependent;
|
||||
private boolean fIsValueDependent;
|
||||
|
||||
public EvalNaryTypeId(Operator operator, IType[] operands, IASTNode pointOfDefinition) {
|
||||
this(operator, operands, findEnclosingTemplate(pointOfDefinition));
|
||||
}
|
||||
|
||||
public EvalNaryTypeId(Operator operator, IType[] operands, IBinding templateDefinition) {
|
||||
super(templateDefinition);
|
||||
fOperator = operator;
|
||||
fOperands = operands;
|
||||
}
|
||||
|
||||
public Operator getOperator() {
|
||||
return fOperator;
|
||||
}
|
||||
|
||||
public IType[] getOperands() {
|
||||
return fOperands;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitializerList() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFunctionSet() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeDependent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueDependent() {
|
||||
if (!fCheckedValueDependent) {
|
||||
for (IType operand : fOperands) {
|
||||
if (CPPTemplates.isDependentType(operand)) {
|
||||
fIsValueDependent = true;
|
||||
}
|
||||
}
|
||||
fCheckedValueDependent = true;
|
||||
}
|
||||
return fIsValueDependent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType getType() {
|
||||
switch (fOperator) {
|
||||
case __is_trivially_constructible:
|
||||
return CPPBasicType.BOOLEAN;
|
||||
}
|
||||
return ProblemType.UNKNOWN_FOR_EXPRESSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IValue getValue() {
|
||||
if (isValueDependent()) {
|
||||
return DependentValue.create(this);
|
||||
}
|
||||
|
||||
return ValueFactory.evaluateNaryTypeIdExpression(fOperator, fOperands, getTemplateDefinition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueCategory getValueCategory() {
|
||||
return ValueCategory.PRVALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPEvaluation instantiate(InstantiationContext context, int maxDepth) {
|
||||
IType[] operands = CPPTemplates.instantiateTypes(fOperands, context);
|
||||
if (operands == fOperands) {
|
||||
return this;
|
||||
}
|
||||
return new EvalNaryTypeId(fOperator, operands, getTemplateDefinition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPEvaluation computeForFunctionCall(ActivationRecord record,
|
||||
ConstexprEvaluationContext context) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int determinePackSize(ICPPTemplateParameterMap tpMap) {
|
||||
int result = 0;
|
||||
for (int i = 0; i < fOperands.length; i++) {
|
||||
result = CPPTemplates.combinePackSize(result,
|
||||
CPPTemplates.determinePackSize(fOperands[i], tpMap));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean referencesTemplateParameter() {
|
||||
return isValueDependent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
|
||||
buffer.putShort(ITypeMarshalBuffer.EVAL_NARY_TYPE_ID);
|
||||
buffer.putByte((byte) fOperator.ordinal());
|
||||
buffer.putInt(fOperands.length);
|
||||
for (IType operand : fOperands) {
|
||||
buffer.marshalType(operand);
|
||||
}
|
||||
marshalTemplateDefinition(buffer);
|
||||
}
|
||||
|
||||
public static ICPPEvaluation unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException {
|
||||
int op = buffer.getByte();
|
||||
int len = buffer.getInt();
|
||||
IType[] operands = new IType[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
operands[i] = buffer.unmarshalType();
|
||||
}
|
||||
IBinding templateDefinition = buffer.unmarshalBinding();
|
||||
return new EvalNaryTypeId(Operator.values()[op], operands, templateDefinition);
|
||||
}
|
||||
}
|
|
@ -20,9 +20,11 @@ import java.util.Set;
|
|||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IArrayType;
|
||||
import org.eclipse.cdt.core.dom.ast.IBasicType;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IEnumeration;
|
||||
import org.eclipse.cdt.core.dom.ast.IPointerType;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType;
|
||||
|
@ -30,12 +32,14 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
|||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUnaryTypeTransformation.Operator;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.SemanticQueries;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion;
|
||||
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.CPPBasicType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction;
|
||||
|
@ -43,6 +47,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitConstructor;
|
|||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnaryTypeTransformation;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper.MethodKind;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalFunction;
|
||||
|
||||
/**
|
||||
|
@ -559,4 +564,29 @@ public class TypeTraits {
|
|||
return isScalar(type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if 'typeToConstruct' is trivially constructible from arguments
|
||||
* of type 'argumentTypes', as defined in [meta.unary.prop].
|
||||
*/
|
||||
public static boolean isTriviallyConstructible(IType typeToConstruct, IType[] argumentTypes,
|
||||
IBinding pointOfDefinition) {
|
||||
IType type = SemanticUtil.getSimplifiedType(typeToConstruct);
|
||||
if (!(type instanceof ICPPClassType)) {
|
||||
return true;
|
||||
}
|
||||
// Invent (the evaluation of) a type constructor expression of the form "T(declval<Args>()...)".
|
||||
// (The standard says a variable declaration of the form "T t(declval<Args>()...)",
|
||||
// but we don't currently type-check variable initialization, and a type constructor expression
|
||||
// should have the same semantics.)
|
||||
ICPPEvaluation[] arguments = new ICPPEvaluation[argumentTypes.length];
|
||||
for (int i = 0; i < argumentTypes.length; i++) {
|
||||
// Value category is xvalue because declval() returns an rvalue reference.
|
||||
arguments[i] = new EvalFixed(argumentTypes[i], ValueCategory.XVALUE, IntegralValue.UNKNOWN);
|
||||
}
|
||||
EvalTypeId eval = new EvalTypeId(type, pointOfDefinition, false, false, arguments);
|
||||
ICPPFunction constructor = eval.getConstructor();
|
||||
// TODO check that conversions are trivial as well
|
||||
return constructor instanceof ICPPMethod && ((ICPPMethod) constructor).isImplicit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFunctionSet;
|
|||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalID;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalInitList;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalMemberAccess;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalNaryTypeId;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalPackExpansion;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalTypeId;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalUnary;
|
||||
|
@ -441,6 +442,14 @@ public class CPPCompositesFactory extends AbstractCompositeFactory {
|
|||
compositeTemplateDefinition);
|
||||
return e;
|
||||
}
|
||||
if (eval instanceof EvalNaryTypeId) {
|
||||
EvalNaryTypeId e = (EvalNaryTypeId) eval;
|
||||
IType[] operands = e.getOperands();
|
||||
IType[] operands2 = getCompositeTypes(operands);
|
||||
if (operands != operands2 || templateDefinition != compositeTemplateDefinition)
|
||||
e = new EvalNaryTypeId(e.getOperator(), operands2, compositeTemplateDefinition);
|
||||
return e;
|
||||
}
|
||||
if (eval instanceof EvalPackExpansion) {
|
||||
EvalPackExpansion e = (EvalPackExpansion) eval;
|
||||
ICPPEvaluation a = e.getExpansionPattern();
|
||||
|
|
|
@ -131,6 +131,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFunctionSet;
|
|||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalID;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalInitList;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalMemberAccess;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalNaryTypeId;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalPackExpansion;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalPointer;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalReference;
|
||||
|
@ -1698,6 +1699,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
|
|||
return EvalPointer.unmarshal(firstBytes, buffer);
|
||||
case ITypeMarshalBuffer.EVAL_COMPOSITE_ACCESS:
|
||||
return EvalCompositeAccess.unmarshal(firstBytes, buffer);
|
||||
case ITypeMarshalBuffer.EVAL_NARY_TYPE_ID:
|
||||
return EvalNaryTypeId.unmarshal(firstBytes, buffer);
|
||||
}
|
||||
throw new CoreException(CCorePlugin.createStatus("Cannot unmarshal an evaluation, first bytes=" + firstBytes)); //$NON-NLS-1$
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue