diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 25 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 103 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 6 |
3 files changed, 130 insertions, 4 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 6b753a1342..7d99732e68 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1172,10 +1172,27 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { ArrayType::Normal, 0); // Pass &StringTokLocs[0], StringTokLocs.size() to factory! - return Owned(StringLiteral::Create(Context, Literal.GetString(), - Kind, Literal.Pascal, StrTy, - &StringTokLocs[0], - StringTokLocs.size())); + StringLiteral *Lit = StringLiteral::Create(Context, Literal.GetString(), + Kind, Literal.Pascal, StrTy, + &StringTokLocs[0], + StringTokLocs.size()); + if (Literal.getUDSuffix().empty()) + return Owned(Lit); + + // We're building a user-defined literal. + IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix()); + SourceLocation UDSuffixLoc = StringTokLocs[0]; + // FIXME: = Literal.getUDSuffixLoc(getSourceManager()); + + // C++11 [lex.ext]p5: The literal L is treated as a call of the form + // operator "" X (str, len) + QualType SizeType = Context.getSizeType(); + llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars()); + IntegerLiteral *LenArg = IntegerLiteral::Create(Context, Len, SizeType, + StringTokLocs[0]); + Expr *Args[] = { Lit, LenArg }; + return BuildLiteralOperatorCall(UDSuffix, UDSuffixLoc, Args, + StringTokLocs.back()); } ExprResult diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 91e8defcd4..14c773fdb4 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -10895,6 +10895,109 @@ 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(); + + while (F.hasNext()) { + FunctionDecl *D = dyn_cast<FunctionDecl>(F.next()); + // FIXME: using-decls? + + 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; + } + } + } + } + + F.done(); +} + +/// 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; + + // 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( + InitializedEntity::InitializeParameter(Context, FD->getParamDecl(ArgIdx)), + SourceLocation(), Args[ArgIdx]); + if (InputInit.isInvalid()) + return true; + 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); + + if (CheckCallReturnType(FD->getResultType(), UDSuffixLoc, UDL, FD)) + return ExprError(); + + if (CheckFunctionCall(FD, UDL)) + return ExprError(); + + return MaybeBindToTemporary(UDL); +} + /// FixOverloadedFunctionReference - E is an expression that refers to /// a C++ overloaded function (possibly with some parentheses and /// perhaps a '&' around it). We have resolved the overloaded function diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 0a0f5c7c32..8d4d934402 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -6088,6 +6088,12 @@ TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformUserDefinedLiteral(UserDefinedLiteral *E) { + return SemaRef.MaybeBindToTemporary(E); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) { ExprResult ControllingExpr = getDerived().TransformExpr(E->getControllingExpr()); |