forked from OSchip/llvm-project
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. llvm-svn: 303694
This commit is contained in:
parent
26450bf579
commit
6b5eceac2e
|
@ -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">;
|
||||
|
|
|
@ -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>;
|
||||
|
||||
|
|
|
@ -2946,6 +2946,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,
|
||||
|
@ -3070,7 +3072,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,
|
||||
|
|
|
@ -652,9 +652,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':
|
||||
|
@ -667,36 +664,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,
|
||||
ImaginarySuffixLoc - 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1599,8 +1599,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);
|
||||
|
@ -1691,8 +1692,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());
|
||||
|
@ -1725,6 +1727,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();
|
||||
|
@ -3347,11 +3350,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()) {
|
||||
|
@ -3567,10 +3574,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -3066,7 +3066,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");
|
||||
|
@ -3167,11 +3167,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) {
|
||||
|
|
|
@ -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
|
|
@ -2394,9 +2394,12 @@ void SelectionDAGBuilder::visitIndirectBr(const IndirectBrInst &I) {
|
|||
}
|
||||
|
||||
void SelectionDAGBuilder::visitUnreachable(const UnreachableInst &I) {
|
||||
if (DAG.getTarget().Options.TrapUnreachable)
|
||||
errs() << "WARNING: trap\n";
|
||||
if (DAG.getTarget().Options.TrapUnreachable) {
|
||||
DAG.setRoot(
|
||||
DAG.getNode(ISD::TRAP, getCurSDLoc(), MVT::Other, DAG.getRoot()));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SelectionDAGBuilder::visitFSub(const User &I) {
|
||||
|
|
Loading…
Reference in New Issue