diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-03-08 08:45:32 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-03-08 08:45:32 +0000 |
commit | 39570d00201ce7d9b65750e8ea5fc95e0047f467 (patch) | |
tree | 7da1856afce67cd0b55ed2711ae1756b933ae266 /clang | |
parent | 5a4bcc749acae6b92451cc9c2aa502d25600fbce (diff) | |
download | bcm5719-llvm-39570d00201ce7d9b65750e8ea5fc95e0047f467.tar.gz bcm5719-llvm-39570d00201ce7d9b65750e8ea5fc95e0047f467.zip |
Add support for cooked forms of user-defined-integer-literal and
user-defined-floating-literal. Support for raw forms of these literals
to follow.
llvm-svn: 152302
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Basic/DiagnosticLexKinds.td | 6 | ||||
-rw-r--r-- | clang/include/clang/Lex/LiteralSupport.h | 15 | ||||
-rw-r--r-- | clang/lib/Lex/LiteralSupport.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Lex/PPExpressions.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 95 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/cxx11-user-defined-literal.cpp | 8 | ||||
-rw-r--r-- | clang/test/Parser/cxx11-user-defined-literals.cpp | 41 | ||||
-rw-r--r-- | clang/test/SemaCXX/cxx11-user-defined-literals.cpp | 35 |
8 files changed, 164 insertions, 60 deletions
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 4fd55ef4e7b..ba6385b9b91 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -146,9 +146,9 @@ def err_unsupported_string_concat : Error< def err_string_concat_mixed_suffix : Error< "differing user-defined suffixes ('%0' and '%1') in string literal " "concatenation">; -def err_pp_invalid_char_udl : Error< - "character literal with user-defined suffix cannot be used in preprocessor " - "constant expression">; +def err_pp_invalid_udl : Error< + "%select{character|integer}0 literal with user-defined suffix " + "cannot be used in preprocessor constant expression">; def err_bad_string_encoding : Error< "illegal character encoding in string literal">; def warn_bad_string_encoding : ExtWarn< diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h index dd59732d19b..7e7f82f05fa 100644 --- a/clang/include/clang/Lex/LiteralSupport.h +++ b/clang/include/clang/Lex/LiteralSupport.h @@ -45,7 +45,7 @@ class NumericLiteralParser { unsigned radix; - bool saw_exponent, saw_period; + bool saw_exponent, saw_period, saw_ud_suffix; public: NumericLiteralParser(const char *begin, const char *end, @@ -64,8 +64,17 @@ public: bool isFloatingLiteral() const { return saw_period || saw_exponent; } - bool hasSuffix() const { - return SuffixBegin != ThisTokEnd; + + bool hasUDSuffix() const { + return saw_ud_suffix; + } + StringRef getUDSuffix() const { + assert(saw_ud_suffix); + return StringRef(SuffixBegin, ThisTokEnd - SuffixBegin); + } + unsigned getUDSuffixOffset() const { + assert(saw_ud_suffix); + return SuffixBegin - ThisTokBegin; } unsigned getRadix() const { return radix; } diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp index e0bdc5f8589..901d96d21ae 100644 --- a/clang/lib/Lex/LiteralSupport.cpp +++ b/clang/lib/Lex/LiteralSupport.cpp @@ -333,6 +333,10 @@ static void EncodeUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, /// decimal-constant integer-suffix /// octal-constant integer-suffix /// hexadecimal-constant integer-suffix +/// user-defiend-integer-literal: [C++11 lex.ext] +/// decimal-literal ud-suffix +/// octal-literal ud-suffix +/// hexadecimal-literal ud-suffix /// decimal-constant: /// nonzero-digit /// decimal-constant digit @@ -382,6 +386,7 @@ NumericLiteralParser(const char *begin, const char *end, s = DigitsBegin = begin; saw_exponent = false; saw_period = false; + saw_ud_suffix = false; isLong = false; isUnsigned = false; isLongLong = false; @@ -519,13 +524,20 @@ NumericLiteralParser(const char *begin, const char *end, isImaginary = true; continue; // Success. } - // If we reached here, there was an error. + // If we reached here, there was an error or a ud-suffix. break; } - // Report an error if there are any. if (s != ThisTokEnd) { - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin), + if (PP.getLangOptions().CPlusPlus0x && s == SuffixBegin && *s == '_') { + // We have a ud-suffix! By C++11 [lex.ext]p10, ud-suffixes not starting + // with an '_' are ill-formed. + saw_ud_suffix = true; + return; + } + + // Report an error if there are any. + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin-begin), isFPConstant ? diag::err_invalid_suffix_float_constant : diag::err_invalid_suffix_integer_constant) << StringRef(SuffixBegin, ThisTokEnd-SuffixBegin); diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp index 8d8fe316e7e..ae2f5c1ab23 100644 --- a/clang/lib/Lex/PPExpressions.cpp +++ b/clang/lib/Lex/PPExpressions.cpp @@ -215,6 +215,10 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, } assert(Literal.isIntegerLiteral() && "Unknown ppnumber"); + // Complain about, and drop, any ud-suffix. + if (Literal.hasUDSuffix()) + PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*integer*/1; + // long long is a C99 feature. if (!PP.getLangOptions().C99 && Literal.isLongLong) PP.Diag(PeekTok, PP.getLangOptions().CPlusPlus0x ? @@ -253,7 +257,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, case tok::utf32_char_constant: // U'x' // Complain about, and drop, any ud-suffix. if (PeekTok.hasUDSuffix()) - PP.Diag(PeekTok, diag::err_pp_invalid_char_udl); + PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*character*/0; SmallString<32> CharBuffer; bool CharInvalid = false; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index f82ff4395de..c1ce02eeea2 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2437,6 +2437,38 @@ ExprResult Sema::ActOnIntegerConstant(SourceLocation Loc, uint64_t Val) { Context.IntTy, Loc)); } +static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal, + QualType Ty, SourceLocation Loc) { + const llvm::fltSemantics &Format = S.Context.getFloatTypeSemantics(Ty); + + using llvm::APFloat; + APFloat Val(Format); + + APFloat::opStatus result = Literal.GetFloatValue(Val); + + // Overflow is always an error, but underflow is only an error if + // we underflowed to zero (APFloat reports denormals as underflow). + if ((result & APFloat::opOverflow) || + ((result & APFloat::opUnderflow) && Val.isZero())) { + unsigned diagnostic; + SmallString<20> buffer; + if (result & APFloat::opOverflow) { + diagnostic = diag::warn_float_overflow; + APFloat::getLargest(Format).toString(buffer); + } else { + diagnostic = diag::warn_float_underflow; + APFloat::getSmallest(Format).toString(buffer); + } + + S.Diag(Loc, diagnostic) + << Ty + << StringRef(buffer.data(), buffer.size()); + } + + bool isExact = (result == APFloat::opOK); + return FloatingLiteral::Create(S.Context, Val, isExact, Ty, Loc); +} + ExprResult Sema::ActOnNumericConstant(const Token &Tok) { // Fast path for a single digit (which is quite common). A single digit // cannot have a trigraph, escaped newline, radix prefix, or type suffix. @@ -2461,6 +2493,40 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { if (Literal.hadError) return ExprError(); + if (Literal.hasUDSuffix()) { + // We're building a user-defined literal. + IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix()); + SourceLocation UDSuffixLoc = + getUDSuffixLoc(*this, Tok.getLocation(), Literal.getUDSuffixOffset()); + + // FIXME: Perform literal operator lookup now, and build a raw literal if + // there is no usable operator. + + QualType Ty; + Expr *Lit; + if (Literal.isFloatingLiteral()) { + // C++11 [lex.ext]p4: If S contains a literal operator with parameter type + // long double, the literal is treated as a call of the form + // operator "" X (f L) + Lit = BuildFloatingLiteral(*this, Literal, Context.LongDoubleTy, + Tok.getLocation()); + } else { + // C++11 [lex.ext]p3: If S contains a literal operator with parameter type + // unsigned long long, the literal is treated as a call of the form + // operator "" X (n ULL) + llvm::APInt ResultVal(Context.getTargetInfo().getLongLongWidth(), 0); + if (Literal.GetIntegerValue(ResultVal)) + Diag(Tok.getLocation(), diag::warn_integer_too_large); + + QualType Ty = Context.UnsignedLongLongTy; + Lit = IntegerLiteral::Create(Context, ResultVal, Ty, Tok.getLocation()); + } + + return BuildLiteralOperatorCall(UDSuffix, UDSuffixLoc, + llvm::makeArrayRef(&Lit, 1), + Tok.getLocation()); + } + Expr *Res; if (Literal.isFloatingLiteral()) { @@ -2472,34 +2538,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { else Ty = Context.LongDoubleTy; - const llvm::fltSemantics &Format = Context.getFloatTypeSemantics(Ty); - - using llvm::APFloat; - APFloat Val(Format); - - APFloat::opStatus result = Literal.GetFloatValue(Val); - - // Overflow is always an error, but underflow is only an error if - // we underflowed to zero (APFloat reports denormals as underflow). - if ((result & APFloat::opOverflow) || - ((result & APFloat::opUnderflow) && Val.isZero())) { - unsigned diagnostic; - SmallString<20> buffer; - if (result & APFloat::opOverflow) { - diagnostic = diag::warn_float_overflow; - APFloat::getLargest(Format).toString(buffer); - } else { - diagnostic = diag::warn_float_underflow; - APFloat::getSmallest(Format).toString(buffer); - } - - Diag(Tok.getLocation(), diagnostic) - << Ty - << StringRef(buffer.data(), buffer.size()); - } - - bool isExact = (result == APFloat::opOK); - Res = FloatingLiteral::Create(Context, Val, isExact, Ty, Tok.getLocation()); + Res = BuildFloatingLiteral(*this, Literal, Ty, Tok.getLocation()); if (Ty == Context.DoubleTy) { if (getLangOptions().SinglePrecisionConstants) { diff --git a/clang/test/CodeGenCXX/cxx11-user-defined-literal.cpp b/clang/test/CodeGenCXX/cxx11-user-defined-literal.cpp index 4bd49c8b94b..647ea57cbc5 100644 --- a/clang/test/CodeGenCXX/cxx11-user-defined-literal.cpp +++ b/clang/test/CodeGenCXX/cxx11-user-defined-literal.cpp @@ -4,15 +4,21 @@ struct S { S(); ~S(); S(const S &); void operator()(int); }; using size_t = decltype(sizeof(int)); S operator"" _x(const char *, size_t); S operator"" _y(wchar_t); +S operator"" _z(unsigned long long); +S operator"" _f(long double); 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 @_Zli2_yw({{.*}} 97) + // CHECK: call void @_Zli2_zy({{.*}} 42) + // CHECK: call void @_Zli2_fe({{.*}} x86_fp80 0xK3FFF8000000000000000) // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind - "foo"_x, "bar"_x, L'a'_y; + // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind + // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind + "foo"_x, "bar"_x, L'a'_y, 42_z, 1.0_f; } template<typename T> auto g(T t) -> decltype("foo"_x(t)) { return "foo"_x(t); } diff --git a/clang/test/Parser/cxx11-user-defined-literals.cpp b/clang/test/Parser/cxx11-user-defined-literals.cpp index 80ff741ba09..b34680d080f 100644 --- a/clang/test/Parser/cxx11-user-defined-literals.cpp +++ b/clang/test/Parser/cxx11-user-defined-literals.cpp @@ -31,6 +31,12 @@ int cake() __attribute__((availability(macosx, unavailable, message = "is a lie" #error error #endif +// A ud-suffix cannot be used on integer literals in preprocessor constant +// expressions: +#if 0_foo // expected-error {{integer literal with user-defined suffix cannot be used in preprocessor constant expression}} +#error error +#endif + // But they can appear in expressions. constexpr char operator"" _id(char c) { return c; } constexpr wchar_t operator"" _id(wchar_t c) { return c; } @@ -43,6 +49,9 @@ constexpr const wchar_t operator"" _id(const wchar_t *p, size_t n) { return *p; 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; } +constexpr unsigned long long operator"" _id(unsigned long long n) { return n; } +constexpr long double operator"" _id(long double d) { return d; } + template<int n> struct S {}; S<"a"_id> sa; S<L"b"_id> sb; @@ -55,30 +64,13 @@ S<L'x'_id> sx; S<u'y'_id> sy; S<U'z'_id> sz; +S<100_id> sn; +S<(int)1.3_id> sf; + void h() { (void)"test"_id "test" L"test"; } -enum class LitKind { Char, WideChar, Char16, Char32, CharStr, WideStr, Char16Str, Char32Str }; -constexpr LitKind operator"" _kind(char p) { return LitKind::Char; } -constexpr LitKind operator"" _kind(wchar_t p) { return LitKind::WideChar; } -constexpr LitKind operator"" _kind(char16_t p) { return LitKind::Char16; } -constexpr LitKind operator"" _kind(char32_t p) { return LitKind::Char32; } -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('x'_kind == LitKind::Char, ""); -static_assert(L'x'_kind == LitKind::WideChar, ""); -static_assert(u'x'_kind == LitKind::Char16, ""); -static_assert(U'x'_kind == LitKind::Char32, ""); -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, ""); - // Test source location for suffix is known const char *p = "foo\nbar" R"x( @@ -89,7 +81,14 @@ _no_such_suffix // expected-error {{'_no_such_suffix'}} "and a bit more" "and another suffix"_no_such_suffix; -// And for character literals char c = '\x14'\ _no_such_suffix; // expected-error {{'_no_such_suffix'}} + +int &r = +1234567\ +_no_such_suffix; // expected-error {{'_no_such_suffix'}} + +int k = +1234567.89\ +_no_such_suffix; // expected-error {{'_no_such_suffix'}} diff --git a/clang/test/SemaCXX/cxx11-user-defined-literals.cpp b/clang/test/SemaCXX/cxx11-user-defined-literals.cpp new file mode 100644 index 00000000000..e77e80739cb --- /dev/null +++ b/clang/test/SemaCXX/cxx11-user-defined-literals.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s -fms-extensions -triple x86_64-apple-darwin9.0.0 + +using size_t = decltype(sizeof(int)); +enum class LitKind { + Char, WideChar, Char16, Char32, + CharStr, WideStr, Char16Str, Char32Str, + Integer, Floating +}; +constexpr LitKind operator"" _kind(char p) { return LitKind::Char; } +constexpr LitKind operator"" _kind(wchar_t p) { return LitKind::WideChar; } +constexpr LitKind operator"" _kind(char16_t p) { return LitKind::Char16; } +constexpr LitKind operator"" _kind(char32_t p) { return LitKind::Char32; } +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; } +constexpr LitKind operator"" _kind(unsigned long long n) { return LitKind::Integer; } +constexpr LitKind operator"" _kind(long double n) { return LitKind::Floating; } + +static_assert('x'_kind == LitKind::Char, ""); +static_assert(L'x'_kind == LitKind::WideChar, ""); +static_assert(u'x'_kind == LitKind::Char16, ""); +static_assert(U'x'_kind == LitKind::Char32, ""); +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, ""); +static_assert(194_kind == LitKind::Integer, ""); +static_assert(0377_kind == LitKind::Integer, ""); +static_assert(0x5ffc_kind == LitKind::Integer, ""); +static_assert(.5954_kind == LitKind::Floating, ""); +static_assert(1._kind == LitKind::Floating, ""); +static_assert(1.e-2_kind == LitKind::Floating, ""); +static_assert(4e6_kind == LitKind::Floating, ""); |