diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-03-07 08:35:16 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-03-07 08:35:16 +0000 |
commit | 9fcce65e7e1307b5b8da9be13e4092d6bb94dc1d (patch) | |
tree | 2442cd0ff555a2ecf676e6f35d4df696831406d1 /lib/Sema/SemaOverload.cpp | |
parent | b65e24a690482e239dbd7f292bed3e87f644f8f7 (diff) |
AST representation for user-defined literals, plus just enough of semantic
analysis to make the AST representation testable. They are represented by a
new UserDefinedLiteral AST node, which is a sugared CallExpr. All semantic
properties, including full CodeGen support, are achieved for free by this
representation.
UserDefinedLiterals can never be dependent, so no custom instantiation
behavior is required. They are mangled as if they were direct calls to the
underlying literal operator. This matches g++'s apparent behavior (but not its
actual mangling, which is broken for literal-operator-ids).
User-defined *string* literals are now fully-operational, but the semantic
analysis is quite hacky and needs more work. No other forms of user-defined
literal are created yet, but the AST support for them is present.
This patch committed after midnight because we had already hit the quota for
new kinds of literal yesterday.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152211 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 103 |
1 files changed, 103 insertions, 0 deletions
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 |