1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-09 18:56:02 +02:00

Bug 156668: Implicit ctors for automatic variables.

This commit is contained in:
Markus Schorn 2010-09-17 09:59:48 +00:00
parent ca68f6bb04
commit 200c531f33
7 changed files with 146 additions and 57 deletions

View file

@ -9118,4 +9118,40 @@ public class AST2CPPTests extends AST2BaseTest {
assertSame(fc, ref); assertSame(fc, ref);
bh.assertNonProblem("g(0 ? p : \"\")", 1); // bh.assertNonProblem("g(0 ? p : \"\")", 1); //
} }
// struct C {
// C();
// C(int a, int b);
// };
//
// C c1; // C()
// C c2(1,2); // C(int, int)
// C c3 ({1,2}); // C(C(int, int)) // copy ctor is elided
// C c4 ={1,2}; // C(C(int, int)) // copy ctor is elided
// C c5 {1,2}; // C(int, int)
public void testCtorForAutomaticVariables_156668() throws Exception {
String code= getAboveComment();
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
IFunction ctor1= bh.assertNonProblem("C();", 1);
IFunction ctor2= bh.assertNonProblem("C(int a, int b);", 1);
IASTName name;
IASTImplicitNameOwner dtor;
name= bh.findName("c1", 2);
dtor= (IASTImplicitNameOwner) name.getParent();
assertSame(ctor1, dtor.getImplicitNames()[0].resolveBinding());
name= bh.findName("c2", 2);
dtor= (IASTImplicitNameOwner) name.getParent();
assertSame(ctor2, dtor.getImplicitNames()[0].resolveBinding());
name= bh.findName("c3", 2);
dtor= (IASTImplicitNameOwner) name.getParent();
assertSame(ctor2, dtor.getImplicitNames()[0].resolveBinding());
name= bh.findName("c4", 2);
dtor= (IASTImplicitNameOwner) name.getParent();
assertSame(ctor2, dtor.getImplicitNames()[0].resolveBinding());
name= bh.findName("c5", 2);
dtor= (IASTImplicitNameOwner) name.getParent();
assertSame(ctor2, dtor.getImplicitNames()[0].resolveBinding());
}
} }

View file

@ -196,6 +196,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalNamespaceScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalNamespaceScope;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context;
@ -2399,7 +2400,14 @@ public class CPPSemantics {
((FunctionSetType) iType).applySelectedFunction(bestFnCost.getCost(i).getSelectedFunction()); ((FunctionSetType) iType).applySelectedFunction(bestFnCost.getCost(i).getSelectedFunction());
} }
} }
return bestFnCost.getFunction(); IFunction result= bestFnCost.getFunction();
if (bestFnCost.isDirectInitWithCopyCtor()) {
Cost c0= bestFnCost.getCost(0);
IFunction firstConversion= c0.getUserDefinedConversion();
if (firstConversion instanceof ICPPConstructor)
return firstConversion;
}
return result;
} }
private static void setTargetedFunctionsToUnknown(IType[] argTypes) { private static void setTargetedFunctionsToUnknown(IType[] argTypes) {
@ -2450,8 +2458,8 @@ public class CPPSemantics {
if (iast != i) { if (iast != i) {
fns[i]= fns[iast]; fns[i]= fns[iast];
fns[iast]= fn; fns[iast]= fn;
iast++;
} }
iast++;
} }
} }
} }
@ -2545,9 +2553,10 @@ public class CPPSemantics {
Context ctx= Context.ORDINARY; Context ctx= Context.ORDINARY;
if (j==0 && sourceLen == 1 && fn instanceof ICPPConstructor) { if (j==0 && sourceLen == 1 && fn instanceof ICPPConstructor) {
if (paramType instanceof ICPPReferenceType && !((ICPPReferenceType) paramType).isRValueReference()) { if (paramType instanceof ICPPReferenceType) {
if (((ICPPConstructor) fn).getClassOwner().isSameType(getNestedType(paramType, TDEF|REF|CVTYPE))) { if (((ICPPConstructor) fn).getClassOwner().isSameType(getNestedType(paramType, TDEF|REF|CVTYPE))) {
ctx= Context.FIRST_PARAM_OF_DIRECT_COPY_CTOR; ctx= Context.FIRST_PARAM_OF_DIRECT_COPY_CTOR;
result.setIsDirectInitWithCopyCtor(true);
} }
} }
} }
@ -2940,7 +2949,8 @@ public class CPPSemantics {
IASTDeclarator dtor= ASTQueries.findOutermostDeclarator(declarator); IASTDeclarator dtor= ASTQueries.findOutermostDeclarator(declarator);
IASTNode parent = dtor.getParent(); IASTNode parent = dtor.getParent();
if (parent instanceof IASTSimpleDeclaration) { if (parent instanceof IASTSimpleDeclaration) {
if (dtor.getInitializer() == null) { final IASTInitializer initializer = dtor.getInitializer();
if (initializer == null) {
IASTDeclSpecifier declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier(); IASTDeclSpecifier declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier();
parent = parent.getParent(); parent = parent.getParent();
if (parent instanceof IASTCompositeTypeSpecifier || if (parent instanceof IASTCompositeTypeSpecifier ||
@ -2950,7 +2960,7 @@ public class CPPSemantics {
return null; return null;
} }
} }
return findImplicitlyCalledConstructor(declarator.getName(), dtor.getInitializer()); return findImplicitlyCalledConstructor(declarator.getName(), initializer);
} }
return null; return null;
} }
@ -2976,10 +2986,12 @@ public class CPPSemantics {
type = SemanticUtil.getNestedType(((ICPPVariable) binding).getType(), TDEF | CVTYPE); type = SemanticUtil.getNestedType(((ICPPVariable) binding).getType(), TDEF | CVTYPE);
if (!(type instanceof ICPPClassType)) if (!(type instanceof ICPPClassType))
return null; return null;
final ICPPClassType classType = (ICPPClassType) type; if (type instanceof ICPPClassTemplate || type instanceof ICPPUnknownClassType || type instanceof IProblemBinding)
return null;
// Copy initialization final ICPPClassType classType = (ICPPClassType) type;
if (initializer instanceof IASTEqualsInitializer) { if (initializer instanceof IASTEqualsInitializer) {
// Copy initialization
IASTEqualsInitializer eqInit= (IASTEqualsInitializer) initializer; IASTEqualsInitializer eqInit= (IASTEqualsInitializer) initializer;
IASTInitializerClause initClause = eqInit.getInitializerClause(); IASTInitializerClause initClause = eqInit.getInitializerClause();
IType sourceType= null; IType sourceType= null;
@ -2994,15 +3006,24 @@ public class CPPSemantics {
if (sourceType != null) { if (sourceType != null) {
Cost c= Conversions.checkImplicitConversionSequence(type, sourceType, isLValue, UDCMode.ALLOWED, Context.ORDINARY); Cost c= Conversions.checkImplicitConversionSequence(type, sourceType, isLValue, UDCMode.ALLOWED, Context.ORDINARY);
if (c.converts()) { if (c.converts()) {
IFunction f= c.getUserDefinedConversion(); ICPPFunction f = c.getUserDefinedConversion();
if (f instanceof ICPPConstructor)
return (ICPPConstructor) f;
// If a conversion is used, the constructor is elided.
}
}
} else if (initializer instanceof ICPPASTInitializerList) {
// List initialization
final InitializerListType listType = new InitializerListType((ICPPASTInitializerList) initializer);
Cost c= Conversions.listInitializationSequence(listType, type, UDCMode.ALLOWED, true);
if (c.converts()) {
ICPPFunction f = c.getUserDefinedConversion();
if (f instanceof ICPPConstructor) if (f instanceof ICPPConstructor)
return (ICPPConstructor) f; return (ICPPConstructor) f;
} }
return null; } else if (initializer instanceof ICPPASTConstructorInitializer) {
}
}
// Direct Initialization // Direct Initialization
final IASTInitializerClause[] arguments = ((ICPPASTConstructorInitializer) initializer).getArguments();
CPPASTName astName = new CPPASTName(); CPPASTName astName = new CPPASTName();
astName.setName(classType.getNameCharArray()); astName.setName(classType.getNameCharArray());
astName.setOffsetAndLength((ASTNode) name); astName.setOffsetAndLength((ASTNode) name);
@ -3011,18 +3032,21 @@ public class CPPSemantics {
idExp.setPropertyInParent(IASTFunctionCallExpression.FUNCTION_NAME); idExp.setPropertyInParent(IASTFunctionCallExpression.FUNCTION_NAME);
LookupData data = new LookupData(astName); LookupData data = new LookupData(astName);
if (initializer == null) { data.setFunctionArguments(false, arguments);
data.setFunctionArguments(false);
} else if (initializer instanceof ICPPASTConstructorInitializer) {
data.setFunctionArguments(false, ((ICPPASTConstructorInitializer) initializer).getArguments());
} else {
return null;
}
data.forceQualified = true; data.forceQualified = true;
data.foundItems = classType.getConstructors(); data.foundItems = classType.getConstructors();
binding = resolveAmbiguities(data, astName); binding = resolveAmbiguities(data, astName);
if (binding instanceof ICPPConstructor) if (binding instanceof ICPPConstructor)
return (ICPPConstructor) binding; return (ICPPConstructor) binding;
} else if (initializer == null) {
// Default initialization
ICPPConstructor[] ctors = classType.getConstructors();
for (ICPPConstructor ctor : ctors) {
if (ctor.getRequiredArgumentCount() == 0)
return ctor;
}
return null;
}
} catch (DOMException e) { } catch (DOMException e) {
} }
return null; return null;

View file

@ -85,32 +85,42 @@ public class Conversions {
public static Cost checkImplicitConversionSequence(IType target, IType exprType, public static Cost checkImplicitConversionSequence(IType target, IType exprType,
ValueCategory valueCat, UDCMode udc, Context ctx) throws DOMException { ValueCategory valueCat, UDCMode udc, Context ctx) throws DOMException {
final boolean isImpliedObject= ctx == Context.IMPLICIT_OBJECT; final boolean isImpliedObject= ctx == Context.IMPLICIT_OBJECT;
if (isImpliedObject) { if (isImpliedObject)
udc= UDCMode.FORBIDDEN; udc= UDCMode.FORBIDDEN;
}
target= getNestedType(target, TDEF); target= getNestedType(target, TDEF);
exprType= getNestedType(exprType, TDEF | REF); exprType= getNestedType(exprType, TDEF | REF);
final IType cv1T1= getNestedType(target, TDEF | REF);
final IType T1= getNestedType(cv1T1, TDEF | REF | ALLCVQ);
ReferenceBinding refBindingType= ReferenceBinding.OTHER;
if (target instanceof ICPPReferenceType) { if (target instanceof ICPPReferenceType) {
// [8.5.3-5] initialization of a reference // [8.5.3-5] initialization of a reference
final boolean isLValueRef= !((ICPPReferenceType) target).isRValueReference(); final boolean isLValueRef= !((ICPPReferenceType) target).isRValueReference();
final IType cv1T1= getNestedType(target, TDEF | REF);
final IType T1= getNestedType(cv1T1, TDEF | REF | ALLCVQ);
final IType cv2T2= exprType; final IType cv2T2= exprType;
final IType T2= getNestedType(cv2T2, TDEF | REF | ALLCVQ); final IType T2= getNestedType(cv2T2, TDEF | REF | ALLCVQ);
// mstodo: will change when implementing rvalue references on this pointer // mstodo: will change when implementing rvalue references on this pointer
final boolean isImplicitWithoutRefQualifier = isImpliedObject; final boolean isImplicitWithoutRefQualifier = isImpliedObject;
ReferenceBinding refBindingType= ReferenceBinding.OTHER;
if (!isImplicitWithoutRefQualifier) { if (!isImplicitWithoutRefQualifier) {
if (isLValueRef) { if (isLValueRef) {
refBindingType= ReferenceBinding.LVALUE_REF; refBindingType= ReferenceBinding.LVALUE_REF;
} else if (valueCat == LVALUE) { } else {
refBindingType= ReferenceBinding.RVALUE_REF_BINDS_RVALUE; refBindingType= ReferenceBinding.RVALUE_REF_BINDS_RVALUE;
} }
} }
if (exprType instanceof InitializerListType) {
if (isLValueRef && getCVQualifier(cv1T1) != CVQualifier.c)
return Cost.NO_CONVERSION;
Cost cost= listInitializationSequence(((InitializerListType) exprType), T1, udc, false);
if (cost.converts()) {
cost.setReferenceBinding(refBindingType);
}
return cost;
}
// If the reference is an lvalue reference and ... // If the reference is an lvalue reference and ...
if (isLValueRef) { if (isLValueRef) {
// ... the initializer expression is an lvalue (but is not a bit field) // ... the initializer expression is an lvalue (but is not a bit field)
@ -237,24 +247,12 @@ public class Conversions {
} }
// Non-reference binding // Non-reference binding
IType uqsource= getNestedType(exprType, TDEF | REF | ALLCVQ); Cost cost= nonReferenceConversion(valueCat, exprType, T1, udc, isImpliedObject);
IType uqtarget= getNestedType(target, TDEF | REF | ALLCVQ); if (cost.converts()) {
cost.setReferenceBinding(refBindingType);
// [13.3.3.1-6] Derived to base conversion
if (uqsource instanceof ICPPClassType && uqtarget instanceof ICPPClassType) {
int depth= SemanticUtil.calculateInheritanceDepth(uqsource, uqtarget);
if (depth > -1) {
if (depth == 0) {
return new Cost(uqsource, uqtarget, Rank.IDENTITY);
} }
Cost cost= new Cost(uqsource, uqtarget, Rank.CONVERSION);
cost.setInheritanceDistance(depth);
return cost; return cost;
} }
}
return nonReferenceConversion(valueCat, exprType, uqtarget, udc, isImpliedObject);
}
/** /**
* C++0x: 13.3.1.6 Initialization by conversion function for direct reference binding * C++0x: 13.3.1.6 Initialization by conversion function for direct reference binding
@ -314,7 +312,7 @@ public class Conversions {
if (uqTarget instanceof ICPPClassType) { if (uqTarget instanceof ICPPClassType) {
if (uqSource instanceof ICPPClassType) { if (uqSource instanceof ICPPClassType) {
// 13.3.3.1-6 Conceptual derived to base conversion // 13.3.3.1-6 Conceptual derived to base conversion
int depth= calculateInheritanceDepth(uqTarget, uqSource); int depth= calculateInheritanceDepth(uqSource, uqTarget);
if (depth >= 0) { if (depth >= 0) {
if (depth == 0) { if (depth == 0) {
return new Cost(source, target, Rank.IDENTITY); return new Cost(source, target, Rank.IDENTITY);

View file

@ -74,6 +74,10 @@ public class Cost {
public void setCouldNarrow() { public void setCouldNarrow() {
assert false; assert false;
} }
@Override
public void setSelectedFunction(ICPPFunction function) {
assert false;
}
}; };
IType source; IType source;
@ -110,6 +114,11 @@ public class Cost {
fRank= rank; fRank= rank;
} }
public ReferenceBinding getReferenceBinding() {
return fReferenceBinding;
}
public void setReferenceBinding(ReferenceBinding binding) { public void setReferenceBinding(ReferenceBinding binding) {
fReferenceBinding= binding; fReferenceBinding= binding;
} }

View file

@ -30,6 +30,7 @@ class FunctionCost {
private final IFunction fFunction; private final IFunction fFunction;
private final Cost[] fCosts; private final Cost[] fCosts;
private final ValueCategory[] fValueCategories; private final ValueCategory[] fValueCategories;
private boolean fIsDirectCopyCtor;
public FunctionCost(IFunction fn, int paramCount) { public FunctionCost(IFunction fn, int paramCount) {
fFunction= fn; fFunction= fn;
@ -109,6 +110,7 @@ class FunctionCost {
if (!udcCost.converts()) { if (!udcCost.converts()) {
return false; return false;
} }
udcCost.setReferenceBinding(cost.getReferenceBinding());
} }
return true; return true;
} }
@ -212,4 +214,12 @@ class FunctionCost {
} }
return null; return null;
} }
public void setIsDirectInitWithCopyCtor(boolean val) {
fIsDirectCopyCtor= val;
}
public boolean isDirectInitWithCopyCtor() {
return fIsDirectCopyCtor;
}
} }

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2006, 2009 Wind River Systems, Inc. and others. * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -293,7 +293,7 @@ public class BasicCppCallHierarchyTest extends CallHierarchyBaseTest {
// void automatic() { // void automatic() {
// MyClass m; // MyClass m;
// } // }
public void _testAutomaticConstructor_156668() throws Exception { public void testAutomaticConstructor_156668() throws Exception {
String content = readTaggedComment("testAutomaticConstructor"); String content = readTaggedComment("testAutomaticConstructor");
IFile file= createFile(getProject(), "testConstructor.cpp", content); IFile file= createFile(getProject(), "testConstructor.cpp", content);
waitForIndexer(fIndex, file, CallHierarchyBaseTest.INDEXER_WAIT_TIME); waitForIndexer(fIndex, file, CallHierarchyBaseTest.INDEXER_WAIT_TIME);
@ -304,6 +304,15 @@ public class BasicCppCallHierarchyTest extends CallHierarchyBaseTest {
Tree tree = getCHTreeViewer().getTree(); Tree tree = getCHTreeViewer().getTree();
checkTreeNode(tree, 0, "MyClass::MyClass()"); checkTreeNode(tree, 0, "MyClass::MyClass()");
checkTreeNode(tree, 0, 0, "automatic()"); checkTreeNode(tree, 0, 0, "automatic()");
}
public void _testAutomaticDestructor_156668() throws Exception {
String content = readTaggedComment("testAutomaticConstructor");
IFile file= createFile(getProject(), "testConstructor.cpp", content);
waitForIndexer(fIndex, file, CallHierarchyBaseTest.INDEXER_WAIT_TIME);
CEditor editor = openEditor(file);
openCallHierarchy(editor);
Tree tree = getCHTreeViewer().getTree();
editor.selectAndReveal(content.indexOf("~MyClass"), 2); editor.selectAndReveal(content.indexOf("~MyClass"), 2);
openCallHierarchy(editor); openCallHierarchy(editor);

View file

@ -58,6 +58,7 @@ import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.PreferenceConstants; import org.eclipse.cdt.ui.PreferenceConstants;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
/** /**
@ -1991,6 +1992,8 @@ public class SemanticHighlightings {
&& ((ICPPMethod) binding).isImplicit()) { && ((ICPPMethod) binding).isImplicit()) {
return false; return false;
} }
if (binding instanceof ICPPUnknownBinding)
return false;
char[] chars = name.toCharArray(); char[] chars = name.toCharArray();
if (chars[0] == '~' || OverloadableOperator.isNew(chars) if (chars[0] == '~' || OverloadableOperator.isNew(chars)
|| OverloadableOperator.isDelete(chars)) { || OverloadableOperator.isDelete(chars)) {