aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-03-07 08:35:16 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-03-07 08:35:16 +0000
commit9fcce65e7e1307b5b8da9be13e4092d6bb94dc1d (patch)
tree2442cd0ff555a2ecf676e6f35d4df696831406d1 /lib
parentb65e24a690482e239dbd7f292bed3e87f644f8f7 (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')
-rw-r--r--lib/AST/Expr.cpp6
-rw-r--r--lib/AST/ExprCXX.cpp33
-rw-r--r--lib/AST/ExprClassification.cpp1
-rw-r--r--lib/AST/ExprConstant.cpp1
-rw-r--r--lib/AST/ItaniumMangle.cpp3
-rw-r--r--lib/AST/StmtPrinter.cpp25
-rw-r--r--lib/AST/StmtProfile.cpp4
-rw-r--r--lib/Analysis/CFG.cpp1
-rw-r--r--lib/CodeGen/CGExpr.cpp1
-rw-r--r--lib/Sema/SemaExpr.cpp25
-rw-r--r--lib/Sema/SemaOverload.cpp103
-rw-r--r--lib/Sema/TreeTransform.h6
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp9
-rw-r--r--lib/Serialization/ASTWriter.cpp1
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp3
16 files changed, 221 insertions, 7 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index e35091a101..0fdca5a33b 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1681,7 +1681,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
// Fallthrough for generic call handling.
}
case CallExprClass:
- case CXXMemberCallExprClass: {
+ case CXXMemberCallExprClass:
+ case UserDefinedLiteralClass: {
// If this is a direct call, get the callee.
const CallExpr *CE = cast<CallExpr>(this);
if (const Decl *FD = CE->getCalleeDecl()) {
@@ -2014,7 +2015,8 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
// exception-specification
case CallExprClass:
case CXXMemberCallExprClass:
- case CXXOperatorCallExprClass: {
+ case CXXOperatorCallExprClass:
+ case UserDefinedLiteralClass: {
const CallExpr *CE = cast<CallExpr>(this);
CanThrowResult CT;
if (isTypeDependent())
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index dc559f0940..039d70cfc5 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -624,6 +624,39 @@ CXXFunctionalCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
return new (Buffer) CXXFunctionalCastExpr(EmptyShell(), PathSize);
}
+UserDefinedLiteral::LiteralOperatorKind
+UserDefinedLiteral::getLiteralOperatorKind() const {
+ if (getNumArgs() == 0)
+ return LOK_Template;
+ if (getNumArgs() == 2)
+ return LOK_String;
+
+ assert(getNumArgs() == 1 && "unexpected #args in literal operator call");
+ QualType ParamTy =
+ cast<FunctionDecl>(getCalleeDecl())->getParamDecl(0)->getType();
+ if (ParamTy->isPointerType())
+ return LOK_Raw;
+ if (ParamTy->isAnyCharacterType())
+ return LOK_Character;
+ if (ParamTy->isIntegerType())
+ return LOK_Integer;
+ if (ParamTy->isFloatingType())
+ return LOK_Floating;
+
+ llvm_unreachable("unknown kind of literal operator");
+}
+
+Expr *UserDefinedLiteral::getCookedLiteral() {
+#ifndef NDEBUG
+ LiteralOperatorKind LOK = getLiteralOperatorKind();
+ assert(LOK != LOK_Template && LOK != LOK_Raw && "not a cooked literal");
+#endif
+ return getArg(0);
+}
+
+const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const {
+ return cast<FunctionDecl>(getCalleeDecl())->getLiteralIdentifier();
+}
CXXDefaultArgExpr *
CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc,
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 693e28c8a4..00160a0073 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -269,6 +269,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CallExprClass:
case Expr::CXXOperatorCallExprClass:
case Expr::CXXMemberCallExprClass:
+ case Expr::UserDefinedLiteralClass:
case Expr::CUDAKernelCallExprClass:
return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType());
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 08794f355f..947f661c2c 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -6243,6 +6243,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CXXTypeidExprClass:
case Expr::CXXUuidofExprClass:
case Expr::CXXNullPtrLiteralExprClass:
+ case Expr::UserDefinedLiteralClass:
case Expr::CXXThisExprClass:
case Expr::CXXThrowExprClass:
case Expr::CXXNewExprClass:
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index ea6e8b2e23..c4eed7c34d 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -2439,6 +2439,9 @@ recurse:
Arity);
break;
+ case Expr::UserDefinedLiteralClass:
+ // We follow g++'s approach of mangling a UDL as a call to the literal
+ // operator.
case Expr::CXXMemberCallExprClass: // fallthrough
case Expr::CallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index cd8b6bb5c2..b8e68d8574 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1222,6 +1222,31 @@ void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) {
OS << ")";
}
+void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) {
+ switch (Node->getLiteralOperatorKind()) {
+ case UserDefinedLiteral::LOK_Raw:
+ OS << cast<StringLiteral>(Node->getArg(0))->getString();
+ break;
+ case UserDefinedLiteral::LOK_Template: {
+ DeclRefExpr *DRE = cast<DeclRefExpr>(Node->getCallee());
+ assert(DRE->hasExplicitTemplateArgs());
+ const TemplateArgumentLoc *Args = DRE->getTemplateArgs();
+ for (unsigned i = 0, e = DRE->getNumTemplateArgs(); i != e; ++i) {
+ char C = (char)Args[i].getArgument().getAsIntegral()->getZExtValue();
+ OS << C;
+ }
+ break;
+ }
+ case UserDefinedLiteral::LOK_Integer:
+ case UserDefinedLiteral::LOK_Floating:
+ case UserDefinedLiteral::LOK_String:
+ case UserDefinedLiteral::LOK_Character:
+ PrintExpr(Node->getCookedLiteral());
+ break;
+ }
+ OS << Node->getUDSuffix()->getName();
+}
+
void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
OS << (Node->getValue() ? "true" : "false");
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 7935d6d44d..db27f821f5 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -738,6 +738,10 @@ void StmtProfiler::VisitCXXConstCastExpr(const CXXConstCastExpr *S) {
VisitCXXNamedCastExpr(S);
}
+void StmtProfiler::VisitUserDefinedLiteral(const UserDefinedLiteral *S) {
+ VisitCallExpr(S);
+}
+
void StmtProfiler::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->getValue());
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index b06cf44344..f50cc31e9d 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -935,6 +935,7 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass:
case Stmt::CXXMemberCallExprClass:
+ case Stmt::UserDefinedLiteralClass:
return VisitCallExpr(cast<CallExpr>(S), asc);
case Stmt::CaseStmtClass:
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 18aa0fc431..9def5543a8 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -656,6 +656,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::CallExprClass:
case Expr::CXXMemberCallExprClass:
case Expr::CXXOperatorCallExprClass:
+ case Expr::UserDefinedLiteralClass:
return EmitCallExprLValue(cast<CallExpr>(E));
case Expr::VAArgExprClass:
return EmitVAArgExprLValue(cast<VAArgExpr>(E));
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());
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 479805e7e5..a0d7e457e0 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1161,6 +1161,11 @@ void ASTStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
E->setRParenLoc(ReadSourceLocation(Record, Idx));
}
+void ASTStmtReader::VisitUserDefinedLiteral(UserDefinedLiteral *E) {
+ VisitCallExpr(E);
+ E->UDSuffixLoc = ReadSourceLocation(Record, Idx);
+}
+
void ASTStmtReader::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
VisitExpr(E);
E->setValue(Record[Idx++]);
@@ -2029,6 +2034,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
/*PathSize*/ Record[ASTStmtReader::NumExprFields]);
break;
+ case EXPR_USER_DEFINED_LITERAL:
+ S = new (Context) UserDefinedLiteral(Context, Empty);
+ break;
+
case EXPR_CXX_BOOL_LITERAL:
S = new (Context) CXXBoolLiteralExpr(Empty);
break;
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 4edfbff288..8b6859cd42 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -720,6 +720,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_CXX_REINTERPRET_CAST);
RECORD(EXPR_CXX_CONST_CAST);
RECORD(EXPR_CXX_FUNCTIONAL_CAST);
+ RECORD(EXPR_USER_DEFINED_LITERAL);
RECORD(EXPR_CXX_BOOL_LITERAL);
RECORD(EXPR_CXX_NULL_PTR_LITERAL);
RECORD(EXPR_CXX_TYPEID_EXPR);
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 76bbc850c2..a59f2b6a77 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1144,6 +1144,12 @@ void ASTStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
Code = serialization::EXPR_CXX_FUNCTIONAL_CAST;
}
+void ASTStmtWriter::VisitUserDefinedLiteral(UserDefinedLiteral *E) {
+ VisitCallExpr(E);
+ Writer.AddSourceLocation(E->UDSuffixLoc, Record);
+ Code = serialization::EXPR_USER_DEFINED_LITERAL;
+}
+
void ASTStmtWriter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
VisitExpr(E);
Record.push_back(E->getValue());
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 408bcd3528..d19cc9c7d3 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -712,7 +712,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass:
- case Stmt::CXXMemberCallExprClass: {
+ case Stmt::CXXMemberCallExprClass:
+ case Stmt::UserDefinedLiteralClass: {
Bldr.takeNodes(Pred);
VisitCallExpr(cast<CallExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);