diff options
| author | Tim Northover <tnorthover@apple.com> | 2017-08-09 14:56:48 +0000 |
|---|---|---|
| committer | Tim Northover <tnorthover@apple.com> | 2017-08-09 14:56:48 +0000 |
| commit | 9710338a5699a48b26807693371d277b1acb3387 (patch) | |
| tree | e97f8396124bb954de3a321dbc7ea61e95a5f0ca | |
| parent | 922ca2345d29f3c6bd089afedbb06b7d88bd4d99 (diff) | |
| download | bcm5719-llvm-9710338a5699a48b26807693371d277b1acb3387.tar.gz bcm5719-llvm-9710338a5699a48b26807693371d277b1acb3387.zip | |
Reapply Sema: allow imaginary constants via GNU extension if UDL overloads not present.
C++14 added user-defined literal support for complex numbers so that you
can write something like "complex<double> val = 2i". However, there is
an existing GNU extension supporting this syntax and interpreting the
result as a _Complex type.
This changes parsing so that such literals are interpreted in terms of
C++14's operators if an overload is present but otherwise falls back to
the original GNU extension.
(We now have more robust diagnostics for implicit conversions so the
libc++ test that caused the original revert still passes).
llvm-svn: 310478
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticLexKinds.td | 2 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 5 | ||||
| -rw-r--r-- | clang/lib/Lex/LiteralSupport.cpp | 44 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 25 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 16 | ||||
| -rw-r--r-- | clang/test/SemaCXX/imaginary-constants.cpp | 44 |
7 files changed, 97 insertions, 41 deletions
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index d6de5c04a74..40bd06ef3dd 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -173,8 +173,6 @@ def warn_char_constant_too_large : Warning< def err_multichar_utf_character_literal : Error< "Unicode character literals may not contain multiple characters">; def err_exponent_has_no_digits : Error<"exponent has no digits">; -def ext_imaginary_constant : Extension< - "imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>; def err_hex_constant_requires : Error< "hexadecimal floating %select{constant|literal}0 requires " "%select{an exponent|a significand}1">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 8a5c6458301..b251bd1967a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -194,6 +194,8 @@ def warn_duplicate_declspec : Warning<"duplicate '%0' declaration specifier">, InGroup<DuplicateDeclSpecifier>; def ext_plain_complex : ExtWarn< "plain '_Complex' requires a type specifier; assuming '_Complex double'">; +def ext_imaginary_constant : Extension< + "imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>; def ext_integer_complex : Extension< "complex integer types are a GNU extension">, InGroup<GNUComplexInteger>; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 30fb56e338e..267b613acef 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3020,6 +3020,8 @@ public: enum LiteralOperatorLookupResult { /// \brief The lookup resulted in an error. LOLR_Error, + /// \brief The lookup found no match but no diagnostic was issued. + LOLR_ErrorNoDiagnostic, /// \brief The lookup found a single 'cooked' literal operator, which /// expects a normal literal to be built and passed to it. LOLR_Cooked, @@ -3144,7 +3146,8 @@ public: ArrayRef<QualType> ArgTys, bool AllowRaw, bool AllowTemplate, - bool AllowStringTemplate); + bool AllowStringTemplate, + bool DiagnoseMissing); bool isKnownName(StringRef name); void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp index a598a467816..3cc45cea97a 100644 --- a/clang/lib/Lex/LiteralSupport.cpp +++ b/clang/lib/Lex/LiteralSupport.cpp @@ -658,9 +658,6 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, break; } } - // "i", "if", and "il" are user-defined suffixes in C++1y. - if (*s == 'i' && PP.getLangOpts().CPlusPlus14) - break; // fall through. case 'j': case 'J': @@ -672,35 +669,34 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, break; } - if (s != ThisTokEnd) { + // "i", "if", and "il" are user-defined suffixes in C++1y. + if (s != ThisTokEnd || isImaginary) { // FIXME: Don't bother expanding UCNs if !tok.hasUCN(). expandUCNs(UDSuffixBuf, StringRef(SuffixBegin, ThisTokEnd - SuffixBegin)); if (isValidUDSuffix(PP.getLangOpts(), UDSuffixBuf)) { - // Any suffix pieces we might have parsed are actually part of the - // ud-suffix. - isLong = false; - isUnsigned = false; - isLongLong = false; - isFloat = false; - isHalf = false; - isImaginary = false; - MicrosoftInteger = 0; + if (!isImaginary) { + // Any suffix pieces we might have parsed are actually part of the + // ud-suffix. + isLong = false; + isUnsigned = false; + isLongLong = false; + isFloat = false; + isHalf = false; + isImaginary = false; + MicrosoftInteger = 0; + } saw_ud_suffix = true; return; } - // Report an error if there are any. - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin), - diag::err_invalid_suffix_constant) - << StringRef(SuffixBegin, ThisTokEnd-SuffixBegin) << isFPConstant; - hadError = true; - return; - } - - if (isImaginary) { - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin), - diag::ext_imaginary_constant); + if (s != ThisTokEnd) { + // Report an error if there are any. + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin), + diag::err_invalid_suffix_constant) + << StringRef(SuffixBegin, ThisTokEnd - SuffixBegin) << isFPConstant; + hadError = true; + } } } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index a1d39672449..7842f308c80 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1502,8 +1502,9 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope, LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName); if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()), - /*AllowRaw*/false, /*AllowTemplate*/false, - /*AllowStringTemplate*/false) == Sema::LOLR_Error) + /*AllowRaw*/ false, /*AllowTemplate*/ false, + /*AllowStringTemplate*/ false, + /*DiagnoseMissing*/ true) == Sema::LOLR_Error) return ExprError(); return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc); @@ -1594,8 +1595,9 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName); switch (LookupLiteralOperator(UDLScope, R, ArgTy, - /*AllowRaw*/false, /*AllowTemplate*/false, - /*AllowStringTemplate*/true)) { + /*AllowRaw*/ false, /*AllowTemplate*/ false, + /*AllowStringTemplate*/ true, + /*DiagnoseMissing*/ true)) { case LOLR_Cooked: { llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars()); @@ -1628,6 +1630,7 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { } case LOLR_Raw: case LOLR_Template: + case LOLR_ErrorNoDiagnostic: llvm_unreachable("unexpected literal operator lookup result"); case LOLR_Error: return ExprError(); @@ -3250,11 +3253,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { // literal or a cooked one. LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName); switch (LookupLiteralOperator(UDLScope, R, CookedTy, - /*AllowRaw*/true, /*AllowTemplate*/true, - /*AllowStringTemplate*/false)) { + /*AllowRaw*/ true, /*AllowTemplate*/ true, + /*AllowStringTemplate*/ false, + /*DiagnoseMissing*/ !Literal.isImaginary)) { + case LOLR_ErrorNoDiagnostic: + // Lookup failure for imaginary constants isn't fatal, there's still the + // GNU extension producing _Complex types. + break; case LOLR_Error: return ExprError(); - case LOLR_Cooked: { Expr *Lit; if (Literal.isFloatingLiteral()) { @@ -3470,10 +3477,12 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } // If this is an imaginary literal, create the ImaginaryLiteral wrapper. - if (Literal.isImaginary) + if (Literal.isImaginary) { Res = new (Context) ImaginaryLiteral(Res, Context.getComplexType(Res->getType())); + Diag(Tok.getLocation(), diag::ext_imaginary_constant); + } return Res; } diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 4f88edcb31f..a89d3ace244 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3122,7 +3122,7 @@ Sema::LiteralOperatorLookupResult Sema::LookupLiteralOperator(Scope *S, LookupResult &R, ArrayRef<QualType> ArgTys, bool AllowRaw, bool AllowTemplate, - bool AllowStringTemplate) { + bool AllowStringTemplate, bool DiagnoseMissing) { LookupName(R, S); assert(R.getResultKind() != LookupResult::Ambiguous && "literal operator lookup can't be ambiguous"); @@ -3223,11 +3223,15 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R, return LOLR_StringTemplate; // Didn't find anything we could use. - Diag(R.getNameLoc(), diag::err_ovl_no_viable_literal_operator) - << R.getLookupName() << (int)ArgTys.size() << ArgTys[0] - << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRaw - << (AllowTemplate || AllowStringTemplate); - return LOLR_Error; + if (DiagnoseMissing) { + Diag(R.getNameLoc(), diag::err_ovl_no_viable_literal_operator) + << R.getLookupName() << (int)ArgTys.size() << ArgTys[0] + << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRaw + << (AllowTemplate || AllowStringTemplate); + return LOLR_Error; + } + + return LOLR_ErrorNoDiagnostic; } void ADLResult::insert(NamedDecl *New) { diff --git a/clang/test/SemaCXX/imaginary-constants.cpp b/clang/test/SemaCXX/imaginary-constants.cpp new file mode 100644 index 00000000000..bbff92755a1 --- /dev/null +++ b/clang/test/SemaCXX/imaginary-constants.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -include %s -std=gnu++98 +// RUN: %clang_cc1 -fsyntax-only -verify %s -include %s -std=c++11 +// RUN: %clang_cc1 -fsyntax-only -verify %s -include %s -std=c++14 -DCXX14=1 + +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +_Complex int val1 = 2i; +_Complex long val2 = 2il; +_Complex long long val3 = 2ill; +_Complex float val4 = 2.0if; +_Complex double val5 = 2.0i; +_Complex long double val6 = 2.0il; + +#if CXX14 + +#pragma clang system_header + +namespace std { + template<typename T> struct complex {}; + complex<float> operator""if(unsigned long long); + complex<float> operator""if(long double); + + complex<double> operator"" i(unsigned long long); + complex<double> operator"" i(long double); + + complex<long double> operator"" il(unsigned long long); + complex<long double> operator"" il(long double); +} + +using namespace std; + +complex<float> f1 = 2.0if; +complex<float> f2 = 2if; +complex<double> d1 = 2.0i; +complex<double> d2 = 2i; +complex<long double> l1 = 2.0il; +complex<long double> l2 = 2il; + +#endif + +#endif |

