1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 14:12:10 +02:00

Bug 545021 - Implement noexcept operator

- Adds getNoexceptSpecifier() to ICPPFunctionType, returning the
evaluation for the noexcept specifier.
- Adds isNoexcept() to ICPPEvaluation, which returns the result of
applying the noexcept operator to the evaluation.
- Empty throw() specifier is treated as noexcept(true).
- Improves EvalTypeID.isConstantExpression() for conversions.

Change-Id: I4c6418aea21bb258693b33d956bc3745918f3759
Signed-off-by: Hannes Vogt <hannes@havogt.de>
This commit is contained in:
Hannes Vogt 2019-03-08 23:00:22 +01:00 committed by Nathan Ridge
parent 0552fcbf97
commit f938b4d08e
44 changed files with 531 additions and 46 deletions

View file

@ -11645,10 +11645,10 @@ public class AST2CPPTests extends AST2CPPTestBase {
ICPPFunction waldo3 = helper.assertNonProblem("waldo3");
// constexpr on a function *should not* make its return type const
assertSameType(waldo1.getType().getReturnType(), CommonCPPTypes.int_);
assertSameType(waldo2.getType().getReturnType(),
new CPPPointerType(new CPPFunctionType(CommonCPPTypes.int_, new IType[] { CommonCPPTypes.int_ })));
assertSameType(waldo2.getType().getReturnType(), new CPPPointerType(
new CPPFunctionType(CommonCPPTypes.int_, new IType[] { CommonCPPTypes.int_ }, null)));
// constexpr on a method *should not* make the method const
assertSameType(waldo3.getType(), new CPPFunctionType(CommonCPPTypes.int_, new IType[] {}));
assertSameType(waldo3.getType(), new CPPFunctionType(CommonCPPTypes.int_, new IType[] {}, null));
}
// void waldo() noexcept;
@ -13135,4 +13135,211 @@ public class AST2CPPTests extends AST2CPPTestBase {
parseAndCheckImplicitNameBindings();
}
// int fun();
// int fun_noexcept() noexcept;
// int fun2(int);
// int fun2_noexcept(int) noexcept;
// constexpr int fun_constexpr() {return 1;}
// int (*fptr)();
// int (*fptr_noexcept)() noexcept;
// bool condition();
//
// constexpr bool fun_is_not_noexcept = noexcept(fun());
// constexpr bool unevaluated_fun_is_noexcept = noexcept(fun);
// constexpr bool fun_noexcept_is_noexcept = noexcept(fun_noexcept());
// constexpr bool fun2_arg_is_not_noexcept = noexcept(fun2(1));
// constexpr bool fun2_noexcept_arg_is_noexcept = noexcept(fun2_noexcept(1));
// constexpr bool fun2_noexcept_arg_not_noexcept_is_not_noexcept = noexcept(fun2_noexcept(fun()));
// constexpr bool fun_constexpr_is_noexcept = noexcept(fun_constexpr());
// constexpr bool fptr_is_not_noexcept = noexcept(fptr());
// constexpr bool fptr_noexcept_is_noexcept = noexcept(fptr_noexcept());
// constexpr bool throw_is_not_noexcept = noexcept(throw fun_noexcept());
public void testNoexceptOperatorFunctions_545021() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("fun_is_not_noexcept", 0);
helper.assertVariableValue("unevaluated_fun_is_noexcept", 1);
helper.assertVariableValue("fun_noexcept_is_noexcept", 1);
helper.assertVariableValue("fun2_arg_is_not_noexcept", 0);
helper.assertVariableValue("fun2_noexcept_arg_is_noexcept", 1);
helper.assertVariableValue("fun2_noexcept_arg_not_noexcept_is_not_noexcept", 0);
helper.assertVariableValue("fun_constexpr_is_noexcept", 1);
helper.assertVariableValue("fptr_is_not_noexcept", 0);
helper.assertVariableValue("fptr_noexcept_is_noexcept", 1);
helper.assertVariableValue("throw_is_not_noexcept", 0);
}
// int fun();
// int fun_noexcept() noexcept;
// bool condition();
// bool noexcept_condition() noexcept;
// constexpr bool comma_is_noexcept = noexcept(fun_noexcept(), fun_noexcept());
// constexpr bool comma_is_not_noexcept = noexcept(fun(), fun_noexcept());
// constexpr bool not_noexcept_conditional = noexcept(noexcept_condition() ? fun() : fun_noexcept());
// constexpr bool is_noexcept_conditional = noexcept(noexcept_condition() ? fun_noexcept() : fun_noexcept());
// constexpr bool condition_not_noexcept = noexcept(condition() ? fun_noexcept() : fun_noexcept());
public void testNoexceptOperatorOperators_545021() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("comma_is_noexcept", 1);
helper.assertVariableValue("comma_is_not_noexcept", 0);
helper.assertVariableValue("not_noexcept_conditional", 0);
helper.assertVariableValue("is_noexcept_conditional", 1);
helper.assertVariableValue("condition_not_noexcept", 0);
}
// struct aggregate{
// int a;
// };
// aggregate agg;
//
// constexpr bool aggregate_init_is_noexcept = noexcept(aggregate{1});
// constexpr bool aggregate_access_is_noexcept = noexcept(agg.a);
public void testNoexceptOperatorAggregate_545021() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("aggregate_init_is_noexcept", 1);
helper.assertVariableValue("aggregate_access_is_noexcept", 1);
}
// struct myclass{
// myclass() noexcept{}
// myclass(int){}
// constexpr myclass(int, int){}
// };
// constexpr bool ctor_is_noexcept = noexcept(myclass{});
// constexpr bool ctor_is_not_noexcept = noexcept(myclass{1});
// constexpr bool constexpr_ctor_is_noexcept = noexcept(myclass{1, 1});
public void testNoexceptOperatorConstructors_545021() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("ctor_is_noexcept", 1);
helper.assertVariableValue("ctor_is_not_noexcept", 0);
helper.assertVariableValue("constexpr_ctor_is_noexcept", 1);
}
// struct type {
// int mem();
// int mem_noexcept() noexcept;
// constexpr int constexpr_mem() {return 1;}
// operator int() noexcept;
// operator int*();
// };
// type t;
// int (type::*memptr)();
// int (type::*memptr_noexcept)() noexcept;
// constexpr bool mem_is_not_noexcept = noexcept(type{}.mem());
// constexpr bool unevaluated_mem_is_noexcept = noexcept(type{}.mem);
// constexpr bool mem_noexcept_is_noexcept = noexcept(type{}.mem_noexcept());
// constexpr bool constexpr_mem_is_noexcept = noexcept(type{}.constexpr_mem());
// constexpr bool memptr_is_not_noexcept = noexcept((type{}.*(memptr))());
// constexpr bool unevaluated_memptr_is_noexcept = noexcept((type{}.*(memptr)));
// constexpr bool memptr_noexcept_is_noexcept = noexcept((type{}.*(memptr_noexcept))());
// constexpr bool noexcept_conversion = noexcept(static_cast<int>(t));
// constexpr bool not_noexcept_conversion = noexcept(static_cast<int*>(t));
// constexpr bool conversion_from_constructor = noexcept(static_cast<int*>(type{}));
public void testNoexceptOperatorType_545021() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("mem_is_not_noexcept", 0);
helper.assertVariableValue("unevaluated_mem_is_noexcept", 1);
helper.assertVariableValue("mem_noexcept_is_noexcept", 1);
helper.assertVariableValue("constexpr_mem_is_noexcept", 1);
helper.assertVariableValue("memptr_is_not_noexcept", 0);
// TODO(havogt): needs implementation of [except.spec] p.14 (c++11) noexcept for implicitly declared special member functions
// helper.assertVariableValue("unevaluated_memptr_is_noexcept", 1);
helper.assertVariableValue("memptr_noexcept_is_noexcept", 1);
helper.assertVariableValue("noexcept_conversion", 1);
helper.assertVariableValue("not_noexcept_conversion", 0);
helper.assertVariableValue("conversion_from_constructor", 0);
}
// template<typename T>
// int funt(T);
// template<typename T>
// int funt_noexcept(T) noexcept;
//
// constexpr bool funt_is_not_noexcept = noexcept(funt(1));
// constexpr bool funt_noexcept_is_noexcept = noexcept(funt_noexcept(1));
public void testNoexceptOperatorFunctionTemplates_545021() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("funt_is_not_noexcept", 0);
helper.assertVariableValue("funt_noexcept_is_noexcept", 1);
}
// struct type1{
// void operator=(int);
// bool operator!();
// };
// type1 t1;
// struct type2{
// void operator=(int) noexcept;
// bool operator!() noexcept;
// };
// type2 t2;
// constexpr bool binaryop_is_not_noexcept = noexcept(t1 = 1);
// constexpr bool unaryop_is_not_noexcept = noexcept(!t1);
// constexpr bool noexcept_binaryop_is_noexcept = noexcept(t2 = 1);
// constexpr bool noexcept_unaryop_is_noexcept = noexcept(!t2);
public void testNoexceptOperatorOverloadedOperators_545021() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("binaryop_is_not_noexcept", 0);
helper.assertVariableValue("unaryop_is_not_noexcept", 0);
helper.assertVariableValue("noexcept_binaryop_is_noexcept", 1);
helper.assertVariableValue("noexcept_unaryop_is_noexcept", 1);
}
// void fun();
// void fun_taking_funptr(void(*ptr)()) noexcept;
//
// constexpr bool is_noexcept = noexcept(fun_taking_funptr(fun));
public void testNoexceptOperatorNoncalledFunctionPtr_545021() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("is_noexcept", 1);
}
// void fun() throw();
// constexpr bool is_noexcept = noexcept(fun());
public void testNoexceptOperatorEmptyThrow_545021() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("is_noexcept", 1);
}
// auto closure_noexcept = [](int i) noexcept {return i;};
// constexpr bool is_noexcept = noexcept(closure_noexcept());
// auto closure = [](int i) {return i;};
// constexpr bool is_not_noexcept = noexcept(closure());
// constexpr bool conversion_is_noexcept = noexcept(static_cast<int (*)(int)>(closure));
public void testNoexceptOperatorLambda_545021() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("is_noexcept", 1);
helper.assertVariableValue("is_not_noexcept", 0);
helper.assertVariableValue("conversion_is_noexcept", 1);
}
// template <bool B>
// void foo() noexcept(B);
//
// constexpr bool is_noexcept = noexcept(foo<true>());
// constexpr bool is_not_noexcept = noexcept(foo<false>());
public void testNoexceptOperatorDependentNoexcept_545021() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("is_noexcept", 1);
helper.assertVariableValue("is_not_noexcept", 0);
}
// struct S { int mem; };
// S foo(); // could throw
// constexpr bool is_not_noexcept = noexcept(foo().mem); // should be false
public void testNoexceptOperatorOwnerEval_545021() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("is_not_noexcept", 0);
}
}

View file

@ -2552,4 +2552,12 @@ public class IndexCPPBindingResolutionTest extends IndexBindingResolutionTestBas
public void testOOM_529646() throws Exception {
checkBindings();
}
// int foo() noexcept;
// constexpr bool is_noexcept = noexcept(foo());
public void testNoexceptOperator_545021() throws Exception {
IVariable isNoexcept = getBindingFromASTName("is_noexcept", 11);
assertEquals(1, isNoexcept.getInitialValue().numberValue().longValue());
}
}

View file

@ -21,6 +21,7 @@ import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
/**
* C++ adds a few things to function declarators.
@ -154,6 +155,14 @@ public interface ICPPASTFunctionDeclarator extends IASTStandardFunctionDeclarato
*/
public ICPPASTExpression getNoexceptExpression();
/**
* Returns the noexcept evaluation, or {@code null} if no noexcept specification is present, or
* or an evaluation representing {@code noexcept(true)} in case of an empty exception specification.
* @since 6.7
* @noreference This method is not intended to be referenced by clients.
*/
public ICPPEvaluation getNoexceptEvaluation();
/**
* Sets the noexcept expression.
* @since 5.5

View file

@ -17,6 +17,7 @@ package org.eclipse.cdt.core.dom.ast.cpp;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
/**
* @noextend This interface is not intended to be extended by clients.
@ -45,6 +46,13 @@ public interface ICPPFunctionType extends IFunctionType {
*/
public boolean isRValueReference();
/**
* Returns the evaluation object for the noexcept specifier or null if there is no noexcept specifier.
* @since 6.7
* @noreference This method is not intended to be referenced by clients.
*/
public ICPPEvaluation getNoexceptSpecifier();
/**
* Whether the function type takes variable number of arguments.
* @since 5.2

View file

@ -494,7 +494,7 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
theParms[i] = fCpp ? new CPPBuiltinParameter(pType) : new CBuiltinParameter(pType);
}
IType rt = toType(returnType);
IFunctionType ft = fCpp ? new CPPFunctionType(rt, pTypes) : new CFunctionType(rt, pTypes);
IFunctionType ft = fCpp ? new CPPFunctionType(rt, pTypes, null) : new CFunctionType(rt, pTypes);
IBinding b = fCpp
? new CPPImplicitFunction(toCharArray(name), fScope, (ICPPFunctionType) ft, (ICPPParameter[]) theParms,
@ -608,7 +608,7 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
} else if (tstr.equals("va_list")) {
// Use 'char*(*)()'
IType rt = toType("char*");
t = fCpp ? new CPPPointerType(new CPPFunctionType(rt, IType.EMPTY_TYPE_ARRAY))
t = fCpp ? new CPPPointerType(new CPPFunctionType(rt, IType.EMPTY_TYPE_ARRAY, null))
: new CPointerType(new CFunctionType(rt, IType.EMPTY_TYPE_ARRAY), 0);
} else if (tstr.equals("size_t")) {
t = toType("unsigned long");

View file

@ -18,6 +18,7 @@ import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.core.runtime.CoreException;
/**
@ -81,4 +82,9 @@ public class ProblemFunctionType extends ProblemType implements ICPPFunctionType
public IPointerType getThisType() {
return new CPPPointerType(new ProblemType(getID()));
}
@Override
public ICPPEvaluation getNoexceptSpecifier() {
return null;
}
}

View file

@ -43,7 +43,7 @@ public class CExternalFunction extends CFunction implements ICExternalBinding {
public IFunctionType getType() {
if (type == null) {
// Bug 321856: Prevent recursions
type = new CPPFunctionType(VOID_TYPE, IType.EMPTY_TYPE_ARRAY);
type = new CPPFunctionType(VOID_TYPE, IType.EMPTY_TYPE_ARRAY, null);
IFunctionType computedType = createType();
if (computedType != null) {
type = computedType;

View file

@ -18,6 +18,7 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
@ -31,11 +32,16 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVirtSpecifier.SpecifierKind;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionScope;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
/**
* Represents a function declarator.
*/
public class CPPASTFunctionDeclarator extends CPPASTDeclarator implements ICPPASTFunctionDeclarator {
public static final ICPPEvaluation NOEXCEPT_TRUE = new EvalFixed(CPPBasicType.BOOLEAN, ValueCategory.PRVALUE,
IntegralValue.create(true));
private ICPPASTParameterDeclaration[] parameters;
private IASTTypeId[] typeIds = NO_EXCEPTION_SPECIFICATION;
private ICPPASTExpression noexceptExpression;
@ -388,4 +394,14 @@ public class CPPASTFunctionDeclarator extends CPPASTDeclarator implements ICPPAS
}
}
}
@Override
public ICPPEvaluation getNoexceptEvaluation() {
if (getNoexceptExpression() != null) {
return getNoexceptExpression().getEvaluation();
} else if (getExceptionSpecification() == IASTTypeId.EMPTY_TYPEID_ARRAY) {
return NOEXCEPT_TRUE;
}
return null;
}
}

View file

@ -103,7 +103,7 @@ public class CPPASTTranslationUnit extends ASTTranslationUnit implements ICPPAST
IBinding temp = null;
IType[] newParms = new IType[1];
newParms[0] = cpp_size_t;
ICPPFunctionType newFunctionType = new CPPFunctionType(cpp_void_p, newParms);
ICPPFunctionType newFunctionType = new CPPFunctionType(cpp_void_p, newParms, null);
ICPPParameter[] newTheParms = new ICPPParameter[1];
newTheParms[0] = new CPPBuiltinParameter(newParms[0]);
temp = new CPPImplicitFunction(OverloadableOperator.NEW.toCharArray(), theScope, newFunctionType, newTheParms,
@ -120,7 +120,7 @@ public class CPPASTTranslationUnit extends ASTTranslationUnit implements ICPPAST
temp = null;
IType[] deleteParms = new IType[1];
deleteParms[0] = cpp_void_p;
ICPPFunctionType deleteFunctionType = new CPPFunctionType(cpp_void, deleteParms);
ICPPFunctionType deleteFunctionType = new CPPFunctionType(cpp_void, deleteParms, null);
ICPPParameter[] deleteTheParms = new ICPPParameter[1];
deleteTheParms[0] = new CPPBuiltinParameter(deleteParms[0]);
temp = new CPPImplicitFunction(OverloadableOperator.DELETE.toCharArray(), theScope, deleteFunctionType,

View file

@ -115,7 +115,8 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP
// Function call operator
final IType returnType = getReturnType();
final IType[] parameterTypes = getParameterTypes();
ft = new CPPFunctionType(returnType, parameterTypes, !isMutable(), false, false, false, false);
ft = new CPPFunctionType(returnType, parameterTypes, getNoexceptEvaluation(), !isMutable(), false, false, false,
false);
ICPPParameter[] params = getParameters();
char[] operatorParensName = OverloadableOperator.PAREN.toCharArray();
@ -139,8 +140,9 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP
// Conversion operator
if (needConversionOperator) {
final CPPFunctionType conversionTarget = new CPPFunctionType(returnType, parameterTypes);
ft = new CPPFunctionType(conversionTarget, IType.EMPTY_TYPE_ARRAY, true, false, false, false, false);
final CPPFunctionType conversionTarget = new CPPFunctionType(returnType, parameterTypes, null);
ft = new CPPFunctionType(conversionTarget, IType.EMPTY_TYPE_ARRAY,
CPPASTFunctionDeclarator.NOEXCEPT_TRUE /* (CWG DR 1722) */, true, false, false, false, false);
// Calling CPPASTConversionName.createName(IType) would try to stringize the type to
// construct a name, which is unnecessary work (not to mention prone to recursion with
// dependent types). Since the name doesn't matter anyways, just make one up.
@ -258,6 +260,13 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP
return fParameterTypes;
}
private ICPPEvaluation getNoexceptEvaluation() {
ICPPEvaluation eval = null;
if (fLambdaExpression.getDeclarator() != null)
eval = fLambdaExpression.getDeclarator().getNoexceptEvaluation();
return eval;
}
public ICPPParameter[] getParameters() {
if (fParameters == null) {
final IType[] parameterTypes = getParameterTypes();

View file

@ -36,7 +36,7 @@ import org.eclipse.core.runtime.CoreException;
public class CPPDeferredFunction extends CPPUnknownBinding
implements ICPPDeferredFunction, ICPPComputableFunction, ISerializableType {
private static final ICPPFunctionType FUNCTION_TYPE = new CPPFunctionType(ProblemType.UNKNOWN_FOR_EXPRESSION,
IType.EMPTY_TYPE_ARRAY);
IType.EMPTY_TYPE_ARRAY, null);
/**
* Creates a CPPDeferredFunction given a set of overloaded functions

View file

@ -37,13 +37,14 @@ public class CPPFunctionType implements ICPPFunctionType, ISerializableType {
private final boolean hasRefQualifier;
private final boolean isRValueReference;
private final boolean takesVarargs;
private final ICPPEvaluation noexceptSpecifier;
public CPPFunctionType(IType returnType, IType[] types) {
this(returnType, types, false, false, false, false, false);
public CPPFunctionType(IType returnType, IType[] types, ICPPEvaluation noexceptSpecifier) {
this(returnType, types, noexceptSpecifier, false, false, false, false, false);
}
public CPPFunctionType(IType returnType, IType[] types, boolean isConst, boolean isVolatile,
boolean hasRefQualifier, boolean isRValueReference, boolean takesVarargs) {
public CPPFunctionType(IType returnType, IType[] types, ICPPEvaluation noexceptSpecifier, boolean isConst,
boolean isVolatile, boolean hasRefQualifier, boolean isRValueReference, boolean takesVarargs) {
this.returnType = returnType;
this.parameters = types;
this.isConst = isConst;
@ -51,6 +52,7 @@ public class CPPFunctionType implements ICPPFunctionType, ISerializableType {
this.hasRefQualifier = hasRefQualifier;
this.isRValueReference = isRValueReference;
this.takesVarargs = takesVarargs;
this.noexceptSpecifier = noexceptSpecifier;
}
@Override
@ -167,6 +169,7 @@ public class CPPFunctionType implements ICPPFunctionType, ISerializableType {
for (int i = 0; i < parameters.length; i++) {
buffer.marshalType(parameters[i]);
}
buffer.marshalEvaluation(noexceptSpecifier, true);
}
public static IType unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException {
@ -176,11 +179,18 @@ public class CPPFunctionType implements ICPPFunctionType, ISerializableType {
for (int i = 0; i < pars.length; i++) {
pars[i] = buffer.unmarshalType();
}
ICPPEvaluation noexcept = buffer.unmarshalEvaluation();
boolean isConst = (firstBytes & ITypeMarshalBuffer.FLAG1) != 0;
boolean takesVarargs = (firstBytes & ITypeMarshalBuffer.FLAG2) != 0;
boolean isVolatile = (firstBytes & ITypeMarshalBuffer.FLAG3) != 0;
boolean hasRefQualifier = (firstBytes & ITypeMarshalBuffer.FLAG4) != 0;
boolean isRValueReference = (firstBytes & ITypeMarshalBuffer.FLAG5) != 0;
return new CPPFunctionType(rt, pars, isConst, isVolatile, hasRefQualifier, isRValueReference, takesVarargs);
return new CPPFunctionType(rt, pars, noexcept, isConst, isVolatile, hasRefQualifier, isRValueReference,
takesVarargs);
}
@Override
public ICPPEvaluation getNoexceptSpecifier() {
return noexceptSpecifier;
}
}

View file

@ -27,7 +27,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
*/
public class CPPUnknownMethod extends CPPUnknownMember implements ICPPMethod {
private static final ICPPFunctionType FUNCTION_TYPE = new CPPFunctionType(ProblemType.UNKNOWN_FOR_EXPRESSION,
IType.EMPTY_TYPE_ARRAY);
IType.EMPTY_TYPE_ARRAY, null);
public CPPUnknownMethod(IType owner, char[] name) {
super(owner, name);

View file

@ -51,6 +51,12 @@ public interface ICPPEvaluation {
*/
boolean isConstantExpression();
/**
* Return the result of the noexcept-operator applied to the expression.
* [expr.unary.noexcept]
*/
boolean isNoexcept();
/**
* Returns {@code true} if this expression is equivalent to 'other' for
* declaration matching purposes.

View file

@ -41,7 +41,7 @@ class AutoTypeResolver implements ICPPFunctionTemplate {
private final CPPFunctionType functionType;
public AutoTypeResolver(IType paramType) {
functionType = new CPPFunctionType(new CPPBasicType(Kind.eVoid, 0), new IType[] { paramType });
functionType = new CPPFunctionType(new CPPBasicType(Kind.eVoid, 0), new IType[] { paramType }, null);
}
@Override

View file

@ -555,7 +555,7 @@ class BuiltinOperators {
private void addFunction(IType returnType, IType[] parameterTypes) {
ICPPParameter[] parameter = new ICPPParameter[parameterTypes.length];
ICPPFunctionType functionType = new CPPFunctionType(returnType, parameterTypes);
ICPPFunctionType functionType = new CPPFunctionType(returnType, parameterTypes, null);
String sig = ASTTypeUtil.getType(functionType, true);
if (fSignatures == null) {
fSignatures = new HashSet<>();

View file

@ -172,9 +172,10 @@ public abstract class CPPEvaluation implements ICPPEvaluation {
* @param argument the evaluation to convert
* @param targetType the type to convert to
* @param allowContextualConversion enable/disable explicit contextual conversion
* @param onlyConstexprConversion allow only constexpr conversion operators
*/
protected static ICPPEvaluation maybeApplyConversion(ICPPEvaluation argument, IType targetType,
boolean allowContextualConversion) {
boolean allowContextualConversion, boolean onlyConstexprConversion) {
if (targetType == null) {
return argument;
}
@ -195,7 +196,7 @@ public abstract class CPPEvaluation implements ICPPEvaluation {
targetType, false, allowContextualConversion);
ICPPFunction conversion = cost.getUserDefinedConversion();
if (conversion != null) {
if (!conversion.isConstexpr()) {
if (onlyConstexprConversion && !conversion.isConstexpr()) {
return EvalFixed.INCOMPLETE;
}
ICPPEvaluation eval = new EvalMemberAccess(uqType, valueCategory, conversion, argument, false,

View file

@ -4132,7 +4132,7 @@ public class CPPSemantics {
parms[i] = t;
theParms[i] = new CPPBuiltinParameter(t);
}
ICPPFunctionType functionType = new CPPFunctionType(returnType, parms);
ICPPFunctionType functionType = new CPPFunctionType(returnType, parms, null);
return new CPPImplicitFunction(CALL_FUNCTION, scope, functionType, theParms, false, false);
}

View file

@ -1559,7 +1559,10 @@ public class CPPTemplates {
IType[] params = instantiateTypes(ps, context);
final IType r = ft.getReturnType();
IType ret = instantiateType(r, context);
if (ret == r && params == ps) {
ICPPEvaluation noex = ft.getNoexceptSpecifier();
ICPPEvaluation noexcept = noex == null ? null
: noex.instantiate(context, IntegralValue.MAX_RECURSION_DEPTH);
if (ret == r && params == ps && noexcept == noex) {
return type;
}
// The parameter types need to be adjusted.
@ -1569,7 +1572,8 @@ public class CPPTemplates {
params[i] = CPPVisitor.adjustParameterType(p, true);
}
}
return new CPPFunctionType(ret, params, ft.isConst(), ft.isVolatile(), ft.hasRefQualifier(),
return new CPPFunctionType(ret, params, noexcept, ft.isConst(), ft.isVolatile(), ft.hasRefQualifier(),
ft.isRValueReference(), ft.takesVarArgs());
}
@ -2609,8 +2613,8 @@ public class CPPTemplates {
IType[] parameterTypesWithExplicitArguments = Arrays.copyOf(originalType.getParameterTypes(),
nExplicitArgs);
return new CPPFunctionType(originalType.getReturnType(), parameterTypesWithExplicitArguments,
originalType.isConst(), originalType.isVolatile(), originalType.hasRefQualifier(),
originalType.isRValueReference(), originalType.takesVarArgs());
originalType.getNoexceptSpecifier(), originalType.isConst(), originalType.isVolatile(),
originalType.hasRefQualifier(), originalType.isRValueReference(), originalType.takesVarArgs());
} else
return originalType;
}
@ -2966,7 +2970,7 @@ public class CPPTemplates {
Cost cost = Conversions.checkImplicitConversionSequence(p, a, LVALUE, UDCMode.FORBIDDEN, Context.ORDINARY);
if (cost == null || !cost.converts()) {
ICPPEvaluation eval = arg.getNonTypeEvaluation();
ICPPEvaluation newEval = CPPEvaluation.maybeApplyConversion(eval, p, false);
ICPPEvaluation newEval = CPPEvaluation.maybeApplyConversion(eval, p, false, true);
if (newEval == EvalFixed.INCOMPLETE && newEval != eval)
return null;
return new CPPTemplateNonTypeArgument(newEval);

View file

@ -1899,7 +1899,9 @@ public class CPPVisitor extends ASTQueries {
pTypes[i] = pt;
}
return new CPPFunctionType(returnType, pTypes, isConst, isVolatile, false, false, false);
return new CPPFunctionType(returnType, pTypes,
null /* TODO(havogt) [except.spec] p.14 (c++11) noexcept for implicitly declared special member functions not implemented */,
isConst, isVolatile, false, false, false);
}
/**
@ -1946,8 +1948,8 @@ public class CPPVisitor extends ASTQueries {
}
RefQualifier refQualifier = fnDtor.getRefQualifier();
CPPFunctionType type = new CPPFunctionType(returnType, pTypes, fnDtor.isConst(), fnDtor.isVolatile(),
refQualifier != null, refQualifier == RefQualifier.RVALUE, fnDtor.takesVarArgs());
CPPFunctionType type = new CPPFunctionType(returnType, pTypes, fnDtor.getNoexceptEvaluation(), fnDtor.isConst(),
fnDtor.isVolatile(), refQualifier != null, refQualifier == RefQualifier.RVALUE, fnDtor.takesVarArgs());
final IASTDeclarator nested = fnDtor.getNestedDeclarator();
if (nested != null) {
return createType(type, nested);
@ -2546,8 +2548,9 @@ public class CPPVisitor extends ASTQueries {
// above.
IType[] pTypes = createParameterTypes(declarator);
RefQualifier refQualifier = declarator.getRefQualifier();
IType result = new CPPFunctionType(returnType, pTypes, declarator.isConst(), declarator.isVolatile(),
refQualifier != null, refQualifier == RefQualifier.RVALUE, declarator.takesVarArgs());
IType result = new CPPFunctionType(returnType, pTypes, declarator.getNoexceptEvaluation(),
declarator.isConst(), declarator.isVolatile(), refQualifier != null,
refQualifier == RefQualifier.RVALUE, declarator.takesVarArgs());
final IASTDeclarator nested = declarator.getNestedDeclarator();
if (nested != null) {
result = createType(result, nested);

View file

@ -184,8 +184,8 @@ public class EvalBinary extends CPPDependentEvaluation {
IType[] parameterTypes = SemanticUtil.getParameterTypesIncludingImplicitThis(overload);
if (parameterTypes.length >= 2) {
boolean allowContextualConversion = operatorAllowsContextualConversion();
arg1 = maybeApplyConversion(fArg1, parameterTypes[0], allowContextualConversion);
arg2 = maybeApplyConversion(fArg2, parameterTypes[1], allowContextualConversion);
arg1 = maybeApplyConversion(fArg1, parameterTypes[0], allowContextualConversion, true);
arg2 = maybeApplyConversion(fArg2, parameterTypes[1], allowContextualConversion, true);
} else {
CCorePlugin.log(IStatus.ERROR, "Unexpected overload for binary operator " + fOperator //$NON-NLS-1$
+ ": '" + overload.getName() + "'"); //$NON-NLS-1$//$NON-NLS-2$
@ -611,4 +611,14 @@ public class EvalBinary extends CPPDependentEvaluation {
public String toString() {
return fArg1.toString() + " <op> " + fArg2.toString(); //$NON-NLS-1$
}
@Override
public boolean isNoexcept() {
ICPPFunction overload = getOverload();
if (overload != null) {
if (!EvalUtil.evaluateNoexceptSpecifier(overload.getType().getNoexceptSpecifier()))
return false;
}
return fArg1.isNoexcept() && fArg2.isNoexcept();
}
}

View file

@ -167,4 +167,9 @@ public class EvalBinaryTypeId extends CPPDependentEvaluation {
public boolean referencesTemplateParameter() {
return isValueDependent();
}
@Override
public boolean isNoexcept() {
return true;
}
}

View file

@ -532,4 +532,9 @@ public class EvalBinding extends CPPDependentEvaluation {
public String toString() {
return getBinding().toString();
}
@Override
public boolean isNoexcept() {
return true;
}
}

View file

@ -265,4 +265,18 @@ public class EvalComma extends CPPDependentEvaluation {
}
return false;
}
@Override
public boolean isNoexcept() {
if (getOverloads() != null)
for (ICPPFunction overload : getOverloads()) {
if (overload != null && !EvalUtil.evaluateNoexceptSpecifier(overload.getType().getNoexceptSpecifier()))
return false;
}
for (ICPPEvaluation arg : fArguments) {
if (!arg.isNoexcept())
return false;
}
return true;
}
}

View file

@ -188,4 +188,9 @@ public final class EvalCompositeAccess implements ICPPEvaluation {
int elementId = buffer.getInt();
return new EvalCompositeAccess(parent, elementId);
}
@Override
public boolean isNoexcept() {
return parent.isNoexcept();
}
}

View file

@ -142,4 +142,9 @@ public class EvalCompoundStatementExpression extends CPPDependentEvaluation {
public boolean referencesTemplateParameter() {
return fDelegate.referencesTemplateParameter();
}
@Override
public boolean isNoexcept() {
return fDelegate.isNoexcept();
}
}

View file

@ -417,4 +417,9 @@ public class EvalConditional extends CPPDependentEvaluation {
|| (fPositive != null && fPositive.referencesTemplateParameter())
|| fNegative.referencesTemplateParameter();
}
@Override
public boolean isNoexcept() {
return fCondition.isNoexcept() && fPositive.isNoexcept() && fNegative.isNoexcept();
}
}

View file

@ -391,4 +391,9 @@ public final class EvalConstructor extends CPPDependentEvaluation {
return new EvalConstructor(newType, newConstructor, newArguments, getTemplateDefinition());
}
@Override
public boolean isNoexcept() {
return EvalUtil.evaluateNoexceptSpecifier(fConstructor.getType().getNoexceptSpecifier());
}
}

View file

@ -226,4 +226,9 @@ public final class EvalFixed extends CPPEvaluation {
public String toString() {
return fType.toString() + ": " + fValue.toString(); //$NON-NLS-1$
}
@Override
public boolean isNoexcept() {
return true;
}
}

View file

@ -33,6 +33,7 @@ import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
@ -42,6 +43,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.dom.parser.CompositeValue;
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.cpp.CPPClosureType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecution;
@ -126,7 +128,7 @@ public final class EvalFunctionCall extends CPPDependentEvaluation {
}
private boolean computeIsConstantExpression() {
return areAllConstantExpressions(fArguments) && isNullOrConstexprFunc(getOverload());
return areAllConstantExpressions(fArguments) && isNullOrConstexprFunc(resolveFunctionBinding());
}
@Override
@ -425,7 +427,7 @@ public final class EvalFunctionCall extends CPPDependentEvaluation {
break;
} else {
if (j < arguments.length) {
ICPPEvaluation argument = maybeApplyConversion(arguments[j++], param.getType(), false);
ICPPEvaluation argument = maybeApplyConversion(arguments[j++], param.getType(), false, true);
record.update(param, argument);
} else if (param.hasDefaultValue()) {
IValue value = param.getDefaultValue();
@ -495,4 +497,37 @@ public final class EvalFunctionCall extends CPPDependentEvaluation {
return null;
}
}
ICPPFunctionType resolveFunctionType() {
ICPPFunction function = resolveFunctionBinding();
if (function != null) {
return function.getType();
}
IType result = fArguments[0].getType();
if (result instanceof IPointerType) {
result = ((IPointerType) result).getType();
} else if (result instanceof CPPClosureType) {
result = ((CPPClosureType) result).getFunctionCallOperator().getType();
}
if (result instanceof ICPPFunctionType) {
return (ICPPFunctionType) result;
}
return null;
}
@Override
public boolean isNoexcept() {
ICPPFunctionType fctType = resolveFunctionType();
if (fctType != null) {
if (!EvalUtil.evaluateNoexceptSpecifier(fctType.getNoexceptSpecifier()))
return false;
}
for (int i = 1; i < fArguments.length; i++) {
ICPPEvaluation eval = fArguments[i];
if (!eval.isNoexcept())
return false;
}
return true;
}
}

View file

@ -380,4 +380,10 @@ public class EvalFunctionSet extends CPPDependentEvaluation {
public boolean referencesTemplateParameter() {
return false;
}
@Override
public boolean isNoexcept() {
assert false; // Shouldn't exist outside of a dependent context
return true;
}
}

View file

@ -513,4 +513,10 @@ public class EvalID extends CPPDependentEvaluation {
public boolean referencesTemplateParameter() {
return fFieldOwner != null && fFieldOwner.referencesTemplateParameter();
}
@Override
public boolean isNoexcept() {
assert false; // Shouldn't exist outside of a dependent context
return true;
}
}

View file

@ -180,4 +180,13 @@ public class EvalInitList extends CPPDependentEvaluation {
}
return false;
}
@Override
public boolean isNoexcept() {
for (ICPPEvaluation eval : getClauses()) {
if (!eval.isNoexcept())
return false;
}
return true;
}
}

View file

@ -470,4 +470,9 @@ public class EvalMemberAccess extends CPPDependentEvaluation {
public boolean referencesTemplateParameter() {
return false;
}
@Override
public boolean isNoexcept() {
return fOwnerEval.isNoexcept();
}
}

View file

@ -169,4 +169,9 @@ public class EvalNaryTypeId extends CPPDependentEvaluation {
IBinding templateDefinition = buffer.unmarshalBinding();
return new EvalNaryTypeId(Operator.values()[op], operands, templateDefinition);
}
@Override
public boolean isNoexcept() {
return true;
}
}

View file

@ -145,4 +145,10 @@ public class EvalPackExpansion extends CPPDependentEvaluation {
IBinding templateDefinition = buffer.unmarshalBinding();
return new EvalPackExpansion(expansionPattern, templateDefinition);
}
@Override
public boolean isNoexcept() {
assert false; // Shouldn't exist outside of a dependent context
return true;
}
}

View file

@ -193,4 +193,10 @@ public class EvalReference extends CPPDependentEvaluation {
return new EvalReference(record, referredBinding, templateDefinition);
}
}
@Override
public boolean isNoexcept() {
assert false;
return true;
}
}

View file

@ -250,6 +250,12 @@ public class EvalTypeId extends CPPDependentEvaluation {
}
private boolean computeIsConstantExpression() {
if (getConstructor() == null && fArguments.length == 1) {
// maybe EvalTypeID represents a conversion
ICPPEvaluation conversionEval = maybeApplyConversion(fArguments[0], fInputType, false, false);
if (!conversionEval.isConstantExpression())
return false;
}
return !fRepresentsNewExpression && areAllConstantExpressions(fArguments)
&& isNullOrConstexprFunc(getConstructor());
}
@ -477,4 +483,24 @@ public class EvalTypeId extends CPPDependentEvaluation {
}
return false;
}
@Override
public boolean isNoexcept() {
if (getConstructor() instanceof CPPFunction) {
CPPFunction f = (CPPFunction) getConstructor();
if (f != AGGREGATE_INITIALIZATION) {
if (!EvalUtil.evaluateNoexceptSpecifier(f.getType().getNoexceptSpecifier()))
return false;
}
} else if (fArguments.length == 1) {
// maybe EvalTypeID represents a conversion
ICPPEvaluation conversionEval = maybeApplyConversion(fArguments[0], fInputType, false, false);
return conversionEval.isNoexcept();
}
for (ICPPEvaluation arg : fArguments) {
if (!arg.isNoexcept())
return false;
}
return true;
}
}

View file

@ -313,7 +313,7 @@ public class EvalUnary extends CPPDependentEvaluation {
if (parameterTypes.length == 0)
return IntegralValue.ERROR;
IType targetType = parameterTypes[0];
arg = maybeApplyConversion(arg, targetType, fOperator == op_not);
arg = maybeApplyConversion(arg, targetType, fOperator == op_not, false);
if (!(overload instanceof CPPImplicitFunction)) {
if (!overload.isConstexpr())
@ -334,7 +334,11 @@ public class EvalUnary extends CPPDependentEvaluation {
return info == null ? IntegralValue.UNKNOWN : IntegralValue.create(info.alignment);
}
case op_noexcept:
return IntegralValue.UNKNOWN; // TODO(sprigogin): Implement
// [expr.unary.noexcept]
if (arg.isConstantExpression())
return IntegralValue.create(true);
else
return IntegralValue.create(arg.isNoexcept());
case op_sizeofParameterPack:
IValue opVal = fArgument.getValue();
return IntegralValue.create(opVal.numberOfSubValues());
@ -523,4 +527,16 @@ public class EvalUnary extends CPPDependentEvaluation {
public boolean referencesTemplateParameter() {
return fArgument.referencesTemplateParameter();
}
@Override
public boolean isNoexcept() {
if (fOperator == op_throw)
return false;
ICPPFunction overload = getOverload();
if (overload != null) {
if (!EvalUtil.evaluateNoexceptSpecifier(overload.getType().getNoexceptSpecifier()))
return false;
}
return fArgument.isNoexcept();
}
}

View file

@ -297,4 +297,9 @@ public class EvalUnaryTypeID extends CPPDependentEvaluation {
}
return EvalFixed.INCOMPLETE;
}
@Override
public boolean isNoexcept() {
return true;
}
}

View file

@ -203,4 +203,13 @@ public class EvalUtil {
public static boolean isDefaultConstructor(ICPPConstructor constructor) {
return constructor.getRequiredArgumentCount() == 0;
}
public static boolean evaluateNoexceptSpecifier(ICPPEvaluation noexceptSpecifier) {
if (noexceptSpecifier != null && noexceptSpecifier.getValue() instanceof IntegralValue) {
IntegralValue v = (IntegralValue) noexceptSpecifier.getValue();
if (v.numberValue() != null)
return v.numberValue().longValue() == 1;
}
return false;
}
}

View file

@ -361,8 +361,8 @@ public class SemanticUtil {
if (ret == r && params == ps) {
return type;
}
return new CPPFunctionType(ret, params, ft.isConst(), ft.isVolatile(), ft.hasRefQualifier(),
ft.isRValueReference(), ft.takesVarArgs());
return new CPPFunctionType(ret, params, ft.getNoexceptSpecifier(), ft.isConst(), ft.isVolatile(),
ft.hasRefQualifier(), ft.isRValueReference(), ft.takesVarArgs());
}
if (type instanceof ITypedef) {

View file

@ -178,8 +178,10 @@ public class CPPCompositesFactory extends AbstractCompositeFactory {
IType r2 = getCompositeType(r);
IType[] p = ft.getParameterTypes();
IType[] p2 = getCompositeTypes(p);
if (r != r2 || p != p2) {
return new CPPFunctionType(r2, p2, ft.isConst(), ft.isVolatile(), ft.hasRefQualifier(),
ICPPEvaluation n = ft.getNoexceptSpecifier();
ICPPEvaluation n2 = getCompositeEvaluation(n);
if (r != r2 || p != p2 || n != n2) {
return new CPPFunctionType(r2, p2, n2, ft.isConst(), ft.isVolatile(), ft.hasRefQualifier(),
ft.isRValueReference(), ft.takesVarArgs());
}
return ft;

View file

@ -296,10 +296,13 @@ public class PDOM extends PlatformObject implements IPDOM {
* CDT 9.5 development (version not supported on the 9.4.x branch)
* 212.0 - C++ constexpr if and if init-statement evaluation
* 213.0 - C++ switch init-statement evaluation
*
* CDT 9.8 development (version not supported on the 9.7.x branch)
* 214.0 - Noexcept specifier in CPPFunctionType, bug 545021
*/
private static final int MIN_SUPPORTED_VERSION = version(213, 0);
private static final int MAX_SUPPORTED_VERSION = version(213, Short.MAX_VALUE);
private static final int DEFAULT_VERSION = version(213, 0);
private static final int MIN_SUPPORTED_VERSION = version(214, 0);
private static final int MAX_SUPPORTED_VERSION = version(214, Short.MAX_VALUE);
private static final int DEFAULT_VERSION = version(214, 0);
private static int version(int major, int minor) {
return (major << 16) + minor;