]> granicus.if.org Git - clang/commitdiff
AST representation for user-defined literals, plus just enough of semantic
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 7 Mar 2012 08:35:16 +0000 (08:35 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 7 Mar 2012 08:35:16 +0000 (08:35 +0000)
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

29 files changed:
include/clang/AST/ExprCXX.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Basic/StmtNodes.td
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/Expr.cpp
lib/AST/ExprCXX.cpp
lib/AST/ExprClassification.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/Analysis/CFG.cpp
lib/CodeGen/CGExpr.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/CXX/lex/lex.literal/lex.ext/p10.cpp
test/CXX/lex/lex.literal/lex.ext/p8.cpp
test/CXX/lex/lex.literal/lex.ext/p9.cpp
test/CodeGenCXX/cxx11-user-defined-literal.cpp [new file with mode: 0644]
test/PCH/cxx11-user-defined-literals.cpp [new file with mode: 0644]
test/Parser/cxx11-user-defined-literals.cpp
test/SemaCXX/cxx11-ast-print.cpp [new file with mode: 0644]
tools/libclang/CXCursor.cpp

index 9631f54975c235e4cf487c50567eadfd5e87d035..a9699f1ce8536daa50269c08acdb46806898c4d7 100644 (file)
@@ -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 {
index aeb9d0508fa1689a75b001983be11a673250c194..38a6a8515abee20e4e7950c45a73ced2e4fad94b 100644 (file)
@@ -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, { })
index 5018ac1901051dff45f03fa2f595925470fbbd00..8d2e8f53a6fe38f481485cf8b96e4c9ad1e1487c 100644 (file)
@@ -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>;
index bc7ecf5eddb63383d9cfe159f13e41dec2687e09..ae4485c85678354b6d76eeab85620e2aa62536d8 100644 (file)
@@ -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);
index 0af1d3b0d17054c4217459fc5ab9cc6189a0d6ef..a25851e0d583fdd019fe07c3632a2977bfaa2838 100644 (file)
@@ -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
index e35091a101736ae2ff0bb89eba417c4a2a8acbd3..0fdca5a33b10b8ad0575e0c69d4948822069d464 100644 (file)
@@ -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())
index dc559f0940fcf752399356edefa92db36619a15a..039d70cfc56eb62a8058ce94e375bc9ee8213c56 100644 (file)
@@ -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, 
index 693e28c8a45fa8ca7b0a47e88eec013e1b01e4d4..00160a007379bd6f3df5cc362b57c19f30f249dc 100644 (file)
@@ -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());
 
index 08794f355f73341767efc0f0807bb1e6aca40d47..947f661c2ca00f7baadda4bad90feb1e40c75316 100644 (file)
@@ -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:
index ea6e8b2e23cd2674b2c8480af8d30e1bd37db639..c4eed7c34d625271cde42cc941dd5fec4de0fdc7 100644 (file)
@@ -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);
index cd8b6bb5c2310efc99baa7149746d14b6de23105..b8e68d8574a74f4978e67e20006d47275a3bd43a 100644 (file)
@@ -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");
 }
index 7935d6d44d1a82ec60dc3623aba3e57d2fc1e65d..db27f821f5b23815654debc0ff3514f53667578c 100644 (file)
@@ -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());
index b06cf443442fffd802cc195b6a8f7db0b2cc967e..f50cc31e9d8b6ea8b9756416bb5ad28f92b89ed4 100644 (file)
@@ -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:
index 18aa0fc4317edc80e502aa47ee1cc1d1facf3966..9def5543a8460ece44023e89c07411ca35757f26 100644 (file)
@@ -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));
index 6b753a13421734dce59111ac0d41a8d8f677d872..7d99732e682bf40aaa57140c7ef1a9f8767cff07 100644 (file)
@@ -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
index 91e8defcd45f4def0126237ff4131d89180822bd..14c773fdb4fe31df09014171a6e8ee1a34426fc2 100644 (file)
@@ -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
index 0a0f5c7c3284e194f07f4af76f0b940b2267e8fe..8d4d934402b479e75cf8366220c358b9c1706c62 100644 (file)
@@ -6086,6 +6086,12 @@ TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) {
   return SemaRef.Owned(E);
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformUserDefinedLiteral(UserDefinedLiteral *E) {
+  return SemaRef.MaybeBindToTemporary(E);
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
index 479805e7e53716b1172d5ba9af7512c55b114ff2..a0d7e457e0c52c6b930ecdc330b5d44b1ccc5b6e 100644 (file)
@@ -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;
index 4edfbff28880587d285c4d10db5e1cb62f3c576d..8b6859cd427816773c9feb980afec3776f34be79 100644 (file)
@@ -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);
index 76bbc850c21de78c11f4191b1dff248a00380f54..a59f2b6a7781788c495db48e541356e0588053f4 100644 (file)
@@ -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());
index 408bcd352865510b160ffb418979e3ab5257e91d..d19cc9c7d3d38af46fd42d37a3fa0b5b7d0f45e7 100644 (file)
@@ -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);
index 7fbd9f8e4be636ff9122253f872e45badc370c73..6652c9a890f1cc8fc75f0780e1fa77e4b84c930c 100644 (file)
@@ -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;
 }
index 2833769d73aaaa6168dd1a25ed235ab8684dbff0..d9078221ff5e3a82bd5daa35a65e4d7f21f44666 100644 (file)
@@ -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}}
index e3de34df9e9c175bea176587d49937cce3f8d449..65e27b41b066804af7e6bdfb7d4bcfb8ce64feb6 100644 (file)
@@ -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 (file)
index 0000000..fbd3621
--- /dev/null
@@ -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 (file)
index 0000000..4a7c24b
--- /dev/null
@@ -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
index c2d5af5c1deadfc02f2d5e7b29e95d058090c026..e3f79ecc7cc2127ab07bd5197db5ae1312b98820 100644 (file)
@@ -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 (file)
index 0000000..1f6f947
--- /dev/null
@@ -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;
index 77b6ba276071ccf893b44f83dda51d49db054ec4..ac8cf28880353e365763e1c2ff1f48fc80818852 100644 (file)
@@ -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;