mirror of
https://github.com/intel/llvm.git
synced 2026-01-24 08:30:34 +08:00
Support for raw and template forms of numeric user-defined literals,
and lots of tidying up. llvm-svn: 152392
This commit is contained in:
@@ -43,6 +43,10 @@ def err_expected_colon_after_setter_name : Error<
|
||||
"must end with ':'">;
|
||||
def err_invalid_string_udl : Error<
|
||||
"string literal with user-defined suffix cannot be used here">;
|
||||
def err_invalid_character_udl : Error<
|
||||
"character literal with user-defined suffix cannot be used here">;
|
||||
def err_invalid_numeric_udl : Error<
|
||||
"numeric literal with user-defined suffix cannot be used here">;
|
||||
|
||||
// Parse && Sema
|
||||
def ext_no_declarators : ExtWarn<"declaration does not declare anything">,
|
||||
|
||||
@@ -2195,7 +2195,13 @@ def err_addr_ovl_not_func_ptrref : Error<
|
||||
"address of overloaded function %0 cannot be converted to type %1">;
|
||||
def err_addr_ovl_no_qualifier : Error<
|
||||
"can't form member pointer of type %0 without '&' and class name">;
|
||||
|
||||
|
||||
// C++11 Literal Operators
|
||||
def err_ovl_no_viable_literal_operator : Error<
|
||||
"no matching literal operator for call to %0"
|
||||
"%select{| with argument of type %2| with arguments of types %2 and %3}1"
|
||||
"%select{| or 'const char *', and no matching literal operator template}4">;
|
||||
|
||||
// C++ Template Declarations
|
||||
def err_template_param_shadow : Error<
|
||||
"declaration of %0 shadows template parameter">;
|
||||
|
||||
@@ -550,6 +550,11 @@ public:
|
||||
return *I++;
|
||||
}
|
||||
|
||||
/// Restart the iteration.
|
||||
void restart() {
|
||||
I = Results.begin();
|
||||
}
|
||||
|
||||
/// Erase the last element returned from this iterator.
|
||||
void erase() {
|
||||
Results.Decls.erase(--I);
|
||||
|
||||
@@ -1552,7 +1552,8 @@ public:
|
||||
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
|
||||
llvm::ArrayRef<Expr *> Args,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions = false);
|
||||
bool SuppressUserConversions = false,
|
||||
TemplateArgumentListInfo *ExplicitTemplateArgs = 0);
|
||||
void AddMethodCandidate(DeclAccessPair FoundDecl,
|
||||
QualType ObjectType,
|
||||
Expr::Classification ObjectClassification,
|
||||
@@ -1794,6 +1795,22 @@ public:
|
||||
ForRedeclaration
|
||||
};
|
||||
|
||||
/// \brief The possible outcomes of name lookup for a literal operator.
|
||||
enum LiteralOperatorLookupResult {
|
||||
/// \brief The lookup resulted in an error.
|
||||
LOLR_Error,
|
||||
/// \brief The lookup found a single 'cooked' literal operator, which
|
||||
/// expects a normal literal to be built and passed to it.
|
||||
LOLR_Cooked,
|
||||
/// \brief The lookup found a single 'raw' literal operator, which expects
|
||||
/// a string literal containing the spelling of the literal token.
|
||||
LOLR_Raw,
|
||||
/// \brief The lookup found an overload set of literal operator templates,
|
||||
/// which expect the characters of the spelling of the literal token to be
|
||||
/// passed as a non-type template argument pack.
|
||||
LOLR_Template
|
||||
};
|
||||
|
||||
SpecialMemberOverloadResult *LookupSpecialMember(CXXRecordDecl *D,
|
||||
CXXSpecialMember SM,
|
||||
bool ConstArg,
|
||||
@@ -1857,6 +1874,10 @@ public:
|
||||
unsigned ThisQuals);
|
||||
CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class);
|
||||
|
||||
LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R,
|
||||
ArrayRef<QualType> ArgTys,
|
||||
bool AllowRawAndTemplate);
|
||||
|
||||
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
|
||||
SourceLocation Loc,
|
||||
llvm::ArrayRef<Expr *> Args,
|
||||
@@ -2545,15 +2566,16 @@ public:
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
NamedDecl *D);
|
||||
|
||||
ExprResult BuildLiteralOperatorCall(IdentifierInfo *UDSuffix,
|
||||
SourceLocation UDSuffixLoc,
|
||||
ExprResult BuildLiteralOperatorCall(LookupResult &R,
|
||||
DeclarationNameInfo &SuffixInfo,
|
||||
ArrayRef<Expr*> Args,
|
||||
SourceLocation LitEndLoc);
|
||||
SourceLocation LitEndLoc,
|
||||
TemplateArgumentListInfo *ExplicitTemplateArgs = 0);
|
||||
|
||||
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
|
||||
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
|
||||
ExprResult ActOnNumericConstant(const Token &Tok);
|
||||
ExprResult ActOnCharacterConstant(const Token &Tok);
|
||||
ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = 0);
|
||||
ExprResult ActOnCharacterConstant(const Token &Tok, Scope *UDLScope = 0);
|
||||
ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E);
|
||||
ExprResult ActOnParenListExpr(SourceLocation L,
|
||||
SourceLocation R,
|
||||
@@ -2561,8 +2583,8 @@ public:
|
||||
|
||||
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
|
||||
/// fragments (e.g. "foo" "bar" L"baz").
|
||||
ExprResult ActOnStringLiteral(const Token *StringToks,
|
||||
unsigned NumStringToks);
|
||||
ExprResult ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks,
|
||||
Scope *UDLScope = 0);
|
||||
|
||||
ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc,
|
||||
SourceLocation DefaultLoc,
|
||||
|
||||
@@ -164,6 +164,8 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
|
||||
for (unsigned I = 0, E = QualTypeVals.size(); I != E; ++I) {
|
||||
QualType CompareTy =
|
||||
QualType::getFromOpaquePtr(reinterpret_cast<void*>(QualTypeVals[I]));
|
||||
if (CompareTy.isNull())
|
||||
continue;
|
||||
if (CompareTy == Ty)
|
||||
continue; // Same types
|
||||
QualType CompareCanTy = CompareTy.getCanonicalType();
|
||||
|
||||
@@ -4613,7 +4613,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
|
||||
} else if (Tok.getKind() == tok::numeric_constant &&
|
||||
GetLookAheadToken(1).is(tok::r_square)) {
|
||||
// [4] is very common. Parse the numeric constant expression.
|
||||
ExprResult ExprRes(Actions.ActOnNumericConstant(Tok));
|
||||
ExprResult ExprRes(Actions.ActOnNumericConstant(Tok, getCurScope()));
|
||||
ConsumeToken();
|
||||
|
||||
T.consumeClose();
|
||||
|
||||
@@ -700,7 +700,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
||||
// constant: integer-constant
|
||||
// constant: floating-constant
|
||||
|
||||
Res = Actions.ActOnNumericConstant(Tok);
|
||||
Res = Actions.ActOnNumericConstant(Tok, /*UDLScope*/getCurScope());
|
||||
ConsumeToken();
|
||||
break;
|
||||
|
||||
@@ -841,7 +841,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
||||
case tok::wide_char_constant:
|
||||
case tok::utf16_char_constant:
|
||||
case tok::utf32_char_constant:
|
||||
Res = Actions.ActOnCharacterConstant(Tok);
|
||||
Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope());
|
||||
ConsumeToken();
|
||||
break;
|
||||
case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
|
||||
@@ -2120,18 +2120,13 @@ ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) {
|
||||
SmallVector<Token, 4> StringToks;
|
||||
|
||||
do {
|
||||
if (!AllowUserDefinedLiteral && Tok.hasUDSuffix()) {
|
||||
Diag(Tok, diag::err_invalid_string_udl);
|
||||
do ConsumeStringToken(); while (isTokenStringLiteral());
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
StringToks.push_back(Tok);
|
||||
ConsumeStringToken();
|
||||
} while (isTokenStringLiteral());
|
||||
|
||||
// Pass the set of string tokens, ready for concatenation, to the actions.
|
||||
return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size());
|
||||
return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size(),
|
||||
AllowUserDefinedLiteral ? getCurScope() : 0);
|
||||
}
|
||||
|
||||
/// ParseGenericSelectionExpression - Parse a C11 generic-selection
|
||||
|
||||
@@ -2042,8 +2042,6 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
|
||||
|
||||
case tok::string_literal: // primary-expression: string-literal
|
||||
case tok::wide_string_literal:
|
||||
if (Tok.hasUDSuffix())
|
||||
return ExprError(Diag(Tok, diag::err_invalid_string_udl));
|
||||
return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
|
||||
|
||||
case tok::char_constant:
|
||||
|
||||
@@ -9306,9 +9306,15 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
|
||||
|
||||
bool Valid = false;
|
||||
|
||||
// This might be the definition of a literal operator template.
|
||||
FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate();
|
||||
// This might be a specialization of a literal operator template.
|
||||
if (!TpDecl)
|
||||
TpDecl = FnDecl->getPrimaryTemplate();
|
||||
|
||||
// template <char...> type operator "" name() is the only valid template
|
||||
// signature, and the only valid signature with no parameters.
|
||||
if (FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate()) {
|
||||
if (TpDecl) {
|
||||
if (FnDecl->param_size() == 0) {
|
||||
// Must have only one template parameter
|
||||
TemplateParameterList *Params = TpDecl->getTemplateParameters();
|
||||
|
||||
@@ -1130,6 +1130,35 @@ static SourceLocation getUDSuffixLoc(Sema &S, SourceLocation TokLoc,
|
||||
S.getLangOptions());
|
||||
}
|
||||
|
||||
/// BuildCookedLiteralOperatorCall - A user-defined literal was found. Look up
|
||||
/// the corresponding cooked (non-raw) literal operator, and build a call to it.
|
||||
static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope,
|
||||
IdentifierInfo *UDSuffix,
|
||||
SourceLocation UDSuffixLoc,
|
||||
ArrayRef<Expr*> Args,
|
||||
SourceLocation LitEndLoc) {
|
||||
assert(Args.size() <= 2 && "too many arguments for literal operator");
|
||||
|
||||
QualType ArgTy[2];
|
||||
for (unsigned ArgIdx = 0; ArgIdx != Args.size(); ++ArgIdx) {
|
||||
ArgTy[ArgIdx] = Args[ArgIdx]->getType();
|
||||
if (ArgTy[ArgIdx]->isArrayType())
|
||||
ArgTy[ArgIdx] = S.Context.getArrayDecayedType(ArgTy[ArgIdx]);
|
||||
}
|
||||
|
||||
DeclarationName OpName =
|
||||
S.Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix);
|
||||
DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc);
|
||||
OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc);
|
||||
|
||||
LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName);
|
||||
if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()),
|
||||
/*AllowRawAndTemplate*/false) == Sema::LOLR_Error)
|
||||
return ExprError();
|
||||
|
||||
return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc);
|
||||
}
|
||||
|
||||
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
|
||||
/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string
|
||||
/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from
|
||||
@@ -1137,7 +1166,8 @@ static SourceLocation getUDSuffixLoc(Sema &S, SourceLocation TokLoc,
|
||||
/// string.
|
||||
///
|
||||
ExprResult
|
||||
Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
|
||||
Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks,
|
||||
Scope *UDLScope) {
|
||||
assert(NumStringToks && "Must have at least one string!");
|
||||
|
||||
StringLiteralParser Literal(StringToks, NumStringToks, PP);
|
||||
@@ -1193,6 +1223,10 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
|
||||
getUDSuffixLoc(*this, StringTokLocs[Literal.getUDSuffixToken()],
|
||||
Literal.getUDSuffixOffset());
|
||||
|
||||
// Make sure we're allowed user-defined literals here.
|
||||
if (!UDLScope)
|
||||
return ExprError(Diag(UDSuffixLoc, diag::err_invalid_string_udl));
|
||||
|
||||
// C++11 [lex.ext]p5: The literal L is treated as a call of the form
|
||||
// operator "" X (str, len)
|
||||
QualType SizeType = Context.getSizeType();
|
||||
@@ -1200,8 +1234,8 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
|
||||
IntegerLiteral *LenArg = IntegerLiteral::Create(Context, Len, SizeType,
|
||||
StringTokLocs[0]);
|
||||
Expr *Args[] = { Lit, LenArg };
|
||||
return BuildLiteralOperatorCall(UDSuffix, UDSuffixLoc, Args,
|
||||
StringTokLocs.back());
|
||||
return BuildCookedLiteralOperatorCall(*this, UDLScope, UDSuffix, UDSuffixLoc,
|
||||
Args, StringTokLocs.back());
|
||||
}
|
||||
|
||||
ExprResult
|
||||
@@ -2381,7 +2415,7 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
|
||||
return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
|
||||
ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) {
|
||||
SmallString<16> CharBuffer;
|
||||
bool Invalid = false;
|
||||
StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid);
|
||||
@@ -2424,11 +2458,15 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
|
||||
SourceLocation UDSuffixLoc =
|
||||
getUDSuffixLoc(*this, Tok.getLocation(), Literal.getUDSuffixOffset());
|
||||
|
||||
// Make sure we're allowed user-defined literals here.
|
||||
if (!UDLScope)
|
||||
return ExprError(Diag(UDSuffixLoc, diag::err_invalid_character_udl));
|
||||
|
||||
// C++11 [lex.ext]p6: The literal L is treated as a call of the form
|
||||
// operator "" X (ch)
|
||||
return BuildLiteralOperatorCall(UDSuffix, UDSuffixLoc,
|
||||
llvm::makeArrayRef(&Lit, 1),
|
||||
Tok.getLocation());
|
||||
return BuildCookedLiteralOperatorCall(*this, UDLScope, UDSuffix, UDSuffixLoc,
|
||||
llvm::makeArrayRef(&Lit, 1),
|
||||
Tok.getLocation());
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnIntegerConstant(SourceLocation Loc, uint64_t Val) {
|
||||
@@ -2469,9 +2507,9 @@ static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal,
|
||||
return FloatingLiteral::Create(S.Context, Val, isExact, Ty, Loc);
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
|
||||
ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
|
||||
// Fast path for a single digit (which is quite common). A single digit
|
||||
// cannot have a trigraph, escaped newline, radix prefix, or type suffix.
|
||||
// cannot have a trigraph, escaped newline, radix prefix, or suffix.
|
||||
if (Tok.getLength() == 1) {
|
||||
const char Val = PP.getSpellingOfSingleCharacterNumericConstant(Tok);
|
||||
return ActOnIntegerConstant(Tok.getLocation(), Val-'0');
|
||||
@@ -2499,32 +2537,88 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
|
||||
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.
|
||||
// Make sure we're allowed user-defined literals here.
|
||||
if (!UDLScope)
|
||||
return ExprError(Diag(UDSuffixLoc, diag::err_invalid_numeric_udl));
|
||||
|
||||
QualType Ty;
|
||||
Expr *Lit;
|
||||
QualType CookedTy;
|
||||
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());
|
||||
CookedTy = Context.LongDoubleTy;
|
||||
} 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());
|
||||
CookedTy = Context.UnsignedLongLongTy;
|
||||
}
|
||||
|
||||
return BuildLiteralOperatorCall(UDSuffix, UDSuffixLoc,
|
||||
llvm::makeArrayRef(&Lit, 1),
|
||||
Tok.getLocation());
|
||||
DeclarationName OpName =
|
||||
Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix);
|
||||
DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc);
|
||||
OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc);
|
||||
|
||||
// Perform literal operator lookup to determine if we're building a raw
|
||||
// literal or a cooked one.
|
||||
LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName);
|
||||
switch (LookupLiteralOperator(UDLScope, R, llvm::makeArrayRef(&CookedTy, 1),
|
||||
/*AllowRawAndTemplate*/true)) {
|
||||
case LOLR_Error:
|
||||
return ExprError();
|
||||
|
||||
case LOLR_Cooked: {
|
||||
Expr *Lit;
|
||||
if (Literal.isFloatingLiteral()) {
|
||||
Lit = BuildFloatingLiteral(*this, Literal, CookedTy, Tok.getLocation());
|
||||
} else {
|
||||
llvm::APInt ResultVal(Context.getTargetInfo().getLongLongWidth(), 0);
|
||||
if (Literal.GetIntegerValue(ResultVal))
|
||||
Diag(Tok.getLocation(), diag::warn_integer_too_large);
|
||||
Lit = IntegerLiteral::Create(Context, ResultVal, CookedTy,
|
||||
Tok.getLocation());
|
||||
}
|
||||
return BuildLiteralOperatorCall(R, OpNameInfo,
|
||||
llvm::makeArrayRef(&Lit, 1),
|
||||
Tok.getLocation());
|
||||
}
|
||||
|
||||
case LOLR_Raw: {
|
||||
// C++11 [lit.ext]p3, p4: If S contains a raw literal operator, the
|
||||
// literal is treated as a call of the form
|
||||
// operator "" X ("n")
|
||||
SourceLocation TokLoc = Tok.getLocation();
|
||||
unsigned Length = Literal.getUDSuffixOffset();
|
||||
QualType StrTy = Context.getConstantArrayType(
|
||||
Context.CharTy, llvm::APInt(32, Length + 1),
|
||||
ArrayType::Normal, 0);
|
||||
Expr *Lit = StringLiteral::Create(
|
||||
Context, StringRef(ThisTokBegin, Length), StringLiteral::Ascii,
|
||||
/*Pascal*/false, StrTy, &TokLoc, 1);
|
||||
return BuildLiteralOperatorCall(R, OpNameInfo,
|
||||
llvm::makeArrayRef(&Lit, 1), TokLoc);
|
||||
}
|
||||
|
||||
case LOLR_Template:
|
||||
// C++11 [lit.ext]p3, p4: Otherwise (S contains a literal operator
|
||||
// template), L is treated as a call fo the form
|
||||
// operator "" X <'c1', 'c2', ... 'ck'>()
|
||||
// where n is the source character sequence c1 c2 ... ck.
|
||||
TemplateArgumentListInfo ExplicitArgs;
|
||||
unsigned CharBits = Context.getIntWidth(Context.CharTy);
|
||||
bool CharIsUnsigned = Context.CharTy->isUnsignedIntegerType();
|
||||
llvm::APSInt Value(CharBits, CharIsUnsigned);
|
||||
for (unsigned I = 0, N = Literal.getUDSuffixOffset(); I != N; ++I) {
|
||||
Value = ThisTokBegin[I];
|
||||
TemplateArgument Arg(Value, Context.CharTy);
|
||||
TemplateArgumentLocInfo ArgInfo;
|
||||
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
|
||||
}
|
||||
return BuildLiteralOperatorCall(R, OpNameInfo, ArrayRef<Expr*>(),
|
||||
Tok.getLocation(), &ExplicitArgs);
|
||||
}
|
||||
|
||||
llvm_unreachable("unexpected literal operator lookup result");
|
||||
}
|
||||
|
||||
Expr *Res;
|
||||
|
||||
@@ -2525,6 +2525,105 @@ CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) {
|
||||
false, false)->getMethod());
|
||||
}
|
||||
|
||||
/// LookupLiteralOperator - Determine which literal operator should be used for
|
||||
/// a user-defined literal, per C++11 [lex.ext].
|
||||
///
|
||||
/// Normal overload resolution is not used to select which literal operator to
|
||||
/// call for a user-defined literal. Look up the provided literal operator name,
|
||||
/// and filter the results to the appropriate set for the given argument types.
|
||||
Sema::LiteralOperatorLookupResult
|
||||
Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
|
||||
ArrayRef<QualType> ArgTys,
|
||||
bool AllowRawAndTemplate) {
|
||||
LookupName(R, S);
|
||||
assert(R.getResultKind() != LookupResult::Ambiguous &&
|
||||
"literal operator lookup can't be ambiguous");
|
||||
|
||||
// Filter the lookup results appropriately.
|
||||
LookupResult::Filter F = R.makeFilter();
|
||||
|
||||
bool FoundTemplate = false;
|
||||
bool FoundRaw = false;
|
||||
bool FoundExactMatch = false;
|
||||
|
||||
while (F.hasNext()) {
|
||||
Decl *D = F.next();
|
||||
if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D))
|
||||
D = USD->getTargetDecl();
|
||||
|
||||
bool IsTemplate = isa<FunctionTemplateDecl>(D);
|
||||
bool IsRaw = false;
|
||||
bool IsExactMatch = false;
|
||||
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
if (FD->getNumParams() == 1 &&
|
||||
FD->getParamDecl(0)->getType()->getAs<PointerType>())
|
||||
IsRaw = true;
|
||||
else {
|
||||
IsExactMatch = true;
|
||||
for (unsigned ArgIdx = 0; ArgIdx != ArgTys.size(); ++ArgIdx) {
|
||||
QualType ParamTy = FD->getParamDecl(ArgIdx)->getType();
|
||||
if (!Context.hasSameUnqualifiedType(ArgTys[ArgIdx], ParamTy)) {
|
||||
IsExactMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsExactMatch) {
|
||||
FoundExactMatch = true;
|
||||
AllowRawAndTemplate = false;
|
||||
if (FoundRaw || FoundTemplate) {
|
||||
// Go through again and remove the raw and template decls we've
|
||||
// already found.
|
||||
F.restart();
|
||||
FoundRaw = FoundTemplate = false;
|
||||
}
|
||||
} else if (AllowRawAndTemplate && (IsTemplate || IsRaw)) {
|
||||
FoundTemplate |= IsTemplate;
|
||||
FoundRaw |= IsRaw;
|
||||
} else {
|
||||
F.erase();
|
||||
}
|
||||
}
|
||||
|
||||
F.done();
|
||||
|
||||
// C++11 [lex.ext]p3, p4: If S contains a literal operator with a matching
|
||||
// parameter type, that is used in preference to a raw literal operator
|
||||
// or literal operator template.
|
||||
if (FoundExactMatch)
|
||||
return LOLR_Cooked;
|
||||
|
||||
// C++11 [lex.ext]p3, p4: S shall contain a raw literal operator or a literal
|
||||
// operator template, but not both.
|
||||
if (FoundRaw && FoundTemplate) {
|
||||
Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName();
|
||||
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
|
||||
Decl *D = *I;
|
||||
if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D))
|
||||
D = USD->getTargetDecl();
|
||||
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
|
||||
D = FunTmpl->getTemplatedDecl();
|
||||
NoteOverloadCandidate(cast<FunctionDecl>(D));
|
||||
}
|
||||
return LOLR_Error;
|
||||
}
|
||||
|
||||
if (FoundRaw)
|
||||
return LOLR_Raw;
|
||||
|
||||
if (FoundTemplate)
|
||||
return LOLR_Template;
|
||||
|
||||
// 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()) << AllowRawAndTemplate;
|
||||
return LOLR_Error;
|
||||
}
|
||||
|
||||
void ADLResult::insert(NamedDecl *New) {
|
||||
NamedDecl *&Old = Decls[cast<NamedDecl>(New->getCanonicalDecl())];
|
||||
|
||||
|
||||
@@ -5236,7 +5236,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
|
||||
void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
|
||||
llvm::ArrayRef<Expr *> Args,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions) {
|
||||
bool SuppressUserConversions,
|
||||
TemplateArgumentListInfo *ExplicitTemplateArgs) {
|
||||
for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
|
||||
NamedDecl *D = F.getDecl()->getUnderlyingDecl();
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
@@ -5255,13 +5256,13 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
|
||||
!cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic())
|
||||
AddMethodTemplateCandidate(FunTmpl, F.getPair(),
|
||||
cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
|
||||
/*FIXME: explicit args */ 0,
|
||||
ExplicitTemplateArgs,
|
||||
Args[0]->getType(),
|
||||
Args[0]->Classify(Context), Args.slice(1),
|
||||
CandidateSet, SuppressUserConversions);
|
||||
else
|
||||
AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
|
||||
/*FIXME: explicit args */ 0, Args,
|
||||
ExplicitTemplateArgs, Args,
|
||||
CandidateSet, SuppressUserConversions);
|
||||
}
|
||||
}
|
||||
@@ -10895,66 +10896,60 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
|
||||
return MaybeBindToTemporary(TheCall);
|
||||
}
|
||||
|
||||
static void FilterLookupForLiteralOperator(Sema &S, LookupResult &R,
|
||||
ArrayRef<Expr*> Args) {
|
||||
LookupResult::Filter F = R.makeFilter();
|
||||
/// BuildLiteralOperatorCall - Build a UserDefinedLiteral by creating a call to
|
||||
/// a literal operator described by the provided lookup results.
|
||||
ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
|
||||
DeclarationNameInfo &SuffixInfo,
|
||||
ArrayRef<Expr*> Args,
|
||||
SourceLocation LitEndLoc,
|
||||
TemplateArgumentListInfo *TemplateArgs) {
|
||||
SourceLocation UDSuffixLoc = SuffixInfo.getCXXLiteralOperatorNameLoc();
|
||||
|
||||
while (F.hasNext()) {
|
||||
FunctionDecl *D = dyn_cast<FunctionDecl>(F.next());
|
||||
// FIXME: using-decls?
|
||||
OverloadCandidateSet CandidateSet(UDSuffixLoc);
|
||||
AddFunctionCandidates(R.asUnresolvedSet(), Args, CandidateSet, true,
|
||||
TemplateArgs);
|
||||
|
||||
if (!D || D->getNumParams() != Args.size()) {
|
||||
F.erase();
|
||||
} else {
|
||||
// The literal operator's parameter types must exactly match the decayed
|
||||
// argument types.
|
||||
for (unsigned ArgIdx = 0; ArgIdx != Args.size(); ++ArgIdx) {
|
||||
QualType ArgTy = Args[ArgIdx]->getType();
|
||||
QualType ParamTy = D->getParamDecl(ArgIdx)->getType();
|
||||
if (ArgTy->isArrayType())
|
||||
ArgTy = S.Context.getArrayDecayedType(ArgTy);
|
||||
if (!S.Context.hasSameUnqualifiedType(ArgTy, ParamTy)) {
|
||||
F.erase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool HadMultipleCandidates = (CandidateSet.size() > 1);
|
||||
|
||||
// FIXME: Reject default arguments in literal operator definitions. We're not
|
||||
// supposed to treat this as ambiguous:
|
||||
//
|
||||
// int operator"" _x(const char *p);
|
||||
// int operator"" _x(const char *p, size_t n = 0);
|
||||
// int k = 123_x;
|
||||
|
||||
// Perform overload resolution. This will usually be trivial, but might need
|
||||
// to perform substitutions for a literal operator template.
|
||||
OverloadCandidateSet::iterator Best;
|
||||
switch (CandidateSet.BestViableFunction(*this, UDSuffixLoc, Best)) {
|
||||
case OR_Success:
|
||||
case OR_Deleted:
|
||||
break;
|
||||
|
||||
case OR_No_Viable_Function:
|
||||
Diag(UDSuffixLoc, diag::err_ovl_no_viable_function_in_call)
|
||||
<< R.getLookupName();
|
||||
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
|
||||
return ExprError();
|
||||
|
||||
case OR_Ambiguous:
|
||||
Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName();
|
||||
CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
F.done();
|
||||
}
|
||||
FunctionDecl *FD = Best->Function;
|
||||
MarkFunctionReferenced(UDSuffixLoc, FD);
|
||||
DiagnoseUseOfDecl(Best->FoundDecl, UDSuffixLoc);
|
||||
|
||||
/// BuildLiteralOperatorCall - A user-defined literal was found. Look up the
|
||||
/// corresponding literal operator, and build a call to it.
|
||||
/// FIXME: Support for raw literal operators and literal operator templates.
|
||||
ExprResult
|
||||
Sema::BuildLiteralOperatorCall(IdentifierInfo *UDSuffix,
|
||||
SourceLocation UDSuffixLoc,
|
||||
ArrayRef<Expr*> Args, SourceLocation LitEndLoc) {
|
||||
DeclarationName OpName =
|
||||
Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix);
|
||||
DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc);
|
||||
OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc);
|
||||
|
||||
LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName);
|
||||
LookupName(R, /*FIXME*/CurScope);
|
||||
assert(R.getResultKind() != LookupResult::Ambiguous &&
|
||||
"literal operator lookup can't be ambiguous");
|
||||
|
||||
// Filter the lookup results appropriately.
|
||||
FilterLookupForLiteralOperator(*this, R, Args);
|
||||
|
||||
// FIXME: For literal operator templates, we need to perform overload
|
||||
// resolution to deal with SFINAE.
|
||||
FunctionDecl *FD = R.getAsSingle<FunctionDecl>();
|
||||
if (!FD || FD->getNumParams() != Args.size())
|
||||
return ExprError(
|
||||
Diag(UDSuffixLoc, diag::err_ovl_no_viable_oper) << UDSuffix->getName());
|
||||
bool HadMultipleCandidates = false;
|
||||
ExprResult Fn = CreateFunctionRefExpr(*this, FD, HadMultipleCandidates,
|
||||
SuffixInfo.getLoc(),
|
||||
SuffixInfo.getInfo());
|
||||
if (Fn.isInvalid())
|
||||
return true;
|
||||
|
||||
// Check the argument types. This should almost always be a no-op, except
|
||||
// that array-to-pointer decay is applied to string literals.
|
||||
assert(Args.size() <= 2 && "too many arguments for literal operator");
|
||||
Expr *ConvArgs[2];
|
||||
for (unsigned ArgIdx = 0; ArgIdx != Args.size(); ++ArgIdx) {
|
||||
ExprResult InputInit = PerformCopyInitialization(
|
||||
@@ -10965,26 +10960,10 @@ Sema::BuildLiteralOperatorCall(IdentifierInfo *UDSuffix,
|
||||
ConvArgs[ArgIdx] = InputInit.take();
|
||||
}
|
||||
|
||||
MarkFunctionReferenced(UDSuffixLoc, FD);
|
||||
DiagnoseUseOfDecl(FD, UDSuffixLoc);
|
||||
|
||||
ExprResult Fn = CreateFunctionRefExpr(*this, FD, HadMultipleCandidates,
|
||||
OpNameInfo.getLoc(),
|
||||
OpNameInfo.getInfo());
|
||||
if (Fn.isInvalid())
|
||||
return true;
|
||||
|
||||
QualType ResultTy = FD->getResultType();
|
||||
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
|
||||
ResultTy = ResultTy.getNonLValueExprType(Context);
|
||||
|
||||
// FIXME: A literal operator call never uses default arguments.
|
||||
// But is this ambiguous?
|
||||
// void operator"" _x(const char *p);
|
||||
// void operator"" _x(const char *p, size_t n = 0);
|
||||
// 123_x
|
||||
// g++ says no, but bizarrely rejects it if the default argument is omitted.
|
||||
|
||||
UserDefinedLiteral *UDL =
|
||||
new (Context) UserDefinedLiteral(Context, Fn.take(), ConvArgs, Args.size(),
|
||||
ResultTy, VK, LitEndLoc, UDSuffixLoc);
|
||||
|
||||
16
clang/test/CXX/lex/lex.literal/lex.ext/p2.cpp
Normal file
16
clang/test/CXX/lex/lex.literal/lex.ext/p2.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
|
||||
|
||||
typedef decltype(sizeof(int)) size_t;
|
||||
|
||||
// FIXME: These diagnostics should say 'size_t' instead of 'unsigned long'
|
||||
int a = 123_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with argument of type 'unsigned long long' or 'const char *', and no matching literal operator template}}
|
||||
int b = 4.2_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with argument of type 'long double' or 'const char *', and no matching literal operator template}}
|
||||
int c = "foo"_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with arguments of types 'const char *' and 'unsigned long'}}
|
||||
int d = L"foo"_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with arguments of types 'const wchar_t *' and 'unsigned long'}}
|
||||
int e = u8"foo"_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with arguments of types 'const char *' and 'unsigned long'}}
|
||||
int f = u"foo"_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with arguments of types 'const char16_t *' and 'unsigned long'}}
|
||||
int g = U"foo"_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with arguments of types 'const char32_t *' and 'unsigned long'}}
|
||||
int h = 'y'_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with argument of type 'char'}}
|
||||
int i = L'y'_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with argument of type 'wchar_t'}}
|
||||
int j = u'y'_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with argument of type 'char16_t'}}
|
||||
int k = U'y'_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with argument of type 'char32_t'}}
|
||||
18
clang/test/CXX/lex/lex.literal/lex.ext/p3.cpp
Normal file
18
clang/test/CXX/lex/lex.literal/lex.ext/p3.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
|
||||
|
||||
int &operator "" _x1 (unsigned long long);
|
||||
int &i1 = 0x123_x1;
|
||||
|
||||
double &operator "" _x1 (const char *);
|
||||
int &i2 = 45_x1;
|
||||
|
||||
template<char...> char &operator "" _x1 ();
|
||||
int &i3 = 0377_x1;
|
||||
|
||||
int &i4 = 90000000000000000000000000000000000000000000000_x1; // expected-warning {{integer constant is too large}}
|
||||
|
||||
double &operator "" _x2 (const char *);
|
||||
double &i5 = 123123123123123123123123123123123123123123123_x2;
|
||||
|
||||
template<char...Cs> constexpr int operator "" _x3() { return sizeof...(Cs); }
|
||||
static_assert(123456789012345678901234567890123456789012345678901234567890_x3 == 60, "");
|
||||
18
clang/test/CXX/lex/lex.literal/lex.ext/p4.cpp
Normal file
18
clang/test/CXX/lex/lex.literal/lex.ext/p4.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
|
||||
|
||||
int &operator "" _x1 (long double);
|
||||
int &i1 = 0.123_x1;
|
||||
|
||||
double &operator "" _x1 (const char *);
|
||||
int &i2 = 45._x1;
|
||||
|
||||
template<char...> char &operator "" _x1 ();
|
||||
int &i3 = 0377e-1_x1;
|
||||
|
||||
int &i4 = 1e1000000_x1; // expected-warning {{too large for type 'long double'}}
|
||||
|
||||
double &operator "" _x2 (const char *);
|
||||
double &i5 = 1e1000000_x2;
|
||||
|
||||
template<char...Cs> constexpr int operator "" _x3() { return sizeof...(Cs); }
|
||||
static_assert(1e1000000_x3 == 9, "");
|
||||
13
clang/test/CXX/lex/lex.literal/lex.ext/p5.cpp
Normal file
13
clang/test/CXX/lex/lex.literal/lex.ext/p5.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
|
||||
|
||||
using size_t = decltype(sizeof(int));
|
||||
|
||||
int &operator "" _x1 (const char *);
|
||||
double &operator "" _x1 (const char *, size_t);
|
||||
double &i1 = "foo"_x1;
|
||||
double &i2 = u8"foo"_x1;
|
||||
double &i3 = L"foo"_x1; // expected-error {{no matching literal operator}}
|
||||
|
||||
char &operator "" _x1(const wchar_t *, size_t);
|
||||
char &i4 = L"foo"_x1; // ok
|
||||
double &i5 = R"(foo)"_x1; // ok
|
||||
14
clang/test/CXX/lex/lex.literal/lex.ext/p6.cpp
Normal file
14
clang/test/CXX/lex/lex.literal/lex.ext/p6.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
|
||||
|
||||
using size_t = decltype(sizeof(int));
|
||||
|
||||
int &operator "" _x1 (const char *);
|
||||
double &i1 = 'a'_x1; // expected-error {{no matching literal operator}}
|
||||
double &operator "" _x1 (wchar_t);
|
||||
double &i2 = L'a'_x1;
|
||||
double &i3 = 'a'_x1; // expected-error {{no matching literal operator}}
|
||||
double &i4 = operator"" _x1('a'); // ok
|
||||
|
||||
char &operator "" _x1(char16_t);
|
||||
char &i5 = u'a'_x1; // ok
|
||||
double &i6 = L'a'_x1; // ok
|
||||
27
clang/test/CXX/lex/lex.literal/lex.ext/p7.cpp
Normal file
27
clang/test/CXX/lex/lex.literal/lex.ext/p7.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
|
||||
|
||||
using size_t = decltype(sizeof(int));
|
||||
namespace std {
|
||||
struct string {};
|
||||
}
|
||||
|
||||
template<typename T, typename U> struct same_type;
|
||||
template<typename T> struct same_type<T, T> {};
|
||||
|
||||
namespace std_example {
|
||||
|
||||
long double operator "" _w(long double);
|
||||
std::string operator "" _w(const char16_t*, size_t);
|
||||
unsigned operator "" _w(const char*);
|
||||
int main() {
|
||||
auto v1 = 1.2_w; // calls operator "" _w(1.2L)
|
||||
auto v2 = u"one"_w; // calls operator "" _w(u"one", 3)
|
||||
auto v3 = 12_w; // calls operator "" _w("12")
|
||||
"two"_w; // expected-error {{no matching literal operator}}
|
||||
|
||||
same_type<decltype(v1), long double> test1;
|
||||
same_type<decltype(v2), std::string> test2;
|
||||
same_type<decltype(v3), unsigned> test3;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,21 +6,46 @@ S operator"" _x(const char *, size_t);
|
||||
S operator"" _y(wchar_t);
|
||||
S operator"" _z(unsigned long long);
|
||||
S operator"" _f(long double);
|
||||
S operator"" _r(const char *);
|
||||
template<char...Cs> S operator"" _t() { return S(); }
|
||||
|
||||
// CHECK: @[[s_foo:.*]] = {{.*}} constant [4 x i8] c"foo\00"
|
||||
// CHECK: @[[s_bar:.*]] = {{.*}} constant [4 x i8] c"bar\00"
|
||||
// CHECK: @[[s_123:.*]] = {{.*}} constant [4 x i8] c"123\00"
|
||||
// CHECK: @[[s_4_9:.*]] = {{.*}} constant [4 x i8] c"4.9\00"
|
||||
// CHECK: @[[s_0xffffeeee:.*]] = {{.*}} constant [11 x i8] c"0xffffeeee\00"
|
||||
|
||||
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_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @[[s_foo]], i32 0, i32 0), i64 3)
|
||||
// CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @[[s_bar]], 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
|
||||
// CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind
|
||||
// CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind
|
||||
// CHECK: call void @_ZN1SD1Ev({{.*}})
|
||||
// CHECK: call void @_ZN1SD1Ev({{.*}})
|
||||
// CHECK: call void @_ZN1SD1Ev({{.*}})
|
||||
// CHECK: call void @_ZN1SD1Ev({{.*}})
|
||||
// CHECK: call void @_ZN1SD1Ev({{.*}})
|
||||
"foo"_x, "bar"_x, L'a'_y, 42_z, 1.0_f;
|
||||
|
||||
// CHECK: call void @_Zli2_rPKc({{.*}}, i8* getelementptr inbounds ([4 x i8]* @[[s_123]], i32 0, i32 0))
|
||||
// CHECK: call void @_Zli2_rPKc({{.*}}, i8* getelementptr inbounds ([4 x i8]* @[[s_4_9]], i32 0, i32 0))
|
||||
// CHECK: call void @_Zli2_rPKc({{.*}}, i8* getelementptr inbounds ([11 x i8]* @[[s_0xffffeeee]], i32 0, i32 0))
|
||||
// CHECK: call void @_ZN1SD1Ev({{.*}})
|
||||
// CHECK: call void @_ZN1SD1Ev({{.*}})
|
||||
// CHECK: call void @_ZN1SD1Ev({{.*}})
|
||||
123_r, 4.9_r, 0xffff\
|
||||
eeee_r;
|
||||
|
||||
// FIXME: This mangling is insane. Maybe we should have a special case for
|
||||
// char parameter packs?
|
||||
// CHECK: call void @_Zli2_tIJLc48ELc120ELc49ELc50ELc51ELc52ELc53ELc54ELc55ELc56EEE1Sv({{.*}})
|
||||
// CHECK: call void @_ZN1SD1Ev({{.*}})
|
||||
0x12345678_t;
|
||||
}
|
||||
|
||||
// CHECK: define {{.*}} @_Zli2_tIJLc48ELc120ELc49ELc50ELc51ELc52ELc53ELc54ELc55ELc56EEE1Sv(
|
||||
|
||||
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); }
|
||||
|
||||
|
||||
@@ -77,21 +77,21 @@ const char *p =
|
||||
erk
|
||||
flux
|
||||
)x" "eep\x1f"\
|
||||
_no_such_suffix // expected-error {{'_no_such_suffix'}}
|
||||
_no_such_suffix // expected-error {{'operator "" _no_such_suffix'}}
|
||||
"and a bit more"
|
||||
"and another suffix"_no_such_suffix;
|
||||
|
||||
char c =
|
||||
'\x14'\
|
||||
_no_such_suffix; // expected-error {{'_no_such_suffix'}}
|
||||
_no_such_suffix; // expected-error {{'operator "" _no_such_suffix'}}
|
||||
|
||||
int &r =
|
||||
1234567\
|
||||
_no_such_suffix; // expected-error {{'_no_such_suffix'}}
|
||||
_no_such_suffix; // expected-error {{'operator "" _no_such_suffix'}}
|
||||
|
||||
int k =
|
||||
1234567.89\
|
||||
_no_such_suffix; // expected-error {{'_no_such_suffix'}}
|
||||
_no_such_suffix; // expected-error {{'operator "" _no_such_suffix'}}
|
||||
|
||||
// Make sure we handle more interesting ways of writing a string literal which
|
||||
// is "" in translation phase 7.
|
||||
|
||||
@@ -4,7 +4,7 @@ using size_t = decltype(sizeof(int));
|
||||
enum class LitKind {
|
||||
Char, WideChar, Char16, Char32,
|
||||
CharStr, WideStr, Char16Str, Char32Str,
|
||||
Integer, Floating
|
||||
Integer, Floating, Raw, Template
|
||||
};
|
||||
constexpr LitKind operator"" _kind(char p) { return LitKind::Char; }
|
||||
constexpr LitKind operator"" _kind(wchar_t p) { return LitKind::WideChar; }
|
||||
@@ -16,6 +16,8 @@ constexpr LitKind operator"" _kind(const char16_t *p, size_t n) { return LitKind
|
||||
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; }
|
||||
constexpr LitKind operator"" _kind2(const char *p) { return LitKind::Raw; }
|
||||
template<char ...Cs> constexpr LitKind operator"" _kind3() { return LitKind::Template; }
|
||||
|
||||
static_assert('x'_kind == LitKind::Char, "");
|
||||
static_assert(L'x'_kind == LitKind::WideChar, "");
|
||||
@@ -33,3 +35,94 @@ 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, "");
|
||||
static_assert(4e6_kind2 == LitKind::Raw, "");
|
||||
static_assert(4e6_kind3 == LitKind::Template, "");
|
||||
|
||||
constexpr const char *fractional_digits_impl(const char *p) {
|
||||
return *p == '.' ? p + 1 : *p ? fractional_digits_impl(p + 1) : 0;
|
||||
}
|
||||
constexpr const char *operator"" _fractional_digits(const char *p) {
|
||||
return fractional_digits_impl(p) ?: p;
|
||||
}
|
||||
constexpr bool streq(const char *p, const char *q) {
|
||||
return *p == *q && (!*p || streq(p+1, q+1));
|
||||
}
|
||||
|
||||
static_assert(streq(143.97_fractional_digits, "97"), "");
|
||||
static_assert(streq(0x786_fractional_digits, "0x786"), "");
|
||||
static_assert(streq(.4_fractional_digits, "4"), "");
|
||||
static_assert(streq(4._fractional_digits, ""), "");
|
||||
static_assert(streq(1e+97_fractional_digits, "1e+97"), "");
|
||||
static_assert(streq(0377_fractional_digits, "0377"), "");
|
||||
static_assert(streq(0377.5_fractional_digits, "5"), "");
|
||||
|
||||
int operator"" _ambiguous(char); // expected-note {{candidate}}
|
||||
namespace N {
|
||||
void *operator"" _ambiguous(char); // expected-note {{candidate}}
|
||||
}
|
||||
using namespace N;
|
||||
int k = 'x'_ambiguous; // expected-error {{ambiguous}}
|
||||
|
||||
int operator"" _deleted(unsigned long long) = delete; // expected-note {{here}}
|
||||
int m = 42_deleted; // expected-error {{attempt to use a deleted}}
|
||||
|
||||
namespace Using {
|
||||
namespace M {
|
||||
int operator"" _using(char);
|
||||
}
|
||||
int k1 = 'x'_using; // expected-error {{no matching literal operator for call to 'operator "" _using'}}
|
||||
|
||||
using M::operator "" _using;
|
||||
int k2 = 'x'_using;
|
||||
}
|
||||
|
||||
namespace AmbiguousRawTemplate {
|
||||
int operator"" _ambig1(const char *); // expected-note {{candidate}}
|
||||
template<char...> int operator"" _ambig1(); // expected-note {{candidate}}
|
||||
|
||||
int k1 = 123_ambig1; // expected-error {{call to 'operator "" _ambig1' is ambiguous}}
|
||||
|
||||
namespace Inner {
|
||||
template<char...> int operator"" _ambig2(); // expected-note 3{{candidate}}
|
||||
}
|
||||
int operator"" _ambig2(const char *); // expected-note 3{{candidate}}
|
||||
using Inner::operator"" _ambig2;
|
||||
|
||||
int k2 = 123_ambig2; // expected-error {{call to 'operator "" _ambig2' is ambiguous}}
|
||||
|
||||
namespace N {
|
||||
using Inner::operator"" _ambig2;
|
||||
|
||||
int k3 = 123_ambig2; // ok
|
||||
|
||||
using AmbiguousRawTemplate::operator"" _ambig2;
|
||||
|
||||
int k4 = 123_ambig2; // expected-error {{ambiguous}}
|
||||
|
||||
namespace M {
|
||||
|
||||
template<char...> int operator"" _ambig2();
|
||||
|
||||
int k5 = 123_ambig2; // ok
|
||||
}
|
||||
|
||||
int operator"" _ambig2(unsigned long long);
|
||||
|
||||
int k6 = 123_ambig2; // ok
|
||||
int k7 = 123._ambig2; // expected-error {{ambiguous}}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr unsigned mash(unsigned a) {
|
||||
return 0x93ae27b5 * ((a >> 13) | a << 19);
|
||||
}
|
||||
template<typename=void> constexpr unsigned hash(unsigned a) { return a; }
|
||||
template<char C, char...Cs> constexpr unsigned hash(unsigned a) {
|
||||
return hash<Cs...>(mash(a ^ mash(C)));
|
||||
}
|
||||
template<typename T, T v> struct constant { constexpr static T value = v; };
|
||||
template<char...Cs> constexpr unsigned operator"" _hash() {
|
||||
return constant<unsigned, hash<Cs...>(0)>::value;
|
||||
}
|
||||
static_assert(0x1234_hash == 0x103eff5e, "");
|
||||
static_assert(hash<'0', 'x', '1', '2', '3', '4'>(0) == 0x103eff5e, "");
|
||||
|
||||
Reference in New Issue
Block a user