From: Richard Smith Date: Fri, 9 Mar 2012 08:00:36 +0000 (+0000) Subject: Support for raw and template forms of numeric user-defined literals, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=36f5cfe4df32af6c5fe01228102512996f566f9d;p=clang Support for raw and template forms of numeric user-defined literals, and lots of tidying up. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152392 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index c649cfcf7c..103fc00b40 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -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">, diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 0f5e7670ac..a5a597bdb9 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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">; diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h index e7a6f15c0e..d35711a361 100644 --- a/include/clang/Sema/Lookup.h +++ b/include/clang/Sema/Lookup.h @@ -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); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ae4485c856..86634d128c 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1552,7 +1552,8 @@ public: void AddFunctionCandidates(const UnresolvedSetImpl &Functions, llvm::ArrayRef 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 ArgTys, + bool AllowRawAndTemplate); + void ArgumentDependentLookup(DeclarationName Name, bool Operator, SourceLocation Loc, llvm::ArrayRef Args, @@ -2545,15 +2566,16 @@ public: const DeclarationNameInfo &NameInfo, NamedDecl *D); - ExprResult BuildLiteralOperatorCall(IdentifierInfo *UDSuffix, - SourceLocation UDSuffixLoc, + ExprResult BuildLiteralOperatorCall(LookupResult &R, + DeclarationNameInfo &SuffixInfo, ArrayRef 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, diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 9e0a360fcb..0923b5fafb 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -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(QualTypeVals[I])); + if (CompareTy.isNull()) + continue; if (CompareTy == Ty) continue; // Same types QualType CompareCanTy = CompareTy.getCanonicalType(); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index e3d31e34ba..296a3f5fac 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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(); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 669b5b8ba4..c4627f1bba 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -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 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 diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 3309b84a23..cc2efd843f 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -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: diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 221cc6e53e..4d7310a146 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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 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(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 64008e1093..2adce06ce0 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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 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); + CookedTy = Context.UnsignedLongLongTy; + } + + 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(); - QualType Ty = Context.UnsignedLongLongTy; - Lit = IntegerLiteral::Create(Context, ResultVal, Ty, Tok.getLocation()); + 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(), + Tok.getLocation(), &ExplicitArgs); } - return BuildLiteralOperatorCall(UDSuffix, UDSuffixLoc, - llvm::makeArrayRef(&Lit, 1), - Tok.getLocation()); + llvm_unreachable("unexpected literal operator lookup result"); } Expr *Res; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 40774e135c..8e950ac207 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -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 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(D)) + D = USD->getTargetDecl(); + + bool IsTemplate = isa(D); + bool IsRaw = false; + bool IsExactMatch = false; + + if (FunctionDecl *FD = dyn_cast(D)) { + if (FD->getNumParams() == 1 && + FD->getParamDecl(0)->getType()->getAs()) + 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(D)) + D = USD->getTargetDecl(); + if (FunctionTemplateDecl *FunTmpl = dyn_cast(D)) + D = FunTmpl->getTemplatedDecl(); + NoteOverloadCandidate(cast(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(New->getCanonicalDecl())]; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 14c773fdb4..e74e6d5e12 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -5236,7 +5236,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, llvm::ArrayRef 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(D)) { @@ -5255,13 +5256,13 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, !cast(FunTmpl->getTemplatedDecl())->isStatic()) AddMethodTemplateCandidate(FunTmpl, F.getPair(), cast(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 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 Args, + SourceLocation LitEndLoc, + TemplateArgumentListInfo *TemplateArgs) { + SourceLocation UDSuffixLoc = SuffixInfo.getCXXLiteralOperatorNameLoc(); - while (F.hasNext()) { - FunctionDecl *D = dyn_cast(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 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(); - 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); diff --git a/test/CXX/lex/lex.literal/lex.ext/p2.cpp b/test/CXX/lex/lex.literal/lex.ext/p2.cpp new file mode 100644 index 0000000000..aa7393cffb --- /dev/null +++ b/test/CXX/lex/lex.literal/lex.ext/p2.cpp @@ -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'}} diff --git a/test/CXX/lex/lex.literal/lex.ext/p3.cpp b/test/CXX/lex/lex.literal/lex.ext/p3.cpp new file mode 100644 index 0000000000..43f3468e96 --- /dev/null +++ b/test/CXX/lex/lex.literal/lex.ext/p3.cpp @@ -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 &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 constexpr int operator "" _x3() { return sizeof...(Cs); } +static_assert(123456789012345678901234567890123456789012345678901234567890_x3 == 60, ""); diff --git a/test/CXX/lex/lex.literal/lex.ext/p4.cpp b/test/CXX/lex/lex.literal/lex.ext/p4.cpp new file mode 100644 index 0000000000..011e832c69 --- /dev/null +++ b/test/CXX/lex/lex.literal/lex.ext/p4.cpp @@ -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 &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 constexpr int operator "" _x3() { return sizeof...(Cs); } +static_assert(1e1000000_x3 == 9, ""); diff --git a/test/CXX/lex/lex.literal/lex.ext/p5.cpp b/test/CXX/lex/lex.literal/lex.ext/p5.cpp new file mode 100644 index 0000000000..4655aa17dc --- /dev/null +++ b/test/CXX/lex/lex.literal/lex.ext/p5.cpp @@ -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 diff --git a/test/CXX/lex/lex.literal/lex.ext/p6.cpp b/test/CXX/lex/lex.literal/lex.ext/p6.cpp new file mode 100644 index 0000000000..23cd7081d5 --- /dev/null +++ b/test/CXX/lex/lex.literal/lex.ext/p6.cpp @@ -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 diff --git a/test/CXX/lex/lex.literal/lex.ext/p7.cpp b/test/CXX/lex/lex.literal/lex.ext/p7.cpp new file mode 100644 index 0000000000..79c9394a96 --- /dev/null +++ b/test/CXX/lex/lex.literal/lex.ext/p7.cpp @@ -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 struct same_type; +template struct same_type {}; + +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 test1; + same_type test2; + same_type test3; +} + +} diff --git a/test/CodeGenCXX/cxx11-user-defined-literal.cpp b/test/CodeGenCXX/cxx11-user-defined-literal.cpp index 647ea57cbc..347ffe91f7 100644 --- a/test/CodeGenCXX/cxx11-user-defined-literal.cpp +++ b/test/CodeGenCXX/cxx11-user-defined-literal.cpp @@ -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 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 auto g(T t) -> decltype("foo"_x(t)) { return "foo"_x(t); } template auto i(T t) -> decltype(operator"" _x("foo", 3)(t)) { return operator"" _x("foo", 3)(t); } diff --git a/test/Parser/cxx11-user-defined-literals.cpp b/test/Parser/cxx11-user-defined-literals.cpp index 7a4df2b459..49fea01eef 100644 --- a/test/Parser/cxx11-user-defined-literals.cpp +++ b/test/Parser/cxx11-user-defined-literals.cpp @@ -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. diff --git a/test/SemaCXX/cxx11-user-defined-literals.cpp b/test/SemaCXX/cxx11-user-defined-literals.cpp index e77e80739c..4cfd4d382b 100644 --- a/test/SemaCXX/cxx11-user-defined-literals.cpp +++ b/test/SemaCXX/cxx11-user-defined-literals.cpp @@ -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 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 int operator"" _ambig1(); // expected-note {{candidate}} + + int k1 = 123_ambig1; // expected-error {{call to 'operator "" _ambig1' is ambiguous}} + + namespace Inner { + template 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 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 constexpr unsigned hash(unsigned a) { return a; } +template constexpr unsigned hash(unsigned a) { + return hash(mash(a ^ mash(C))); +} +template struct constant { constexpr static T value = v; }; +template constexpr unsigned operator"" _hash() { + return constant(0)>::value; +} +static_assert(0x1234_hash == 0x103eff5e, ""); +static_assert(hash<'0', 'x', '1', '2', '3', '4'>(0) == 0x103eff5e, "");