mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-07 17:56:01 +02:00
Bug 495952 - Problem with SFINAE in trailing return type
Change-Id: Ida1d168803da5304c834b19fa83148921f69b2b6
This commit is contained in:
parent
5344893756
commit
a6492d951f
8 changed files with 196 additions and 16 deletions
|
@ -7818,6 +7818,43 @@ public class AST2TemplateTests extends AST2TestBase {
|
||||||
parseAndCheckBindings();
|
parseAndCheckBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// template<typename T>
|
||||||
|
// T a();
|
||||||
|
//
|
||||||
|
// template <class T>
|
||||||
|
// struct A {};
|
||||||
|
//
|
||||||
|
// template <class T>
|
||||||
|
// A<T> b(T t);
|
||||||
|
//
|
||||||
|
// template <class T, class U>
|
||||||
|
// void c(U u);
|
||||||
|
//
|
||||||
|
// template <class T, class U, class W>
|
||||||
|
// decltype(c<T>(1)) d(W w, U u);
|
||||||
|
//
|
||||||
|
// template <class T, class U>
|
||||||
|
// auto d(U u, T t) -> decltype(d<typename A<T>::type>(u, t));
|
||||||
|
//
|
||||||
|
// template <class T, class U>
|
||||||
|
// auto e(U u, T t) -> decltype(d(b(u), t));
|
||||||
|
//
|
||||||
|
// template <typename T, typename U = decltype(e(1, a<T>()))>
|
||||||
|
// class B {};
|
||||||
|
//
|
||||||
|
// template <typename T>
|
||||||
|
// typename B<T>::type waldo(T p);
|
||||||
|
//
|
||||||
|
// template <typename T>
|
||||||
|
// int waldo(T p);
|
||||||
|
//
|
||||||
|
// void test() {
|
||||||
|
// waldo(1);
|
||||||
|
// }
|
||||||
|
public void testSfinaeInTrailingReturnType_495952() throws Exception {
|
||||||
|
parseAndCheckBindings();
|
||||||
|
}
|
||||||
|
|
||||||
// template <typename>
|
// template <typename>
|
||||||
// struct M {
|
// struct M {
|
||||||
// template <typename... Args>
|
// template <typename... Args>
|
||||||
|
|
|
@ -21,6 +21,8 @@ import org.eclipse.core.runtime.CoreException;
|
||||||
* Implementation of problem types.
|
* Implementation of problem types.
|
||||||
*/
|
*/
|
||||||
public class ProblemFunctionType extends ProblemType implements ICPPFunctionType {
|
public class ProblemFunctionType extends ProblemType implements ICPPFunctionType {
|
||||||
|
@SuppressWarnings("hiding")
|
||||||
|
public static final IType RECURSION_IN_LOOKUP = new ProblemFunctionType(BINDING_RECURSION_IN_LOOKUP);
|
||||||
|
|
||||||
public ProblemFunctionType(int id) {
|
public ProblemFunctionType(int id) {
|
||||||
super(id);
|
super(id);
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
package org.eclipse.cdt.internal.core.dom.parser;
|
package org.eclipse.cdt.internal.core.dom.parser;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IProblemType;
|
import org.eclipse.cdt.core.dom.ast.IProblemType;
|
||||||
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IType;
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
import org.eclipse.cdt.internal.core.parser.ParserMessages;
|
import org.eclipse.cdt.internal.core.parser.ParserMessages;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
@ -22,8 +21,9 @@ import org.eclipse.core.runtime.CoreException;
|
||||||
*/
|
*/
|
||||||
public class ProblemType implements IProblemType, ISerializableType {
|
public class ProblemType implements IProblemType, ISerializableType {
|
||||||
public static final IType UNRESOLVED_NAME = new ProblemType(TYPE_UNRESOLVED_NAME);
|
public static final IType UNRESOLVED_NAME = new ProblemType(TYPE_UNRESOLVED_NAME);
|
||||||
public static final IType UNKNOWN_FOR_EXPRESSION = new ProblemType(ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION);
|
public static final IType UNKNOWN_FOR_EXPRESSION = new ProblemType(TYPE_UNKNOWN_FOR_EXPRESSION);
|
||||||
public static final IType ENUMERATION_EXPECTED = new ProblemType(ISemanticProblem.TYPE_ENUMERATION_EXPECTED);
|
public static final IType ENUMERATION_EXPECTED = new ProblemType(TYPE_ENUMERATION_EXPECTED);
|
||||||
|
public static final IType RECURSION_IN_LOOKUP = new ProblemType(BINDING_RECURSION_IN_LOOKUP);
|
||||||
|
|
||||||
private final int fID;
|
private final int fID;
|
||||||
|
|
||||||
|
|
|
@ -58,9 +58,9 @@ public abstract class CPPEvaluation implements ICPPEvaluation {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static ICPPTemplateArgument[] instantiateArguments(ICPPTemplateArgument[] args,
|
protected static ICPPTemplateArgument[] instantiateArguments(ICPPTemplateArgument[] args,
|
||||||
InstantiationContext context) {
|
InstantiationContext context, boolean strict) {
|
||||||
try {
|
try {
|
||||||
return CPPTemplates.instantiateArguments(args, context, false);
|
return CPPTemplates.instantiateArguments(args, context, strict);
|
||||||
} catch (DOMException e) {
|
} catch (DOMException e) {
|
||||||
CCorePlugin.log(e);
|
CCorePlugin.log(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,9 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType;
|
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
|
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
|
||||||
|
@ -121,6 +123,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope;
|
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
|
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
|
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.parser.ProblemFunctionType;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
|
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.Value;
|
import org.eclipse.cdt.internal.core.dom.parser.Value;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
|
||||||
|
@ -219,6 +222,13 @@ public class CPPTemplates {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
private static final ThreadLocal<Set<TypeInstantiationRequest>> instantiationsInProgress =
|
||||||
|
new ThreadLocal<Set<TypeInstantiationRequest>>() {
|
||||||
|
@Override
|
||||||
|
protected Set<TypeInstantiationRequest> initialValue() {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a class template with the given arguments. May return {@code null}.
|
* Instantiates a class template with the given arguments. May return {@code null}.
|
||||||
|
@ -1426,19 +1436,24 @@ public class CPPTemplates {
|
||||||
* Instantiates the given type with the provided map and packОffset.
|
* Instantiates the given type with the provided map and packОffset.
|
||||||
* The context is used to replace templates with their specialization, where appropriate.
|
* The context is used to replace templates with their specialization, where appropriate.
|
||||||
*/
|
*/
|
||||||
public static IType instantiateType(IType type, InstantiationContext context) {
|
public static IType instantiateType(final IType type, InstantiationContext context) {
|
||||||
try {
|
|
||||||
if (context.getParameterMap() == null)
|
if (context.getParameterMap() == null)
|
||||||
return type;
|
return type;
|
||||||
|
|
||||||
|
TypeInstantiationRequest instantiationRequest = new TypeInstantiationRequest(type, context);
|
||||||
|
if (!instantiationsInProgress.get().add(instantiationRequest)) {
|
||||||
|
System.out.println("Recursion in instantiation of type \"" + type + "\""); //$NON-NLS-1$//$NON-NLS-2$ //XXX
|
||||||
|
return type instanceof ICPPFunctionType ?
|
||||||
|
ProblemFunctionType.RECURSION_IN_LOOKUP : ProblemType.RECURSION_IN_LOOKUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
if (type instanceof ICPPFunctionType) {
|
if (type instanceof ICPPFunctionType) {
|
||||||
final ICPPFunctionType ft = (ICPPFunctionType) type;
|
final ICPPFunctionType ft = (ICPPFunctionType) type;
|
||||||
IType ret = null;
|
|
||||||
IType[] params = null;
|
|
||||||
final IType r = ft.getReturnType();
|
|
||||||
ret = instantiateType(r, context);
|
|
||||||
IType[] ps = ft.getParameterTypes();
|
IType[] ps = ft.getParameterTypes();
|
||||||
params = instantiateTypes(ps, context);
|
IType[] params = instantiateTypes(ps, context);
|
||||||
|
final IType r = ft.getReturnType();
|
||||||
|
IType ret = instantiateType(r, context);
|
||||||
if (ret == r && params == ps) {
|
if (ret == r && params == ps) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
@ -1574,6 +1589,8 @@ public class CPPTemplates {
|
||||||
return type;
|
return type;
|
||||||
} catch (DOMException e) {
|
} catch (DOMException e) {
|
||||||
return e.getProblem();
|
return e.getProblem();
|
||||||
|
} finally {
|
||||||
|
instantiationsInProgress.get().remove(instantiationRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -240,7 +240,7 @@ public class EvalFunctionSet extends CPPDependentEvaluation {
|
||||||
ICPPTemplateArgument[] originalArguments = fFunctionSet.getTemplateArguments();
|
ICPPTemplateArgument[] originalArguments = fFunctionSet.getTemplateArguments();
|
||||||
ICPPTemplateArgument[] arguments = originalArguments;
|
ICPPTemplateArgument[] arguments = originalArguments;
|
||||||
if (originalArguments != null)
|
if (originalArguments != null)
|
||||||
arguments = instantiateArguments(originalArguments, context);
|
arguments = instantiateArguments(originalArguments, context, true);
|
||||||
|
|
||||||
IBinding originalOwner = fFunctionSet.getOwner();
|
IBinding originalOwner = fFunctionSet.getOwner();
|
||||||
IBinding owner = originalOwner;
|
IBinding owner = originalOwner;
|
||||||
|
|
|
@ -343,7 +343,7 @@ public class EvalID extends CPPDependentEvaluation {
|
||||||
public ICPPEvaluation instantiate(InstantiationContext context, int maxDepth) {
|
public ICPPEvaluation instantiate(InstantiationContext context, int maxDepth) {
|
||||||
ICPPTemplateArgument[] templateArgs = fTemplateArgs;
|
ICPPTemplateArgument[] templateArgs = fTemplateArgs;
|
||||||
if (templateArgs != null) {
|
if (templateArgs != null) {
|
||||||
templateArgs = instantiateArguments(templateArgs, context);
|
templateArgs = instantiateArguments(templateArgs, context, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ICPPEvaluation fieldOwner = fFieldOwner;
|
ICPPEvaluation fieldOwner = fFieldOwner;
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2016 Google, Inc 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
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTypeSpecialization;
|
||||||
|
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to track ongoing instantiations as a safeguard against infinite recursion.
|
||||||
|
*/
|
||||||
|
public class TypeInstantiationRequest {
|
||||||
|
private final IType type;
|
||||||
|
private final ICPPTemplateParameterMap parameterMap;
|
||||||
|
private final int packOffset;
|
||||||
|
private final ICPPTypeSpecialization contextTypeSpecialization;
|
||||||
|
private final IASTNode point;
|
||||||
|
private int hashCode;
|
||||||
|
|
||||||
|
public TypeInstantiationRequest(IType type, InstantiationContext context) {
|
||||||
|
this.type = type;
|
||||||
|
this.parameterMap = context.getParameterMap();
|
||||||
|
this.packOffset = context.getPackOffset();
|
||||||
|
this.contextTypeSpecialization = context.getContextTypeSpecialization();
|
||||||
|
this.point = context.getPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
if (hashCode == 0) {
|
||||||
|
SignatureBuilder builder = new SignatureBuilder();
|
||||||
|
try {
|
||||||
|
builder.marshalType(type);
|
||||||
|
char[] signature = builder.getSignature();
|
||||||
|
hashCode = CharArrayUtils.hash(signature);
|
||||||
|
} catch (CoreException e) {
|
||||||
|
CCorePlugin.log(e);
|
||||||
|
hashCode = Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (!obj.getClass().equals(getClass()))
|
||||||
|
return false;
|
||||||
|
TypeInstantiationRequest other = (TypeInstantiationRequest) obj;
|
||||||
|
if (!type.isSameType(other.type))
|
||||||
|
return false;
|
||||||
|
if (!equals(contextTypeSpecialization, other.contextTypeSpecialization))
|
||||||
|
return false;
|
||||||
|
if (!equals(parameterMap, other.parameterMap))
|
||||||
|
return false;
|
||||||
|
if (packOffset != other.packOffset)
|
||||||
|
return false;
|
||||||
|
if (point != other.point)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean equals(IType type1, IType type2) {
|
||||||
|
if (type1 == type2)
|
||||||
|
return true;
|
||||||
|
if (type1 == null || type2 == null)
|
||||||
|
return false;
|
||||||
|
return type1.isSameType(type1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean equals(ICPPTemplateParameterMap map1, ICPPTemplateParameterMap map2) {
|
||||||
|
if (map1 == map2)
|
||||||
|
return true;
|
||||||
|
if (map1 == null || map2 == null)
|
||||||
|
return false;
|
||||||
|
Integer[] p1 = map1.getAllParameterPositions();
|
||||||
|
Integer[] p2 = map2.getAllParameterPositions();
|
||||||
|
if (!Arrays.equals(p1, p2))
|
||||||
|
return false;
|
||||||
|
for (Integer paramId : p1) {
|
||||||
|
ICPPTemplateArgument[] packExpansion1 = map1.getPackExpansion(paramId);
|
||||||
|
ICPPTemplateArgument[] packExpansion2 = map2.getPackExpansion(paramId);
|
||||||
|
if (packExpansion1 != null && packExpansion2 != null) {
|
||||||
|
if (packExpansion1.length != packExpansion2.length)
|
||||||
|
return false;
|
||||||
|
for (int i = 0; i < packExpansion1.length; i++) {
|
||||||
|
if (!equals(packExpansion1[i], packExpansion2[i]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (packExpansion1 == null && packExpansion2 == null) {
|
||||||
|
ICPPTemplateArgument arg1 = map1.getArgument(paramId);
|
||||||
|
ICPPTemplateArgument arg2 = map2.getArgument(paramId);
|
||||||
|
if (!equals(arg1, arg2))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean equals(ICPPTemplateArgument arg1, ICPPTemplateArgument arg2) {
|
||||||
|
if (arg1 == arg2)
|
||||||
|
return true;
|
||||||
|
if (arg1 == null || arg2 == null)
|
||||||
|
return false;
|
||||||
|
return arg1.isSameValue(arg2);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue