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

Bug 536986 - Add support for string literal operator templates

This was proposed for standardization in N3599. The proposal was not
accepted, but it's supported by gcc and clang as an extension.

Change-Id: I0c4a6e532f3a9172a8cb26218f0a608a1ca6be7d
This commit is contained in:
Nathan Ridge 2019-11-03 00:54:28 -04:00 committed by Marc-André Laperle
parent c29769823c
commit fac1ba39e6
2 changed files with 52 additions and 5 deletions

View file

@ -11373,4 +11373,16 @@ public class AST2TemplateTests extends AST2CPPTestBase {
public void testGlobalConstWorksAsConstExpression_545756() throws Exception { public void testGlobalConstWorksAsConstExpression_545756() throws Exception {
parseAndCheckBindings(); parseAndCheckBindings();
} }
// template <class C, C... Chars>
// unsigned int operator""_test() {
// return sizeof...(Chars);
// }
//
// void foo() {
// auto len = "test"_test;
// }
public void testStringLiteralOperatorTemplate_536986() throws Exception {
parseAndCheckImplicitNameBindings();
}
} }

View file

@ -231,6 +231,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScope;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeArgument; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTypeArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownField; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownField;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMemberClass; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMemberClass;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMethod; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMethod;
@ -3453,11 +3454,10 @@ public class CPPSemantics {
data.setFunctionArguments(false, createArgForType(exp, charArray)); data.setFunctionArguments(false, createArgForType(exp, charArray));
ret = resolveFunction(data, funcs, true, false); ret = resolveFunction(data, funcs, true, false);
//
char[] stringLiteral = exp.getValue(); // The string literal that was passed to the operator char[] stringLiteral = exp.getValue(); // The string literal that was passed to the operator
// The string literal is passed to the operator as chars: // The string literal is passed to the operator as chars:
// "literal"_op -> operator "" _op<'l', 'i', 't', 'e', 'r', 'a', 'l'>(); // 12345_op -> operator "" _op<'1', '2', '3', '4', '5'>();
ICPPTemplateArgument args[] = new ICPPTemplateArgument[stringLiteral.length]; ICPPTemplateArgument args[] = new ICPPTemplateArgument[stringLiteral.length];
for (int k = 0; k < stringLiteral.length; k++) { for (int k = 0; k < stringLiteral.length; k++) {
args[k] = new CPPTemplateNonTypeArgument( args[k] = new CPPTemplateNonTypeArgument(
@ -3492,13 +3492,48 @@ public class CPPSemantics {
* str (i.e., its length excluding the terminating null character). * str (i.e., its length excluding the terminating null character).
* L is treated as operator "" X(str, len) * L is treated as operator "" X(str, len)
*/ */
CPPPointerType strType = new CPPPointerType( IType charType = new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, null);
new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, null), true, false, CPPPointerType strType = new CPPPointerType(charType, true, false, false);
false);
IASTInitializerClause[] initializer = new IASTInitializerClause[] { createArgForType(exp, strType), IASTInitializerClause[] initializer = new IASTInitializerClause[] { createArgForType(exp, strType),
createArgForType(null, CPPBasicType.UNSIGNED_INT) }; createArgForType(null, CPPBasicType.UNSIGNED_INT) };
data.setFunctionArguments(false, initializer); data.setFunctionArguments(false, initializer);
ret = resolveFunction(data, funcs, true, false); ret = resolveFunction(data, funcs, true, false);
// GNU extension: allow literal operator templates for string literals.
// The implementation follows the proposed spec in
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3599.html.
char[] stringLiteral = exp.getValue(); // The string literal that was passed to the operator
// The operator template is expected to take the character type as its first argument,
// followed by the characters as non-type arguments.
// "literal"_op -> operator "" _op<char, 'l', 'i', 't', 'e', 'r', 'a', 'l'>();
ICPPTemplateArgument args[] = new ICPPTemplateArgument[stringLiteral.length + 1];
args[0] = new CPPTemplateTypeArgument(charType);
for (int k = 0; k < stringLiteral.length; k++) {
args[k + 1] = new CPPTemplateNonTypeArgument(
new EvalFixed(CPPBasicType.CHAR, PRVALUE, IntegralValue.create(stringLiteral[k])));
}
data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), args, exp);
IBinding litTpl = resolveFunction(data, tplFunctions, true, false);
// Do we have valid template and non-template bindings?
if (ret != null && !(ret instanceof IProblemBinding)) {
// Do we have valid template and non-template bindings?
if (litTpl instanceof ICPPFunctionInstance) {
// Ambiguity? It has two valid options, and the spec says it shouldn't
return new ProblemBinding(data.getLookupName(), exp, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP,
tplFunctions);
}
} else {
if (litTpl instanceof ICPPFunctionInstance) {
// Only the template binding is valid
ret = litTpl;
} else {
// Couldn't find a valid operator
return ret;
}
}
} else if (kind == IASTLiteralExpression.lk_char_constant) { } else if (kind == IASTLiteralExpression.lk_char_constant) {
/* /*
* 2.14.8.6 * 2.14.8.6