1
0
Fork 0
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:
Nathan Ridge 2017-12-03 15:11:08 -05:00
parent f8cd850957
commit 2ac7089288
9 changed files with 266 additions and 7 deletions

View file

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

View file

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

View file

@ -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;
@ -268,6 +272,14 @@ public class ValueFactory {
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.
*/
@ -596,6 +608,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;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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