diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-03-07 08:35:16 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-03-07 08:35:16 +0000 |
commit | 9fcce65e7e1307b5b8da9be13e4092d6bb94dc1d (patch) | |
tree | 2442cd0ff555a2ecf676e6f35d4df696831406d1 /test | |
parent | b65e24a690482e239dbd7f292bed3e87f644f8f7 (diff) |
AST representation for user-defined literals, plus just enough of semantic
analysis to make the AST representation testable. They are represented by a
new UserDefinedLiteral AST node, which is a sugared CallExpr. All semantic
properties, including full CodeGen support, are achieved for free by this
representation.
UserDefinedLiterals can never be dependent, so no custom instantiation
behavior is required. They are mangled as if they were direct calls to the
underlying literal operator. This matches g++'s apparent behavior (but not its
actual mangling, which is broken for literal-operator-ids).
User-defined *string* literals are now fully-operational, but the semantic
analysis is quite hacky and needs more work. No other forms of user-defined
literal are created yet, but the AST support for them is present.
This patch committed after midnight because we had already hit the quota for
new kinds of literal yesterday.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152211 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test')
-rw-r--r-- | test/CXX/lex/lex.literal/lex.ext/p10.cpp | 4 | ||||
-rw-r--r-- | test/CXX/lex/lex.literal/lex.ext/p8.cpp | 11 | ||||
-rw-r--r-- | test/CXX/lex/lex.literal/lex.ext/p9.cpp | 4 | ||||
-rw-r--r-- | test/CodeGenCXX/cxx11-user-defined-literal.cpp | 35 | ||||
-rw-r--r-- | test/PCH/cxx11-user-defined-literals.cpp | 21 | ||||
-rw-r--r-- | test/Parser/cxx11-user-defined-literals.cpp | 22 | ||||
-rw-r--r-- | test/SemaCXX/cxx11-ast-print.cpp | 12 |
7 files changed, 93 insertions, 16 deletions
diff --git a/test/CXX/lex/lex.literal/lex.ext/p10.cpp b/test/CXX/lex/lex.literal/lex.ext/p10.cpp index 7fbd9f8e4b..6652c9a890 100644 --- a/test/CXX/lex/lex.literal/lex.ext/p10.cpp +++ b/test/CXX/lex/lex.literal/lex.ext/p10.cpp @@ -10,6 +10,6 @@ void f() { // FIXME: Reject these for the right reason. 123wibble; // expected-error {{suffix 'wibble'}} 123.0wibble; // expected-error {{suffix 'wibble'}} - ""wibble; // expected-warning {{unused}} - R"x("hello")x"wibble; // expected-warning {{unused}} + ""wibble; + R"x("hello")x"wibble; } diff --git a/test/CXX/lex/lex.literal/lex.ext/p8.cpp b/test/CXX/lex/lex.literal/lex.ext/p8.cpp index 2833769d73..d9078221ff 100644 --- a/test/CXX/lex/lex.literal/lex.ext/p8.cpp +++ b/test/CXX/lex/lex.literal/lex.ext/p8.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -std=c++11 -verify %s -constexpr const char *operator "" _id(const char *p) { return p; } +using size_t = decltype(sizeof(int)); +constexpr const char *operator "" _id(const char *p, size_t) { return p; } constexpr const char *s = "foo"_id "bar" "baz"_id "quux"; constexpr bool streq(const char *p, const char *q) { @@ -8,12 +9,10 @@ constexpr bool streq(const char *p, const char *q) { } static_assert(streq(s, "foobarbazquux"), ""); -constexpr const char *operator "" _trim(const char *p) { - return *p == ' ' ? operator "" _trim(p + 1) : p; +constexpr const char *operator "" _trim(const char *p, size_t n) { + return *p == ' ' ? operator "" _trim(p + 1, n - 1) : p; } constexpr const char *t = " " " "_trim " foo"; -// FIXME: once we implement the semantics of user-defined literals, this should -// pass. -static_assert(streq(s, "foo"), ""); // expected-error {{static_assert}} +static_assert(streq(t, "foo"), ""); const char *u = "foo" "bar"_id "baz" "quux"_di "corge"; // expected-error {{differing user-defined suffixes ('_id' and '_di') in string literal concatenation}} diff --git a/test/CXX/lex/lex.literal/lex.ext/p9.cpp b/test/CXX/lex/lex.literal/lex.ext/p9.cpp index e3de34df9e..65e27b41b0 100644 --- a/test/CXX/lex/lex.literal/lex.ext/p9.cpp +++ b/test/CXX/lex/lex.literal/lex.ext/p9.cpp @@ -6,9 +6,7 @@ void operator "" _x(const wchar_t *, size_t); namespace std_example { int main() { - // FIXME: once we implement the semantics of literal operators, this warning - // should vanish. - L"A" "B" "C"_x; // expected-warning {{expression result unused}} + L"A" "B" "C"_x; "P"_x "Q" "R"_y; // expected-error {{differing user-defined suffixes ('_x' and '_y') in string literal concatenation}} } diff --git a/test/CodeGenCXX/cxx11-user-defined-literal.cpp b/test/CodeGenCXX/cxx11-user-defined-literal.cpp new file mode 100644 index 0000000000..fbd3621014 --- /dev/null +++ b/test/CodeGenCXX/cxx11-user-defined-literal.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s + +struct S { S(); ~S(); S(const S &); void operator()(int); }; +using size_t = decltype(sizeof(int)); +S operator"" _x(const char *, size_t); + +void f() { + // CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @{{.*}}, i32 0, i32 0), i64 3) + // CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @{{.*}}, i32 0, i32 0), i64 3) + // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind + // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind + "foo"_x, "bar"_x; +} + +template<typename T> auto g(T t) -> decltype("foo"_x(t)) { return "foo"_x(t); } +template<typename T> auto i(T t) -> decltype(operator"" _x("foo", 3)(t)) { return operator"" _x("foo", 3)(t); } + +void h() { + g(42); + i(42); +} + +// CHECK: define {{.*}} @_Z1hv() +// CHECK: call void @_Z1gIiEDTclclL_Zli2_xPKcmELA4_S0_ELm3EEfp_EET_(i32 42) +// CHECK: call void @_Z1iIiEDTclclL_Zli2_xPKcmELA4_S0_ELi3EEfp_EET_(i32 42) + +// CHECK: define {{.*}} @_Z1gIiEDTclclL_Zli2_xPKcmELA4_S0_ELm3EEfp_EET_(i32 +// CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @{{.*}}, i32 0, i32 0), i64 3) +// CHECK: call void @_ZN1SclEi +// CHECK: call void @_ZN1SD1Ev + +// CHECK: define {{.*}} @_Z1iIiEDTclclL_Zli2_xPKcmELA4_S0_ELi3EEfp_EET_(i32 +// CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @{{.*}}, i32 0, i32 0), i64 3) +// CHECK: call void @_ZN1SclEi +// CHECK: call void @_ZN1SD1Ev diff --git a/test/PCH/cxx11-user-defined-literals.cpp b/test/PCH/cxx11-user-defined-literals.cpp new file mode 100644 index 0000000000..4a7c24b994 --- /dev/null +++ b/test/PCH/cxx11-user-defined-literals.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t +// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s + +#ifndef HEADER_INCLUDED + +#define HEADER_INCLUDED + +using size_t = decltype(sizeof(int)); +int operator"" _foo(const char *p, size_t); + +template<typename T> auto f(T t) -> decltype(t + ""_foo) { return 0; } // expected-note {{substitution failure}} + +#else + +int j = ""_foo; +int k = f(0); +int *l = f(&k); +struct S {}; +int m = f(S()); // expected-error {{no matching}} + +#endif diff --git a/test/Parser/cxx11-user-defined-literals.cpp b/test/Parser/cxx11-user-defined-literals.cpp index c2d5af5c1d..e3f79ecc7c 100644 --- a/test/Parser/cxx11-user-defined-literals.cpp +++ b/test/Parser/cxx11-user-defined-literals.cpp @@ -44,11 +44,11 @@ constexpr const char16_t operator"" _id(const char16_t *p, size_t n) { return *p constexpr const char32_t operator"" _id(const char32_t *p, size_t n) { return *p; } template<int n> struct S {}; -S<"a"_id[0]> sa; -S<L"b"_id[0]> sb; -S<u8"c"_id[0]> sc; -S<u"d"_id[0]> sd; -S<U"e"_id[0]> se; +S<"a"_id> sa; +S<L"b"_id> sb; +S<u8"c"_id> sc; +S<u"d"_id> sd; +S<U"e"_id> se; S<'w'_id> sw; S<L'x'_id> sx; @@ -58,3 +58,15 @@ S<U'z'_id> sz; void h() { (void)"test"_id "test" L"test"; } + +enum class LitKind { CharStr, WideStr, Char16Str, Char32Str }; +constexpr LitKind operator"" _kind(const char *p, size_t n) { return LitKind::CharStr; } +constexpr LitKind operator"" _kind(const wchar_t *p, size_t n) { return LitKind::WideStr; } +constexpr LitKind operator"" _kind(const char16_t *p, size_t n) { return LitKind::Char16Str; } +constexpr LitKind operator"" _kind(const char32_t *p, size_t n) { return LitKind::Char32Str; } + +static_assert("foo"_kind == LitKind::CharStr, ""); +static_assert(u8"foo"_kind == LitKind::CharStr, ""); +static_assert(L"foo"_kind == LitKind::WideStr, ""); +static_assert(u"foo"_kind == LitKind::Char16Str, ""); +static_assert(U"foo"_kind == LitKind::Char32Str, ""); diff --git a/test/SemaCXX/cxx11-ast-print.cpp b/test/SemaCXX/cxx11-ast-print.cpp new file mode 100644 index 0000000000..1f6f947812 --- /dev/null +++ b/test/SemaCXX/cxx11-ast-print.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -std=c++11 -ast-print %s | FileCheck %s + +// FIXME: Print the trailing-return-type properly. +// CHECK: decltype(nullptr) operator "" _foo(const char *p, decltype(sizeof(int))); +auto operator"" _foo(const char *p, decltype(sizeof(int))) -> decltype(nullptr); + +// CHECK: const char *p1 = "bar1"_foo; +const char *p1 = "bar1"_foo; +// CHECK: const char *p2 = "bar2"_foo; +const char *p2 = R"x(bar2)x"_foo; +// CHECK: const char *p3 = u8"bar3"_foo; +const char *p3 = u8"bar3"_foo; |