summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ExprCXX.h61
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h1
-rw-r--r--include/clang/Basic/StmtNodes.td1
-rw-r--r--include/clang/Sema/Sema.h5
-rw-r--r--include/clang/Serialization/ASTBitCodes.h2
-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
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p10.cpp4
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p8.cpp11
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p9.cpp4
-rw-r--r--test/CodeGenCXX/cxx11-user-defined-literal.cpp35
-rw-r--r--test/PCH/cxx11-user-defined-literals.cpp21
-rw-r--r--test/Parser/cxx11-user-defined-literals.cpp22
-rw-r--r--test/SemaCXX/cxx11-ast-print.cpp12
-rw-r--r--tools/libclang/CXCursor.cpp1
29 files changed, 385 insertions, 23 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 9631f54975..a9699f1ce8 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -324,6 +324,67 @@ public:
static bool classof(const CXXConstCastExpr *) { return true; }
};
+/// UserDefinedLiteral - A call to a literal operator (C++11 [over.literal])
+/// written as a user-defined literal (C++11 [lit.ext]).
+///
+/// Represents a user-defined literal, e.g. "foo"_bar or 1.23_xyz. While this
+/// is semantically equivalent to a normal call, this AST node provides better
+/// information about the syntactic representation of the literal.
+///
+/// Since literal operators are never found by ADL and can only be declared at
+/// namespace scope, a user-defined literal is never dependent.
+class UserDefinedLiteral : public CallExpr {
+ /// \brief The location of a ud-suffix within the literal.
+ SourceLocation UDSuffixLoc;
+
+public:
+ UserDefinedLiteral(ASTContext &C, Expr *Fn, Expr **Args, unsigned NumArgs,
+ QualType T, ExprValueKind VK, SourceLocation LitEndLoc,
+ SourceLocation SuffixLoc)
+ : CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, NumArgs, T, VK,
+ LitEndLoc), UDSuffixLoc(SuffixLoc) {}
+ explicit UserDefinedLiteral(ASTContext &C, EmptyShell Empty)
+ : CallExpr(C, UserDefinedLiteralClass, Empty) {}
+
+ /// The kind of literal operator which is invoked.
+ enum LiteralOperatorKind {
+ LOK_Raw, ///< Raw form: operator "" X (const char *)
+ LOK_Template, ///< Raw form: operator "" X<cs...> ()
+ LOK_Integer, ///< operator "" X (unsigned long long)
+ LOK_Floating, ///< operator "" X (long double)
+ LOK_String, ///< operator "" X (const CharT *, size_t)
+ LOK_Character ///< operator "" X (CharT)
+ };
+
+ /// getLiteralOperatorKind - Returns the kind of literal operator invocation
+ /// which this expression represents.
+ LiteralOperatorKind getLiteralOperatorKind() const;
+
+ /// getCookedLiteral - If this is not a raw user-defined literal, get the
+ /// underlying cooked literal (representing the literal with the suffix
+ /// removed).
+ Expr *getCookedLiteral();
+ const Expr *getCookedLiteral() const {
+ return const_cast<UserDefinedLiteral*>(this)->getCookedLiteral();
+ }
+
+ /// getUDSuffixLoc - Returns the location of a ud-suffix in the expression.
+ /// For a string literal, there may be multiple identical suffixes. This
+ /// returns the first.
+ SourceLocation getUDSuffixLoc() const { return getRParenLoc(); }
+
+ /// getUDSuffix - Returns the ud-suffix specified for this literal.
+ const IdentifierInfo *getUDSuffix() const;
+
+ static bool classof(const Stmt *S) {
+ return S->getStmtClass() == UserDefinedLiteralClass;
+ }
+ static bool classof(const UserDefinedLiteral *) { return true; }
+
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+};
+
/// CXXBoolLiteralExpr - [C++ 2.13.5] C++ Boolean Literal.
///
class CXXBoolLiteralExpr : public Expr {
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index aeb9d0508f..38a6a8515a 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -2037,6 +2037,7 @@ DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
})
DEF_TRAVERSE_STMT(CXXThisExpr, { })
DEF_TRAVERSE_STMT(CXXThrowExpr, { })
+DEF_TRAVERSE_STMT(UserDefinedLiteral, { })
DEF_TRAVERSE_STMT(DesignatedInitExpr, { })
DEF_TRAVERSE_STMT(ExtVectorElementExpr, { })
DEF_TRAVERSE_STMT(GNUNullExpr, { })
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 5018ac1901..8d2e8f53a6 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -98,6 +98,7 @@ def CXXReinterpretCastExpr : DStmt<CXXNamedCastExpr>;
def CXXConstCastExpr : DStmt<CXXNamedCastExpr>;
def CXXFunctionalCastExpr : DStmt<ExplicitCastExpr>;
def CXXTypeidExpr : DStmt<Expr>;
+def UserDefinedLiteral : DStmt<CallExpr>;
def CXXBoolLiteralExpr : DStmt<Expr>;
def CXXNullPtrLiteralExpr : DStmt<Expr>;
def CXXThisExpr : DStmt<Expr>;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index bc7ecf5edd..ae4485c856 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2545,6 +2545,11 @@ public:
const DeclarationNameInfo &NameInfo,
NamedDecl *D);
+ ExprResult BuildLiteralOperatorCall(IdentifierInfo *UDSuffix,
+ SourceLocation UDSuffixLoc,
+ ArrayRef<Expr*> Args,
+ SourceLocation LitEndLoc);
+
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
ExprResult ActOnNumericConstant(const Token &Tok);
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 0af1d3b0d1..a25851e0d5 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -1136,6 +1136,8 @@ namespace clang {
EXPR_CXX_CONST_CAST,
/// \brief A CXXFunctionalCastExpr record.
EXPR_CXX_FUNCTIONAL_CAST,
+ /// \brief A UserDefinedLiteral record.
+ EXPR_USER_DEFINED_LITERAL,
/// \brief A CXXBoolLiteralExpr record.
EXPR_CXX_BOOL_LITERAL,
EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr
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);
diff --git a/test/CXX/lex/lex.literal/lex.ext/p10.cpp b/test/CXX/lex/lex.literal/lex.ext/p10.cpp
index 7fbd9f8e4b..6652c9a890 100644
--- a/test/CXX/lex/lex.literal/lex.ext/p10.cpp
+++ b/test/CXX/lex/lex.literal/lex.ext/p10.cpp
@@ -10,6 +10,6 @@ void f() {
// FIXME: Reject these for the right reason.
123wibble; // expected-error {{suffix 'wibble'}}
123.0wibble; // expected-error {{suffix 'wibble'}}
- ""wibble; // expected-warning {{unused}}
- R"x("hello")x"wibble; // expected-warning {{unused}}
+ ""wibble;
+ R"x("hello")x"wibble;
}
diff --git a/test/CXX/lex/lex.literal/lex.ext/p8.cpp b/test/CXX/lex/lex.literal/lex.ext/p8.cpp
index 2833769d73..d9078221ff 100644
--- a/test/CXX/lex/lex.literal/lex.ext/p8.cpp
+++ b/test/CXX/lex/lex.literal/lex.ext/p8.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
-constexpr const char *operator "" _id(const char *p) { return p; }
+using size_t = decltype(sizeof(int));
+constexpr const char *operator "" _id(const char *p, size_t) { return p; }
constexpr const char *s = "foo"_id "bar" "baz"_id "quux";
constexpr bool streq(const char *p, const char *q) {
@@ -8,12 +9,10 @@ constexpr bool streq(const char *p, const char *q) {
}
static_assert(streq(s, "foobarbazquux"), "");
-constexpr const char *operator "" _trim(const char *p) {
- return *p == ' ' ? operator "" _trim(p + 1) : p;
+constexpr const char *operator "" _trim(const char *p, size_t n) {
+ return *p == ' ' ? operator "" _trim(p + 1, n - 1) : p;
}
constexpr const char *t = " " " "_trim " foo";
-// FIXME: once we implement the semantics of user-defined literals, this should
-// pass.
-static_assert(streq(s, "foo"), ""); // expected-error {{static_assert}}
+static_assert(streq(t, "foo"), "");
const char *u = "foo" "bar"_id "baz" "quux"_di "corge"; // expected-error {{differing user-defined suffixes ('_id' and '_di') in string literal concatenation}}
diff --git a/test/CXX/lex/lex.literal/lex.ext/p9.cpp b/test/CXX/lex/lex.literal/lex.ext/p9.cpp
index e3de34df9e..65e27b41b0 100644
--- a/test/CXX/lex/lex.literal/lex.ext/p9.cpp
+++ b/test/CXX/lex/lex.literal/lex.ext/p9.cpp
@@ -6,9 +6,7 @@ void operator "" _x(const wchar_t *, size_t);
namespace std_example {
int main() {
- // FIXME: once we implement the semantics of literal operators, this warning
- // should vanish.
- L"A" "B" "C"_x; // expected-warning {{expression result unused}}
+ L"A" "B" "C"_x;
"P"_x "Q" "R"_y; // expected-error {{differing user-defined suffixes ('_x' and '_y') in string literal concatenation}}
}
diff --git a/test/CodeGenCXX/cxx11-user-defined-literal.cpp b/test/CodeGenCXX/cxx11-user-defined-literal.cpp
new file mode 100644
index 0000000000..fbd3621014
--- /dev/null
+++ b/test/CodeGenCXX/cxx11-user-defined-literal.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+struct S { S(); ~S(); S(const S &); void operator()(int); };
+using size_t = decltype(sizeof(int));
+S operator"" _x(const char *, size_t);
+
+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 @_ZN1SD1Ev({{.*}}) nounwind
+ // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind
+ "foo"_x, "bar"_x;
+}
+
+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); }
+
+void h() {
+ g(42);
+ i(42);
+}
+
+// CHECK: define {{.*}} @_Z1hv()
+// CHECK: call void @_Z1gIiEDTclclL_Zli2_xPKcmELA4_S0_ELm3EEfp_EET_(i32 42)
+// CHECK: call void @_Z1iIiEDTclclL_Zli2_xPKcmELA4_S0_ELi3EEfp_EET_(i32 42)
+
+// CHECK: define {{.*}} @_Z1gIiEDTclclL_Zli2_xPKcmELA4_S0_ELm3EEfp_EET_(i32
+// CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @{{.*}}, i32 0, i32 0), i64 3)
+// CHECK: call void @_ZN1SclEi
+// CHECK: call void @_ZN1SD1Ev
+
+// CHECK: define {{.*}} @_Z1iIiEDTclclL_Zli2_xPKcmELA4_S0_ELi3EEfp_EET_(i32
+// CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @{{.*}}, i32 0, i32 0), i64 3)
+// CHECK: call void @_ZN1SclEi
+// CHECK: call void @_ZN1SD1Ev
diff --git a/test/PCH/cxx11-user-defined-literals.cpp b/test/PCH/cxx11-user-defined-literals.cpp
new file mode 100644
index 0000000000..4a7c24b994
--- /dev/null
+++ b/test/PCH/cxx11-user-defined-literals.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+
+using size_t = decltype(sizeof(int));
+int operator"" _foo(const char *p, size_t);
+
+template<typename T> auto f(T t) -> decltype(t + ""_foo) { return 0; } // expected-note {{substitution failure}}
+
+#else
+
+int j = ""_foo;
+int k = f(0);
+int *l = f(&k);
+struct S {};
+int m = f(S()); // expected-error {{no matching}}
+
+#endif
diff --git a/test/Parser/cxx11-user-defined-literals.cpp b/test/Parser/cxx11-user-defined-literals.cpp
index c2d5af5c1d..e3f79ecc7c 100644
--- a/test/Parser/cxx11-user-defined-literals.cpp
+++ b/test/Parser/cxx11-user-defined-literals.cpp
@@ -44,11 +44,11 @@ constexpr const char16_t operator"" _id(const char16_t *p, size_t n) { return *p
constexpr const char32_t operator"" _id(const char32_t *p, size_t n) { return *p; }
template<int n> struct S {};
-S<"a"_id[0]> sa;
-S<L"b"_id[0]> sb;
-S<u8"c"_id[0]> sc;
-S<u"d"_id[0]> sd;
-S<U"e"_id[0]> se;
+S<"a"_id> sa;
+S<L"b"_id> sb;
+S<u8"c"_id> sc;
+S<u"d"_id> sd;
+S<U"e"_id> se;
S<'w'_id> sw;
S<L'x'_id> sx;
@@ -58,3 +58,15 @@ S<U'z'_id> sz;
void h() {
(void)"test"_id "test" L"test";
}
+
+enum class LitKind { CharStr, WideStr, Char16Str, Char32Str };
+constexpr LitKind operator"" _kind(const char *p, size_t n) { return LitKind::CharStr; }
+constexpr LitKind operator"" _kind(const wchar_t *p, size_t n) { return LitKind::WideStr; }
+constexpr LitKind operator"" _kind(const char16_t *p, size_t n) { return LitKind::Char16Str; }
+constexpr LitKind operator"" _kind(const char32_t *p, size_t n) { return LitKind::Char32Str; }
+
+static_assert("foo"_kind == LitKind::CharStr, "");
+static_assert(u8"foo"_kind == LitKind::CharStr, "");
+static_assert(L"foo"_kind == LitKind::WideStr, "");
+static_assert(u"foo"_kind == LitKind::Char16Str, "");
+static_assert(U"foo"_kind == LitKind::Char32Str, "");
diff --git a/test/SemaCXX/cxx11-ast-print.cpp b/test/SemaCXX/cxx11-ast-print.cpp
new file mode 100644
index 0000000000..1f6f947812
--- /dev/null
+++ b/test/SemaCXX/cxx11-ast-print.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++11 -ast-print %s | FileCheck %s
+
+// FIXME: Print the trailing-return-type properly.
+// CHECK: decltype(nullptr) operator "" _foo(const char *p, decltype(sizeof(int)));
+auto operator"" _foo(const char *p, decltype(sizeof(int))) -> decltype(nullptr);
+
+// CHECK: const char *p1 = "bar1"_foo;
+const char *p1 = "bar1"_foo;
+// CHECK: const char *p2 = "bar2"_foo;
+const char *p2 = R"x(bar2)x"_foo;
+// CHECK: const char *p3 = u8"bar3"_foo;
+const char *p3 = u8"bar3"_foo;
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 77b6ba2760..ac8cf28880 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -446,6 +446,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::CXXConstructExprClass:
case Stmt::CXXTemporaryObjectExprClass:
case Stmt::CXXUnresolvedConstructExprClass:
+ case Stmt::UserDefinedLiteralClass:
K = CXCursor_CallExpr;
break;