1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 09:25:31 +02:00

Conversion to reference types, bug 263778.

This commit is contained in:
Markus Schorn 2009-02-05 13:56:09 +00:00
parent 6c3c6c4eae
commit 45233921c6
4 changed files with 191 additions and 166 deletions

View file

@ -2504,7 +2504,12 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest {
// y.g(); //error
// }
public void test9_3_2s4() throws Exception {
parse(getAboveComment(), ParserLanguage.CPP, true, 0);
String[] problems= {"g"};
final String code = getAboveComment();
IASTTranslationUnit tu= parse(code, ParserLanguage.CPP, problems);
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
bh.assertNonProblem("g();", 1);
bh.assertProblem("g(); //error", 1);
}
// class process {

View file

@ -884,6 +884,7 @@ public class CPPSemantics {
return null;
}
HashSet<IBinding> baseBindings= bases.length > 1 ? new HashSet<IBinding>() : null;
for (ICPPBase base : bases) {
if (base instanceof IProblemBinding)
continue;
@ -899,9 +900,11 @@ public class CPPSemantics {
continue;
}
inherited = null;
final ICPPClassType cls = (ICPPClassType) b;
if (baseBindings != null && !baseBindings.add(cls))
continue;
inherited = null;
final ICPPScope classScope = (ICPPScope) cls.getCompositeScope();
if (classScope == null || classScope instanceof ICPPInternalUnknownScope) {
// 14.6.2.3 scope is not examined
@ -2504,7 +2507,9 @@ public class CPPSemantics {
private static ICPPVariable createVariable(IASTName name, final IType type, final boolean isConst, final boolean isVolatile) {
return new CPPVariable(name) {
@Override public IType getType() {
return new CPPQualifierType(type, isConst, isVolatile);
if (isConst || isVolatile)
return new CPPQualifierType(type, isConst, isVolatile);
return type;
}
};
}

View file

@ -14,8 +14,7 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateTypeViaTypedefs;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.DOMException;
@ -67,142 +66,141 @@ public class Conversions {
*/
public static Cost checkImplicitConversionSequence(boolean allowUDC, IASTExpression sourceExp,
IType source, IType target, boolean isImpliedObject) throws DOMException {
Cost cost;
allowUDC &= !isImpliedObject;
target= getUltimateTypeViaTypedefs(target);
source= getUltimateTypeViaTypedefs(source);
target= getNestedType(target, TYPEDEFS);
source= getNestedType(source, TYPEDEFS);
if (target instanceof ICPPReferenceType) {
// [13.3.3.3.1] Reference binding
IType cv1T1= getUltimateTypeViaTypedefs(((ICPPReferenceType) target).getType());
cost= new Cost(source, cv1T1);
cost.targetHadReference= true;
// [8.5.3-5] initialization of a reference
IType cv1T1= getNestedType(target, TYPEDEFS | REFERENCES);
boolean lvalue= sourceExp == null || !CPPVisitor.isRValue(sourceExp);
if (source instanceof ICPPReferenceType)
source= getNestedType(source, TYPEDEFS | REFERENCES);
boolean lvalue= sourceExp == null || !CPPVisitor.isRValue(sourceExp);
IType T2= source instanceof IQualifierType ?
getUltimateTypeViaTypedefs(((IQualifierType) source).getType()) : source;
getNestedType(((IQualifierType) source).getType(), TYPEDEFS | REFERENCES) : source;
if (lvalue && isReferenceCompatible(cv1T1, source)) {
// Direct reference binding
// [13.3.3.1.4]
if (cost.source.isSameType(cost.target) ||
// 7.3.3.13 for overload resolution the implicit this pointer is treated as if
// it were a pointer to the derived class
(isImpliedObject && cost.source instanceof ICPPClassType &&
cost.target instanceof ICPPClassType)) {
cost.rank = Cost.IDENTITY_RANK;
// [8.5.3-5] Is an lvalue (but is not a bit-field), and "cv1 T1" is reference-compatible with "cv2 T2,"
if (lvalue) {
Cost cost= isReferenceCompatible(cv1T1, source);
if (cost != null) {
// [8.5.3-5] this is a direct reference binding
// [13.3.3.1.4-1] direct binding has either identity or conversion rank.
// 7.3.3.13 for overload resolution the implicit this pointer is treated as if
// it were a pointer to the derived class
if (isImpliedObject)
cost.conversion= 0;
// [13.3.3.1.4]
if (cost.conversion > 0) {
cost.rank= Cost.DERIVED_TO_BASE_CONVERSION;
} else {
cost.rank = Cost.IDENTITY_RANK;
}
return cost;
}
// Is an lvalue (but is not a bit-field), and "cv1 T1" is reference-compatible with "cv2 T2,"
// [13.3.3.1.4-1] direct binding
// [8.5.3-5]
qualificationConversion(cost);
derivedToBaseConversion(cost);
} else if (T2 instanceof ICPPClassType) {
if (allowUDC) {
// Or has a class type (i.e., T2 is a class type) and can be implicitly converted to
// an lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible with "cv3 T3" 92)
// (this conversion is selected by enumerating the applicable conversion functions
// (13.3.1.6) and choosing the best one through overload resolution (13.3)).
ICPPMethod[] fcns= SemanticUtil.getConversionOperators((ICPPClassType) T2);
Cost operatorCost= null;
ICPPMethod conv= null;
boolean ambiguousConversionOperator= false;
if (fcns.length > 0 && !(fcns[0] instanceof IProblemBinding)) {
for (final ICPPMethod op : fcns) {
Cost cost2 = checkStandardConversionSequence(op.getType().getReturnType(), target,
false);
if (cost2.rank != Cost.NO_MATCH_RANK) {
if (operatorCost == null) {
}
}
if (T2 instanceof ICPPClassType && allowUDC) {
// Or has a class type (i.e., T2 is a class type) and can be implicitly converted to
// an lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible with "cv3 T3" 92)
// (this conversion is selected by enumerating the applicable conversion functions
// (13.3.1.6) and choosing the best one through overload resolution (13.3)).
ICPPMethod[] fcns= SemanticUtil.getConversionOperators((ICPPClassType) T2);
Cost operatorCost= null;
ICPPMethod conv= null;
boolean ambiguousConversionOperator= false;
if (fcns.length > 0 && !(fcns[0] instanceof IProblemBinding)) {
for (final ICPPMethod op : fcns) {
Cost cost2 = checkStandardConversionSequence(op.getType().getReturnType(), cv1T1,
false);
if (cost2.rank != Cost.NO_MATCH_RANK) {
if (operatorCost == null) {
operatorCost= cost2;
conv= op;
} else {
int cmp= operatorCost.compare(cost2);
if (cmp >= 0) {
ambiguousConversionOperator= cmp == 0;
operatorCost= cost2;
conv= op;
} else {
int cmp= operatorCost.compare(cost2);
if (cmp >= 0) {
ambiguousConversionOperator= cmp == 0;
operatorCost= cost2;
conv= op;
}
}
}
}
}
if (conv!= null && !ambiguousConversionOperator) {
IType newSource= conv.getType().getReturnType();
boolean isNewSourceLValue= newSource instanceof ICPPReferenceType;
if (isNewSourceLValue && isReferenceCompatible(cv1T1, newSource)) {
cost= new Cost(cv1T1, newSource);
qualificationConversion(cost);
derivedToBaseConversion(cost);
}
}
}
}
// Direct binding failed
if (cost.rank == Cost.NO_MATCH_RANK) {
// 8.5.3-5 - Otherwise
boolean cv1isConst= false;
if (cv1T1 instanceof IQualifierType) {
cv1isConst= ((IQualifierType) cv1T1).isConst() && !((IQualifierType) cv1T1).isVolatile();
} else if (cv1T1 instanceof IPointerType) {
cv1isConst= ((IPointerType) cv1T1).isConst() && !((IPointerType) cv1T1).isVolatile();
}
if (cv1isConst) {
if (!lvalue && source instanceof ICPPClassType) {
cost= new Cost(source, target);
cost.rank= Cost.IDENTITY_RANK;
} else {
// 5 - Otherwise
// Otherwise, a temporary of type "cv1 T1" is created and initialized from
// the initializer expression using the rules for a non-reference copy
// initialization (8.5). The reference is then bound to the temporary.
// If T1 is reference-related to T2, cv1 must be the same cv-qualification as,
// or greater cv-qualification than, cv2; otherwise, the program is ill-formed.
// [Example
boolean illformed= false;
if (isReferenceRelated(cv1T1, source)) {
Integer cmp= compareQualifications(cv1T1, source);
if (cmp == null || cmp < 0) {
illformed= true;
}
}
// We must do a non-reference initialization
if (!illformed) {
cost= checkStandardConversionSequence(source, cv1T1, isImpliedObject);
// 12.3-4 At most one user-defined conversion is implicitly applied to
// a single value. (also prevents infinite loop)
if (allowUDC && (cost.rank == Cost.NO_MATCH_RANK ||
cost.rank == Cost.FUZZY_TEMPLATE_PARAMETERS)) {
Cost temp = checkUserDefinedConversionSequence(source, cv1T1);
if (temp != null) {
cost = temp;
}
}
}
}
}
}
} else {
// Non-reference binding
cost= checkStandardConversionSequence(source, target, isImpliedObject);
if (allowUDC && (cost.rank == Cost.NO_MATCH_RANK ||
cost.rank == Cost.FUZZY_TEMPLATE_PARAMETERS)) {
Cost temp = checkUserDefinedConversionSequence(source, target);
if (temp != null) {
cost = temp;
if (conv!= null && !ambiguousConversionOperator) {
IType newSource= conv.getType().getReturnType();
if (newSource instanceof ICPPReferenceType) { // require an lvalue
IType cvT2= getNestedType(newSource, TYPEDEFS | REFERENCES);
Cost cost= isReferenceCompatible(cv1T1, cvT2);
if (cost != null) {
if (isImpliedObject) {
cost.conversion= 0;
}
cost.rank= Cost.USERDEFINED_CONVERSION_RANK;
cost.userDefined= Cost.USERDEFINED_CONVERSION;
return cost;
}
}
}
}
// [8.5.3-5] Direct binding failed - Otherwise
boolean cv1isConst= false;
if (cv1T1 instanceof IQualifierType) {
cv1isConst= ((IQualifierType) cv1T1).isConst() && !((IQualifierType) cv1T1).isVolatile();
} else if (cv1T1 instanceof IPointerType) {
cv1isConst= ((IPointerType) cv1T1).isConst() && !((IPointerType) cv1T1).isVolatile();
}
if (cv1isConst) {
if (!lvalue && source instanceof ICPPClassType) {
Cost cost= new Cost(source, target);
cost.rank= Cost.IDENTITY_RANK;
return cost;
} else {
// 5 - Otherwise
// Otherwise, a temporary of type "cv1 T1" is created and initialized from
// the initializer expression using the rules for a non-reference copy
// initialization (8.5). The reference is then bound to the temporary.
// If T1 is reference-related to T2, cv1 must be the same cv-qualification as,
// or greater cv-qualification than, cv2; otherwise, the program is ill-formed.
boolean illformed= isReferenceRelated(cv1T1, source) >= 0 && compareQualifications(cv1T1, source) < 0;
// We must do a non-reference initialization
if (!illformed) {
Cost cost= checkStandardConversionSequence(source, cv1T1, isImpliedObject);
// 12.3-4 At most one user-defined conversion is implicitly applied to
// a single value. (also prevents infinite loop)
if (allowUDC && (cost.rank == Cost.NO_MATCH_RANK ||
cost.rank == Cost.FUZZY_TEMPLATE_PARAMETERS)) {
Cost temp = checkUserDefinedConversionSequence(source, cv1T1);
if (temp != null) {
cost = temp;
}
}
return cost;
}
}
}
return new Cost(source, cv1T1);
}
// Non-reference binding
Cost cost= checkStandardConversionSequence(source, target, isImpliedObject);
if (allowUDC && (cost.rank == Cost.NO_MATCH_RANK ||
cost.rank == Cost.FUZZY_TEMPLATE_PARAMETERS)) {
Cost temp = checkUserDefinedConversionSequence(source, target);
if (temp != null) {
cost = temp;
}
}
return cost;
}
@ -215,12 +213,11 @@ public class Conversions {
* @return <ul>
* <li>GT 1 if cv1 is more qualified than cv2
* <li>EQ 0 if cv1 and cv2 are equally qualified
* <li>LT -1 if cv1 is less qualified than cv2
* <li>NC null if cv1 and cv2 are not comparable
* <li>LT -1 if cv1 is less qualified than cv2 or not comparable
* </ul>
* @throws DOMException
*/
private static final Integer compareQualifications(IType cv1, IType cv2) throws DOMException {
private static final int compareQualifications(IType cv1, IType cv2) throws DOMException {
boolean cv1Const= false, cv2Const= false, cv1Volatile= false, cv2Volatile= false;
if (cv1 instanceof IQualifierType) {
IQualifierType qt1= (IQualifierType) cv1;
@ -251,56 +248,57 @@ public class Conversions {
return cmpVolatile;
}
return null;
return -1;
}
/**
* [8.5.3] "cv1 T1" is reference-related to "cv2 T2" if T1 is the same type as T2,
* or T1 is a base class of T2.
* Note this is not a symmetric relation.
* @param cv1t1
* @param cv2t2
* @return whether <code>cv1t1</code> is reference-related to <code>cv2t2</code>
* @throws DOMException
* @return inheritance distance, or -1, if <code>cv1t1</code> is not reference-related to <code>cv2t2</code>
*/
private static final boolean isReferenceRelated(IType cv1t1, IType cv2t2) throws DOMException {
// I've not found anything in the spec to justify unrolling cv1t1 or cv1t2 so far
IType t1= SemanticUtil.getUltimateTypeUptoPointers(cv1t1);
IType t2= SemanticUtil.getUltimateTypeUptoPointers(cv2t2);
private static final int isReferenceRelated(IType cv1Target, IType cv2Source) throws DOMException {
IType t= SemanticUtil.getNestedType(cv1Target, TYPEDEFS | REFERENCES);
IType s= SemanticUtil.getNestedType(cv2Source, TYPEDEFS | REFERENCES);
// The way cv-qualification is currently modeled means
// we must cope with IPointerType objects separately.
if (t1 instanceof IPointerType && t2 instanceof IPointerType) {
IType ptt1= ((IPointerType) t1).getType();
IType ptt2= ((IPointerType) t2).getType();
return ptt1 != null && ptt2 != null ? ptt1.isSameType(ptt2) : ptt1 == ptt2;
if (t instanceof IPointerType && s instanceof IPointerType) {
t= ((IPointerType) t).getType();
s= ((IPointerType) s).getType();
} else {
t= t instanceof IQualifierType ? ((IQualifierType) t).getType() : t;
s= s instanceof IQualifierType ? ((IQualifierType) s).getType() : s;
if (t instanceof ICPPClassType && s instanceof ICPPClassType) {
return calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, s, t);
}
}
t1= t1 instanceof IQualifierType ? ((IQualifierType) t1).getType() : t1;
t2= t2 instanceof IQualifierType ? ((IQualifierType) t2).getType() : t2;
if (t1 instanceof ICPPClassType && t2 instanceof ICPPClassType) {
return calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, t2, t1) >= 0;
if (t == s || (t != null && s != null && t.isSameType(s))) {
return 0;
}
return t1 != null && t2 != null ? t1.isSameType(t2) : t1 == t2;
return -1;
}
/**
* [8.5.3] "cv1 T1" is reference-compatible with "cv2 T2" if T1 is reference-related
* to T2 and cv1 is the same cv-qualification as, or greater cv-qualification than, cv2.
* Note this is not a symmetric relation.
* @param cv1t1
* @param cv2t2
* @return whether <code>cv1t1</code> is reference-compatible with <code>cv2t2</code>
* @throws DOMException
* @return The cost for converting or <code>null</code> if <code>cv1t1</code> is not
* reference-compatible with <code>cv2t2</code>
*/
private static final boolean isReferenceCompatible(IType cv1t1, IType cv2t2) throws DOMException {
if (isReferenceRelated(cv1t1, cv2t2)) {
Integer cmp= compareQualifications(cv1t1, cv2t2);
return cmp != null && cmp >= 0;
}
return false;
private static final Cost isReferenceCompatible(IType cv1Target, IType cv2Source) throws DOMException {
final int inheritanceDist= isReferenceRelated(cv1Target, cv2Source);
if (inheritanceDist < 0)
return null;
final int cmp= compareQualifications(cv1Target, cv2Source);
if (cmp < 0)
return null;
Cost cost= new Cost(cv2Source, cv1Target);
cost.qualification= cmp > 0 ? Cost.CONVERSION_RANK : Cost.IDENTITY_RANK;
cost.conversion= inheritanceDist;
return cost;
}
/**
@ -478,7 +476,7 @@ public class Conversions {
return 1;
}
tbase= getUltimateTypeViaTypedefs(tbase);
tbase= getNestedType(tbase, TYPEDEFS);
if (tbase instanceof ICPPClassType) {
int n= calculateInheritanceDepth(maxdepth - 1, tbase, ancestorToFind);
if (n > 0)

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation and others.
* Copyright (c) 2004, 2009 IBM Corporation and others.
* 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
@ -51,6 +51,9 @@ public class SemanticUtil {
// Cache of overloadable operator names for fast lookup. Used by isConversionOperator.
private static final CharArraySet cas= new CharArraySet(OverloadableOperator.values().length);
static final int TYPEDEFS = 0x1;
static final int REFERENCES = 0x2;
static {
final int OPERATOR_SPC= OPERATOR_CHARS.length + 1;
for (OverloadableOperator op : OverloadableOperator.values()) {
@ -233,17 +236,31 @@ public class SemanticUtil {
* Descends into a typedef sequence.
*/
public static IType getUltimateTypeViaTypedefs(IType type) {
return getNestedType(type, TYPEDEFS);
}
/**
* Descends into typedefs, references, etc. as specified by options.
*/
public static IType getNestedType(IType type, int options) {
boolean typedefs= (options & TYPEDEFS) != 0;
boolean refs= (options & REFERENCES) != 0;
try {
while (type instanceof ITypedef) {
IType t= ((ITypedef) type).getType();
if (t == null)
while (true) {
IType t= null;
if (typedefs && type instanceof ITypedef) {
t= ((ITypedef) type).getType();
} else if (refs && type instanceof ICPPReferenceType) {
t= ((ICPPReferenceType) type).getType();
}
if (t == null)
return type;
type= t;
}
} catch (DOMException e) {
type= e.getProblem();
return e.getProblem();
}
return type;
}
/**