diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java index e7eb048b6fa..db6cbddda0b 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java @@ -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 { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 2ed05aa2bdc..e14b0d51652 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -884,6 +884,7 @@ public class CPPSemantics { return null; } + HashSet baseBindings= bases.length > 1 ? new HashSet() : 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; } }; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java index 1fee9782da9..d8ccb7e25bc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java @@ -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 * @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 cv1t1 is reference-related to cv2t2 - * @throws DOMException + * @return inheritance distance, or -1, if cv1t1 is not reference-related to cv2t2 */ - 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 cv1t1 is reference-compatible with cv2t2 - * @throws DOMException + * @return The cost for converting or null if cv1t1 is not + * reference-compatible with cv2t2 */ - 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) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java index bfbac1ad8f0..c137b7a2c20 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java @@ -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; } /**