]> granicus.if.org Git - clang/commitdiff
t/clang/expr-traits
authorJohn Wiegley <johnw@boostpro.com>
Mon, 25 Apr 2011 06:54:41 +0000 (06:54 +0000)
committerJohn Wiegley <johnw@boostpro.com>
Mon, 25 Apr 2011 06:54:41 +0000 (06:54 +0000)
Patch authored by David Abrahams.

These two expression traits (__is_lvalue_expr, __is_rvalue_expr) are used for
parsing code that employs certain features of the Embarcadero C++ compiler.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130122 91177308-0d34-0410-b5e6-96231b3b80d8

25 files changed:
include/clang/AST/EvaluatedExprVisitor.h
include/clang/AST/ExprCXX.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Basic/ExpressionTraits.h [new file with mode: 0644]
include/clang/Basic/StmtNodes.td
include/clang/Basic/TokenKinds.def
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/ExprClassification.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/CodeGen/CGExprScalar.cpp
lib/Parse/ParseExpr.cpp
lib/Parse/ParseExprCXX.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/SemaCXX/expression-traits.cpp [new file with mode: 0644]
tools/libclang/CIndex.cpp
tools/libclang/CXCursor.cpp

index 3bc62eda2d0626dcdb936c015b6a6986b7c5ad59..bab1606dcee43716cedfc598130701ea390321b8 100644 (file)
@@ -38,6 +38,7 @@ public:
   void VisitDeclRefExpr(DeclRefExpr *E) { }
   void VisitOffsetOfExpr(OffsetOfExpr *E) { }
   void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { }
+  void VisitExpressionTraitExpr(ExpressionTraitExpr *E) { }
   void VisitBlockExpr(BlockExpr *E) { }
   void VisitCXXUuidofExpr(CXXUuidofExpr *E) { }  
   void VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { }
index ed4661b3a4ffef970bf459257572d54ed0bfeb8e..5aaeb8e7ab7ffc65dc39096a1c6ee0bac1cad20a 100644 (file)
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_AST_EXPRCXX_H
 
 #include "clang/Basic/TypeTraits.h"
+#include "clang/Basic/ExpressionTraits.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/UnresolvedSet.h"
 #include "clang/AST/TemplateBase.h"
@@ -1593,6 +1594,58 @@ public:
   friend class ASTStmtReader;
 };
 
+/// ExpressionTraitExpr - An expression trait intrinsic
+/// Example:
+/// __is_lvalue_expr(std::cout) == true
+/// __is_lvalue_expr(1) == false
+class ExpressionTraitExpr : public Expr {
+  /// ET - The trait. A ExpressionTrait enum in MSVC compat unsigned.
+  unsigned ET : 31;
+  /// The value of the type trait. Unspecified if dependent.
+  bool Value : 1;
+
+  /// Loc - The location of the type trait keyword.
+  SourceLocation Loc;
+
+  /// RParen - The location of the closing paren.
+  SourceLocation RParen;
+
+  Expr* QueriedExpression;
+public:
+  ExpressionTraitExpr(SourceLocation loc, ExpressionTrait et, 
+                     Expr *queried, bool value,
+                     SourceLocation rparen, QualType resultType)
+    : Expr(ExpressionTraitExprClass, resultType, VK_RValue, OK_Ordinary,
+           false, // Not type-dependent
+           // Value-dependent if the argument is type-dependent.
+           queried->isTypeDependent(),
+           queried->containsUnexpandedParameterPack()),
+      ET(et), Value(value), Loc(loc), RParen(rparen), QueriedExpression(queried) { }
+
+  explicit ExpressionTraitExpr(EmptyShell Empty)
+    : Expr(ExpressionTraitExprClass, Empty), ET(0), Value(false),
+      QueriedExpression() { }
+
+  SourceRange getSourceRange() const { return SourceRange(Loc, RParen);}
+
+  ExpressionTrait getTrait() const { return static_cast<ExpressionTrait>(ET); }
+
+  Expr *getQueriedExpression() const { return QueriedExpression; }
+
+  bool getValue() const { return Value; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == ExpressionTraitExprClass;
+  }
+  static bool classof(const ExpressionTraitExpr *) { return true; }
+
+  // Iterators
+  child_range children() { return child_range(); }
+
+  friend class ASTStmtReader;
+};
+
+
 /// \brief A reference to an overloaded function set, either an
 /// \t UnresolvedLookupExpr or an \t UnresolvedMemberExpr.
 class OverloadExpr : public Expr {
index 0b3993d88e77c68da4a8b58b79b50ed05dab0c5b..93cc446afd1b180c65427c581f1c78dc28141231 100644 (file)
@@ -1849,6 +1849,10 @@ DEF_TRAVERSE_STMT(BinaryTypeTraitExpr, {
     TRY_TO(TraverseTypeLoc(S->getRhsTypeSourceInfo()->getTypeLoc()));
   })
 
+DEF_TRAVERSE_STMT(ExpressionTraitExpr, {
+    TRY_TO(TraverseStmt(S->getQueriedExpression()));
+  })
+
 DEF_TRAVERSE_STMT(VAArgExpr, {
     // The child-iterator will pick up the expression argument.
     TRY_TO(TraverseTypeLoc(S->getWrittenTypeInfo()->getTypeLoc()));
diff --git a/include/clang/Basic/ExpressionTraits.h b/include/clang/Basic/ExpressionTraits.h
new file mode 100644 (file)
index 0000000..403a59a
--- /dev/null
@@ -0,0 +1,25 @@
+//===--- ExpressionTraits.h - C++ Expression Traits Support Enumerations ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines enumerations for expression traits intrinsics.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_EXPRESSIONTRAITS_H
+#define LLVM_CLANG_EXPRESSIONTRAITS_H
+
+namespace clang {
+
+  enum ExpressionTrait {
+    ET_IsLValueExpr,
+    ET_IsRValueExpr
+  };
+}
+
+#endif
index eaf4b8598466d50484b1f0c56f2ef0402e3e1194..de3fedb724e88817910d0651c07b7216d71b5c08 100644 (file)
@@ -104,6 +104,7 @@ def CXXDeleteExpr : DStmt<Expr>;
 def CXXPseudoDestructorExpr : DStmt<Expr>;
 def UnaryTypeTraitExpr : DStmt<Expr>;
 def BinaryTypeTraitExpr : DStmt<Expr>;
+def ExpressionTraitExpr : DStmt<Expr>;
 def DependentScopeDeclRefExpr : DStmt<Expr>;
 def CXXConstructExpr : DStmt<Expr>;
 def CXXBindTemporaryExpr : DStmt<Expr>;
index ac8e694337e4e27b35d09397fd2a98bbf8ed1c91..98487397ca30f229e7dec3a5cef18766d3f6e0e7 100644 (file)
@@ -346,6 +346,10 @@ KEYWORD(__is_polymorphic            , KEYCXX)
 KEYWORD(__is_trivial                , KEYCXX)
 KEYWORD(__is_union                  , KEYCXX)
 
+// Embarcadero Expression Traits
+KEYWORD(__is_lvalue_expr            , KEYCXX)
+KEYWORD(__is_rvalue_expr            , KEYCXX)
+
 // Apple Extension.
 KEYWORD(__private_extern__          , KEYALL)
 
index 1c0d63b026271848bf378f85ab20f9a0049a47ea..de4904a9a9812d56ae93af3eee9004f103b64edf 100644 (file)
@@ -1802,6 +1802,10 @@ private:
   ExprResult ParseUnaryTypeTrait();
   ExprResult ParseBinaryTypeTrait();
 
+  //===--------------------------------------------------------------------===//
+  // Embarcadero: Expression Traits
+  ExprResult ParseExpressionTrait();
+
   //===--------------------------------------------------------------------===//
   // Preprocessor code-completion pass-through
   virtual void CodeCompleteDirective(bool InConditional);
index 85f36b3d621f4d841b555c1cd634fb7688579310..6c08712fe715c87dec66087aba5396571d557f31 100644 (file)
@@ -27,6 +27,7 @@
 #include "clang/Basic/Specifiers.h"
 #include "clang/Basic/TemplateKinds.h"
 #include "clang/Basic/TypeTraits.h"
+#include "clang/Basic/ExpressionTraits.h"
 #include "llvm/ADT/OwningPtr.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
@@ -2732,6 +2733,18 @@ public:
                                   TypeSourceInfo *RhsT,
                                   SourceLocation RParen);
 
+  /// ActOnExpressionTrait - Parsed one of the unary type trait support
+  /// pseudo-functions.
+  ExprResult ActOnExpressionTrait(ExpressionTrait OET,
+                                  SourceLocation KWLoc,
+                                  Expr *Queried,
+                                  SourceLocation RParen);
+
+  ExprResult BuildExpressionTrait(ExpressionTrait OET,
+                                  SourceLocation KWLoc,
+                                  Expr *Queried,
+                                  SourceLocation RParen);
+
   ExprResult ActOnStartCXXMemberReference(Scope *S,
                                           Expr *Base,
                                           SourceLocation OpLoc,
index 4df6a29c1be6bfb9b5d41c61ce27cbe61aaa3b1b..72252d4da80d2b044c8eb40bbdc4db830d162e0a 100644 (file)
@@ -970,6 +970,7 @@ namespace clang {
       EXPR_CXX_UNRESOLVED_LOOKUP,        // UnresolvedLookupExpr
 
       EXPR_CXX_UNARY_TYPE_TRAIT,  // UnaryTypeTraitExpr
+      EXPR_CXX_EXPRESSION_TRAIT,  // ExpressionTraitExpr
       EXPR_CXX_NOEXCEPT,          // CXXNoexceptExpr
 
       EXPR_OPAQUE_VALUE,          // OpaqueValueExpr
index 0d018804143e2bb925a4730e62502cb566120bf9..ebbdf94f100aa3b4ab4df8865c5a65b3d7b19eb5 100644 (file)
@@ -152,6 +152,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
   case Expr::CXXScalarValueInitExprClass:
   case Expr::UnaryTypeTraitExprClass:
   case Expr::BinaryTypeTraitExprClass:
+  case Expr::ExpressionTraitExprClass:
   case Expr::ObjCSelectorExprClass:
   case Expr::ObjCProtocolExprClass:
   case Expr::ObjCStringLiteralClass:
index e738f0dc908c75c61c9ddb51644cf36c30a80209..519bbaa115ecd70f3e277d523d1a4b1632c8150c 100644 (file)
@@ -1061,6 +1061,10 @@ public:
     return Success(E->getValue(), E);
   }
 
+  bool VisitExpressionTraitExpr(const ExpressionTraitExpr *E) {
+    return Success(E->getValue(), E);
+  }
+
   bool VisitChooseExpr(const ChooseExpr *E) {
     return Visit(E->getChosenSubExpr(Info.Ctx));
   }
@@ -2875,6 +2879,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
   case Expr::CXXScalarValueInitExprClass:
   case Expr::UnaryTypeTraitExprClass:
   case Expr::BinaryTypeTraitExprClass:
+  case Expr::ExpressionTraitExprClass:
   case Expr::CXXNoexceptExprClass:
     return NoDiag();
   case Expr::CallExprClass:
index a32b0ef7512eed2f719c46dc5f3e7a6144c2b045..b62442d6d2a8093b92c382ff08cc0af53be0fb55 100644 (file)
@@ -1910,6 +1910,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
   case Expr::StmtExprClass:
   case Expr::UnaryTypeTraitExprClass:
   case Expr::BinaryTypeTraitExprClass:
+  case Expr::ExpressionTraitExprClass:
   case Expr::VAArgExprClass:
   case Expr::CXXUuidofExprClass:
   case Expr::CXXNoexceptExprClass:
index 3591c32ad828fb11f65484b3e35797338c84a7b7..cf42e633791dde23117550ab743ff54ea5c5b272 100644 (file)
@@ -1281,6 +1281,15 @@ static const char *getTypeTraitName(BinaryTypeTrait BTT) {
   return "";
 }
 
+static const char *getExpressionTraitName(ExpressionTrait ET) {
+  switch (ET) {
+  default: llvm_unreachable("Unknown expression trait");
+  case ET_IsLValueExpr:      return "__is_lvalue_expr";
+  case ET_IsRValueExpr:      return "__is_rvalue_expr";
+  }
+  return "";
+}
+
 void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
   OS << getTypeTraitName(E->getTrait()) << "("
      << E->getQueriedType().getAsString(Policy) << ")";
@@ -1292,6 +1301,12 @@ void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
      << E->getRhsType().getAsString(Policy) << ")";
 }
 
+void StmtPrinter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+    OS << getExpressionTraitName(E->getTrait()) << "(";
+    PrintExpr(E->getQueriedExpression());
+    OS << ")";
+}
+
 void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
   OS << "noexcept(";
   PrintExpr(E->getOperand());
index dbcb7e4fe60c5fd6670dfed6107d7d7563d89b6e..fe9a10b01e0fff021c8b3162487e49a5156ac0a3 100644 (file)
@@ -802,6 +802,12 @@ void StmtProfiler::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *S) {
   VisitType(S->getRhsType());
 }
 
+void StmtProfiler::VisitExpressionTraitExpr(ExpressionTraitExpr *S) {
+  VisitExpr(S);
+  ID.AddInteger(S->getTrait());
+  VisitExpr(S->getQueriedExpression());
+}
+
 void
 StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
   VisitExpr(S);
index 6c5556d4f18a71c1ea2a73f5049a9c1bc7736c1b..f6de1fa1273e08806e9447dfbf322a39e3cd90cc 100644 (file)
@@ -367,6 +367,10 @@ public:
     return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
   }
 
+  Value *VisitExpressionTraitExpr(const ExpressionTraitExpr *E) {
+    return llvm::ConstantInt::get(Builder.getInt1Ty(), E->getValue());
+  }
+
   Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) {
     // C++ [expr.pseudo]p1:
     //   The result shall only be used as the operand for the function call
index cd8f9c53f75b7319eaf633d7150a44bc7d19038b..12761e8d9f842d9ac236fd2bc0329c1f83b68a45 100644 (file)
@@ -555,6 +555,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
 /// [GNU]             '__is_base_of'       
 /// [MS]              '__is_convertible_to'
 ///
+/// [Embarcadero] expression-trait:
+///                   '__is_lvalue_expr'
+///                   '__is_rvalue_expr'
+///
 ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
                                        bool isAddressOfOperand,
                                        bool &NotCastExpr,
@@ -1021,6 +1025,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
   case tok::kw___is_convertible_to:
     return ParseBinaryTypeTrait();
 
+  case tok::kw___is_lvalue_expr:
+  case tok::kw___is_rvalue_expr:
+    return ParseExpressionTrait();
+      
   case tok::at: {
     SourceLocation AtLoc = ConsumeToken();
     return ParseObjCAtExpression(AtLoc);
index 1165ff0978f718f61ad779b2dfb836ab208f2459..e6abac3b4ce04e2acb4b265235d283b556b34d2d 100644 (file)
@@ -1944,6 +1944,14 @@ static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) {
   }
 }
 
+static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) {
+  switch(kind) {
+  default: assert(false && "Not a known unary expression trait.");
+  case tok::kw___is_lvalue_expr:             return ET_IsLValueExpr;
+  case tok::kw___is_rvalue_expr:             return ET_IsRValueExpr;
+  }
+}
+
 /// ParseUnaryTypeTrait - Parse the built-in unary type-trait
 /// pseudo-functions that allow implementation of the TR1/C++0x type traits
 /// templates.
@@ -2009,6 +2017,28 @@ ExprResult Parser::ParseBinaryTypeTrait() {
   return Actions.ActOnBinaryTypeTrait(BTT, Loc, LhsTy.get(), RhsTy.get(), RParen);
 }
 
+/// ParseExpressionTrait - Parse built-in expression-trait
+/// pseudo-functions like __is_lvalue_expr( xxx ).
+///
+///       primary-expression:
+/// [Embarcadero]     expression-trait '(' expression ')'
+///
+ExprResult Parser::ParseExpressionTrait() {
+  ExpressionTrait ET = ExpressionTraitFromTokKind(Tok.getKind());
+  SourceLocation Loc = ConsumeToken();
+
+  SourceLocation LParen = Tok.getLocation();
+  if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+    return ExprError();
+
+  ExprResult Expr = ParseExpression();
+
+  SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
+
+  return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(), RParen);
+}
+
+
 /// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a
 /// parenthesized ambiguous type-id. This uses tentative parsing to disambiguate
 /// based on the context past the parens.
index 27545d802e43920c6d39f2ec1f9352b4e8464d6f..edfa4a532dfc01383e9d05b3ace971f4447cbf3a 100644 (file)
@@ -2739,6 +2739,45 @@ ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT,
                                                  ResultType));
 }
 
+ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET,
+                                     SourceLocation KWLoc,
+                                     Expr* Queried,
+                                     SourceLocation RParen) {
+  // If error parsing the expression, ignore.
+  if (!Queried)
+      return ExprError();
+
+  ExprResult Result
+    = BuildExpressionTrait(ET, KWLoc, Queried, RParen);
+
+  return move(Result);
+}
+
+ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET,
+                                     SourceLocation KWLoc,
+                                     Expr* Queried,
+                                     SourceLocation RParen) {
+  if (Queried->isTypeDependent()) {
+    // Delay type-checking for type-dependent expressions.
+  } else if (Queried->getType()->isPlaceholderType()) {
+    ExprResult PE = CheckPlaceholderExpr(Queried);
+    if (PE.isInvalid()) return ExprError();
+    return BuildExpressionTrait(ET, KWLoc, PE.take(), RParen);
+  }
+
+  bool Value = false;
+  switch (ET) {
+  default: llvm_unreachable("Unknown or unimplemented expression trait");
+  case ET_IsLValueExpr:       Value = Queried->isLValue(); break;
+  case ET_IsRValueExpr:       Value = Queried->isRValue(); break;
+  }
+  
+  // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
+  return Owned(
+      new (Context) ExpressionTraitExpr(
+          KWLoc, ET, Queried, Value, RParen, Context.BoolTy));
+}
+
 QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex,
                                             ExprValueKind &VK,
                                             SourceLocation Loc,
index dc96e59420b3b77e8504071b36db02899e3c4d81..c642e642cc83aa04707da8a164101f3940460900 100644 (file)
@@ -1915,6 +1915,17 @@ public:
     return getSema().BuildBinaryTypeTrait(Trait, StartLoc, LhsT, RhsT, RParenLoc);
   }
 
+  /// \brief Build a new expression trait expression.
+  ///
+  /// By default, performs semantic analysis to build the new expression.
+  /// Subclasses may override this routine to provide different behavior.
+  ExprResult RebuildExpressionTrait(ExpressionTrait Trait,
+                                   SourceLocation StartLoc,
+                                   Expr *Queried,
+                                   SourceLocation RParenLoc) {
+    return getSema().BuildExpressionTrait(Trait, StartLoc, Queried, RParenLoc);
+  }
+
   /// \brief Build a new (previously unresolved) declaration reference
   /// expression.
   ///
@@ -6909,6 +6920,24 @@ TreeTransform<Derived>::TransformBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
                                             E->getLocEnd());
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformExpressionTraitExpr(ExpressionTraitExpr *E) {
+  ExprResult SubExpr;
+  {
+    EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+    SubExpr = getDerived().TransformExpr(E->getQueriedExpression());
+    if (SubExpr.isInvalid())
+      return ExprError();
+
+    if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getQueriedExpression())
+      return SemaRef.Owned(E);
+  }
+
+  return getDerived().RebuildExpressionTrait(
+      E->getTrait(), E->getLocStart(), SubExpr.get(), E->getLocEnd());
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
index 07c5c7b804771a4e72908ef27168915d5472a2e1..608aafc3ce4875de8d39b4b49e9c7747da6b8010 100644 (file)
@@ -179,6 +179,7 @@ namespace clang {
 
     void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
     void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
+    void VisitExpressionTraitExpr(ExpressionTraitExpr *E);
     void VisitCXXNoexceptExpr(CXXNoexceptExpr *E);
     void VisitPackExpansionExpr(PackExpansionExpr *E);
     void VisitSizeOfPackExpr(SizeOfPackExpr *E);
@@ -1343,6 +1344,16 @@ void ASTStmtReader::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
   E->RhsType = GetTypeSourceInfo(Record, Idx);
 }
 
+void ASTStmtReader::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+  VisitExpr(E);
+  E->ET = (ExpressionTrait)Record[Idx++];
+  E->Value = (bool)Record[Idx++];
+  SourceRange Range = ReadSourceRange(Record, Idx);
+  E->QueriedExpression = Reader.ReadSubExpr();
+  E->Loc = Range.getBegin();
+  E->RParen = Range.getEnd();
+}
+
 void ASTStmtReader::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
   VisitExpr(E);
   E->Value = (bool)Record[Idx++];
@@ -1935,6 +1946,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
       S = new (Context) BinaryTypeTraitExpr(Empty);
       break;
 
+    case EXPR_CXX_EXPRESSION_TRAIT:
+      S = new (Context) ExpressionTraitExpr(Empty);
+      break;
+
     case EXPR_CXX_NOEXCEPT:
       S = new (Context) CXXNoexceptExpr(Empty);
       break;
index c2b038284cf1a679444ccd72b5c688d48128e4ce..19cd834dd45453b49365c6599e6a8c1f6ea03a40 100644 (file)
@@ -153,6 +153,7 @@ namespace clang {
 
     void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
     void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
+    void VisitExpressionTraitExpr(ExpressionTraitExpr *E);
     void VisitCXXNoexceptExpr(CXXNoexceptExpr *E);
     void VisitPackExpansionExpr(PackExpansionExpr *E);
     void VisitSizeOfPackExpr(SizeOfPackExpr *E);
@@ -1339,6 +1340,15 @@ void ASTStmtWriter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
   Code = serialization::EXPR_BINARY_TYPE_TRAIT;
 }
 
+void ASTStmtWriter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+  VisitExpr(E);
+  Record.push_back(E->getTrait());
+  Record.push_back(E->getValue());
+  Writer.AddSourceRange(E->getSourceRange(), Record);
+  Writer.AddStmt(E->getQueriedExpression());
+  Code = serialization::EXPR_CXX_EXPRESSION_TRAIT;
+}
+
 void ASTStmtWriter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
   VisitExpr(E);
   Record.push_back(E->getValue());
index ac7e687b935b25b1251a461171494539146589e2..49af4304b05467164b938e4c45f9c11569a93f7b 100644 (file)
@@ -435,6 +435,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
     case Stmt::DependentScopeDeclRefExprClass:
     case Stmt::UnaryTypeTraitExprClass:
     case Stmt::BinaryTypeTraitExprClass:
+    case Stmt::ExpressionTraitExprClass:
     case Stmt::UnresolvedLookupExprClass:
     case Stmt::UnresolvedMemberExprClass:
     case Stmt::CXXNoexceptExprClass:
diff --git a/test/SemaCXX/expression-traits.cpp b/test/SemaCXX/expression-traits.cpp
new file mode 100644 (file)
index 0000000..6b644ea
--- /dev/null
@@ -0,0 +1,620 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fcxx-exceptions %s
+
+//
+// Tests for "expression traits" intrinsics such as __is_lvalue_expr.
+//
+// For the time being, these tests are written against the 2003 C++
+// standard (ISO/IEC 14882:2003 -- see draft at
+// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2001/n1316/).
+//
+// C++0x has its own, more-refined, idea of lvalues and rvalues.
+// If/when we need to support those, we'll need to track both
+// standard documents.
+
+#if !__has_feature(cxx_static_assert)
+# define CONCAT_(X_, Y_) CONCAT1_(X_, Y_)
+# define CONCAT1_(X_, Y_) X_ ## Y_
+
+// This emulation can be used multiple times on one line (and thus in
+// a macro), except at class scope
+# define static_assert(b_, m_) \
+  typedef int CONCAT_(sa_, __LINE__)[b_ ? 1 : -1]
+#endif
+
+// Tests are broken down according to section of the C++03 standard
+// (ISO/IEC 14882:2003(E))
+
+// Assertion macros encoding the following two paragraphs
+//
+// basic.lval/1 Every expression is either an lvalue or an rvalue.
+//
+// expr.prim/5 A parenthesized expression is a primary expression whose type
+// and value are identical to those of the enclosed expression. The
+// presence of parentheses does not affect whether the expression is
+// an lvalue.
+//
+// Note: these asserts cannot be made at class scope in C++03.  Put
+// them in a member function instead.
+#define ASSERT_LVALUE(expr)                                             \
+    static_assert(__is_lvalue_expr(expr), "should be an lvalue");       \
+    static_assert(__is_lvalue_expr((expr)),                             \
+                  "the presence of parentheses should have"             \
+                  " no effect on lvalueness (expr.prim/5)");            \
+    static_assert(!__is_rvalue_expr(expr), "should be an lvalue");      \
+    static_assert(!__is_rvalue_expr((expr)),                            \
+                  "the presence of parentheses should have"             \
+                  " no effect on lvalueness (expr.prim/5)")
+
+#define ASSERT_RVALUE(expr);                                            \
+    static_assert(__is_rvalue_expr(expr), "should be an rvalue");       \
+    static_assert(__is_rvalue_expr((expr)),                             \
+                  "the presence of parentheses should have"             \
+                  " no effect on lvalueness (expr.prim/5)");            \
+    static_assert(!__is_lvalue_expr(expr), "should be an rvalue");      \
+    static_assert(!__is_lvalue_expr((expr)),                            \
+                  "the presence of parentheses should have"             \
+                  " no effect on lvalueness (expr.prim/5)")
+
+enum Enum { Enumerator };
+
+int ReturnInt();
+void ReturnVoid();
+Enum ReturnEnum();
+
+void basic_lval_5()
+{
+    // basic.lval/5: The result of calling a function that does not return
+    // a reference is an rvalue.
+    ASSERT_RVALUE(ReturnInt());
+    ASSERT_RVALUE(ReturnVoid());
+    ASSERT_RVALUE(ReturnEnum());
+}
+
+int& ReturnIntReference();
+extern Enum& ReturnEnumReference();
+
+void basic_lval_6()
+{
+    // basic.lval/6: An expression which holds a temporary object resulting
+    // from a cast to a nonreference type is an rvalue (this includes
+    // the explicit creation of an object using functional notation
+    struct IntClass
+    {
+        explicit IntClass(int = 0);
+        IntClass(char const*);
+        operator int() const;
+    };
+    
+    struct ConvertibleToIntClass
+    {
+        operator IntClass() const;
+    };
+
+    ConvertibleToIntClass b;
+
+    // Make sure even trivial conversions are not detected as lvalues
+    int intLvalue = 0;
+    ASSERT_RVALUE((int)intLvalue);
+    ASSERT_RVALUE((short)intLvalue);
+    ASSERT_RVALUE((long)intLvalue);
+    
+    // Same tests with function-call notation
+    ASSERT_RVALUE(int(intLvalue));
+    ASSERT_RVALUE(short(intLvalue));
+    ASSERT_RVALUE(long(intLvalue));
+
+    char charLValue = 'x';
+    ASSERT_RVALUE((signed char)charLValue);
+    ASSERT_RVALUE((unsigned char)charLValue);
+
+    ASSERT_RVALUE(static_cast<int>(IntClass()));
+    IntClass intClassLValue;
+    ASSERT_RVALUE(static_cast<int>(intClassLValue)); 
+    ASSERT_RVALUE(static_cast<IntClass>(ConvertibleToIntClass()));
+    ConvertibleToIntClass convertibleToIntClassLValue;
+    ASSERT_RVALUE(static_cast<IntClass>(convertibleToIntClassLValue));
+    
+
+    typedef signed char signed_char;
+    typedef unsigned char unsigned_char;
+    ASSERT_RVALUE(signed_char(charLValue));
+    ASSERT_RVALUE(unsigned_char(charLValue));
+
+    ASSERT_RVALUE(int(IntClass()));
+    ASSERT_RVALUE(int(intClassLValue)); 
+    ASSERT_RVALUE(IntClass(ConvertibleToIntClass()));
+    ASSERT_RVALUE(IntClass(convertibleToIntClassLValue));
+}
+
+void conv_ptr_1()
+{
+    // conv.ptr/1: A null pointer constant is an integral constant
+    // expression (5.19) rvalue of integer type that evaluates to
+    // zero.
+    ASSERT_RVALUE(0);
+}
+
+void expr_6()
+{
+    // expr/6: If an expression initially has the type “reference to T”
+    // (8.3.2, 8.5.3), ... the expression is an lvalue.
+    int x = 0;
+    int& referenceToInt = x;
+    ASSERT_LVALUE(referenceToInt);
+    ASSERT_LVALUE(ReturnIntReference());
+}
+
+void expr_prim_2()
+{
+    // 5.1/2 A string literal is an lvalue; all other
+    // literals are rvalues.
+    ASSERT_LVALUE("foo");
+    ASSERT_RVALUE(1);
+    ASSERT_RVALUE(1.2);
+    ASSERT_RVALUE(10UL);
+}
+
+void expr_prim_3()
+{
+    // 5.1/3: The keyword "this" names a pointer to the object for
+    // which a nonstatic member function (9.3.2) is invoked. ...The
+    // expression is an rvalue.
+    struct ThisTest
+    {
+        void f() { ASSERT_RVALUE(this); }
+    };
+}
+
+extern int variable;
+void Function();
+
+struct BaseClass
+{
+    virtual ~BaseClass();
+    
+    int BaseNonstaticMemberFunction();
+    static int BaseStaticMemberFunction();
+    int baseDataMember;
+};
+
+struct Class : BaseClass
+{
+    static void function();
+    static int variable;
+
+    template <class T>
+    struct NestedClassTemplate {};
+
+    template <class T>
+    static int& NestedFuncTemplate() { return variable; } // expected-note{{candidate function}}
+
+    template <class T>
+    int& NestedMemfunTemplate() { return variable; } // expected-note{{candidate function}}
+
+    int operator*() const;
+
+    template <class T>
+    int operator+(T) const; // expected-note{{candidate function}}
+
+    int NonstaticMemberFunction();
+    static int StaticMemberFunction();
+    int dataMember;
+
+    int& referenceDataMember;
+    static int& staticReferenceDataMember;
+    static int staticNonreferenceDataMember;
+
+    enum Enum { Enumerator };
+
+    operator long() const;
+    
+    Class();
+    Class(int,int);
+
+    void expr_prim_4()
+    {
+        // 5.1/4: The operator :: followed by an identifier, a
+        // qualified-id, or an operator-function-id is a primary-
+        // expression. ...The result is an lvalue if the entity is
+        // a function or variable.
+        ASSERT_LVALUE(::Function);         // identifier: function
+        ASSERT_LVALUE(::variable);         // identifier: variable
+
+        // the only qualified-id form that can start without "::" (and thus
+        // be legal after "::" ) is
+        //
+        // ::<sub>opt</sub> nested-name-specifier template<sub>opt</sub> unqualified-id
+        ASSERT_LVALUE(::Class::function);  // qualified-id: function
+        ASSERT_LVALUE(::Class::variable);  // qualified-id: variable
+
+        // The standard doesn't give a clear answer about whether these
+        // should really be lvalues or rvalues without some surrounding
+        // context that forces them to be interpreted as naming a
+        // particular function template specialization (that situation
+        // doesn't come up in legal pure C++ programs). This language
+        // extension simply rejects them as requiring additional context
+        __is_lvalue_expr(::Class::NestedFuncTemplate);    // qualified-id: template \
+        // expected-error{{cannot resolve overloaded function 'NestedFuncTemplate' from context}}
+        
+        __is_lvalue_expr(::Class::NestedMemfunTemplate);  // qualified-id: template \
+        // expected-error{{cannot resolve overloaded function 'NestedMemfunTemplate' from context}}
+        
+        __is_lvalue_expr(::Class::operator+);             // operator-function-id: template \
+        // expected-error{{cannot resolve overloaded function 'operator+' from context}}
+
+        ASSERT_RVALUE(::Class::operator*);         // operator-function-id: member function
+    }
+
+    void expr_prim_7()
+    {
+        // expr.prim/7 An identifier is an id-expression provided it has been
+        // suitably declared (clause 7). [Note: ... ] The type of the
+        // expression is the type of the identifier. The result is the
+        // entity denoted by the identifier. The result is an lvalue if
+        // the entity is a function, variable, or data member... (cont'd)
+        ASSERT_LVALUE(Function);        // identifier: function
+        ASSERT_LVALUE(StaticMemberFunction);        // identifier: function
+        ASSERT_LVALUE(variable);        // identifier: variable
+        ASSERT_LVALUE(dataMember);      // identifier: data member
+        ASSERT_RVALUE(NonstaticMemberFunction); // identifier: member function
+
+        // (cont'd)...A nested-name-specifier that names a class,
+        // optionally followed by the keyword template (14.2), and then
+        // followed by the name of a member of either that class (9.2) or
+        // one of its base classes... is a qualified-id... The result is
+        // the member. The type of the result is the type of the
+        // member. The result is an lvalue if the member is a static
+        // member function or a data member.
+        ASSERT_LVALUE(Class::dataMember);
+        ASSERT_LVALUE(Class::StaticMemberFunction);
+        ASSERT_RVALUE(Class::NonstaticMemberFunction); // identifier: member function
+
+        ASSERT_LVALUE(Class::baseDataMember);
+        ASSERT_LVALUE(Class::BaseStaticMemberFunction);
+        ASSERT_RVALUE(Class::BaseNonstaticMemberFunction); // identifier: member function
+    }
+};
+
+void expr_call_10()
+{
+    // expr.call/10: A function call is an lvalue if and only if the
+    // result type is a reference.  This statement is partially
+    // redundant with basic.lval/5
+    basic_lval_5();
+    
+    ASSERT_LVALUE(ReturnIntReference());
+    ASSERT_LVALUE(ReturnEnumReference());
+}
+
+namespace Namespace
+{
+  int x;
+  void function();
+}
+
+void expr_prim_8()
+{
+    // expr.prim/8 A nested-name-specifier that names a namespace
+    // (7.3), followed by the name of a member of that namespace (or
+    // the name of a member of a namespace made visible by a
+    // using-directive ) is a qualified-id; 3.4.3.2 describes name
+    // lookup for namespace members that appear in qualified-ids. The
+    // result is the member. The type of the result is the type of the
+    // member. The result is an lvalue if the member is a function or
+    // a variable.
+    ASSERT_LVALUE(Namespace::x);
+    ASSERT_LVALUE(Namespace::function);
+}
+
+void expr_sub_1(int* pointer)
+{
+    // expr.sub/1 A postfix expression followed by an expression in
+    // square brackets is a postfix expression. One of the expressions
+    // shall have the type “pointer to T” and the other shall have
+    // enumeration or integral type. The result is an lvalue of type
+    // “T.”
+    ASSERT_LVALUE(pointer[1]);
+    
+    // The expression E1[E2] is identical (by definition) to *((E1)+(E2)).
+    ASSERT_LVALUE(*(pointer+1));
+}
+
+void expr_type_conv_1()
+{
+    // expr.type.conv/1 A simple-type-specifier (7.1.5) followed by a
+    // parenthesized expression-list constructs a value of the specified
+    // type given the expression list. ... If the expression list
+    // specifies more than a single value, the type shall be a class with
+    // a suitably declared constructor (8.5, 12.1), and the expression
+    // T(x1, x2, ...) is equivalent in effect to the declaration T t(x1,
+    // x2, ...); for some invented temporary variable t, with the result
+    // being the value of t as an rvalue.
+    ASSERT_RVALUE(Class(2,2));
+}
+
+void expr_type_conv_2()
+{
+    // expr.type.conv/2 The expression T(), where T is a
+    // simple-type-specifier (7.1.5.2) for a non-array complete object
+    // type or the (possibly cv-qualified) void type, creates an
+    // rvalue of the specified type,
+    ASSERT_RVALUE(int());
+    ASSERT_RVALUE(Class());
+    ASSERT_RVALUE(void());
+}
+
+
+void expr_ref_4()
+{
+    // Applies to expressions of the form E1.E2
+    
+    // If E2 is declared to have type “reference to T”, then E1.E2 is
+    // an lvalue;.... Otherwise, one of the following rules applies.
+    ASSERT_LVALUE(Class().staticReferenceDataMember);
+    ASSERT_LVALUE(Class().referenceDataMember);
+    
+    // — If E2 is a static data member, and the type of E2 is T, then
+    // E1.E2 is an lvalue; ...
+    ASSERT_LVALUE(Class().staticNonreferenceDataMember);
+    ASSERT_LVALUE(Class().staticReferenceDataMember);
+
+
+    // — If E2 is a non-static data member, ... If E1 is an lvalue,
+    // then E1.E2 is an lvalue...
+    Class lvalue;
+    ASSERT_LVALUE(lvalue.dataMember);
+    ASSERT_RVALUE(Class().dataMember);
+
+    // — If E1.E2 refers to a static member function, ... then E1.E2
+    // is an lvalue
+    ASSERT_LVALUE(Class().StaticMemberFunction);
+    
+    // — Otherwise, if E1.E2 refers to a non-static member function,
+    // then E1.E2 is not an lvalue.
+    ASSERT_RVALUE(Class().NonstaticMemberFunction);
+
+    // — If E2 is a member enumerator, and the type of E2 is T, the
+    // expression E1.E2 is not an lvalue. The type of E1.E2 is T.
+    ASSERT_RVALUE(Class().Enumerator);
+    ASSERT_RVALUE(lvalue.Enumerator);
+}
+
+
+void expr_post_incr_1(int x)
+{
+    // expr.post.incr/1 The value obtained by applying a postfix ++ is
+    // the value that the operand had before applying the
+    // operator... The result is an rvalue.
+    ASSERT_RVALUE(x++);
+}
+
+void expr_dynamic_cast_2()
+{
+    // expr.dynamic.cast/2: If T is a pointer type, v shall be an
+    // rvalue of a pointer to complete class type, and the result is
+    // an rvalue of type T.
+    Class instance;
+    ASSERT_RVALUE(dynamic_cast<Class*>(&instance));
+
+    // If T is a reference type, v shall be an
+    // lvalue of a complete class type, and the result is an lvalue of
+    // the type referred to by T.
+    ASSERT_LVALUE(dynamic_cast<Class&>(instance));
+}
+
+void expr_dynamic_cast_5()
+{
+    // expr.dynamic.cast/5: If T is “reference to cv1 B” and v has type
+    // “cv2 D” such that B is a base class of D, the result is an
+    // lvalue for the unique B sub-object of the D object referred
+    // to by v.
+    typedef BaseClass B;
+    typedef Class D;
+    D object;
+    ASSERT_LVALUE(dynamic_cast<B&>(object));
+}
+
+// expr.dynamic.cast/8: The run-time check logically executes as follows:
+//
+// — If, in the most derived object pointed (referred) to by v, v
+// points (refers) to a public base class subobject of a T object, and
+// if only one object of type T is derived from the sub-object pointed
+// (referred) to by v, the result is a pointer (an lvalue referring)
+// to that T object.
+//
+// — Otherwise, if v points (refers) to a public base class sub-object
+// of the most derived object, and the type of the most derived object
+// has a base class, of type T, that is unambiguous and public, the
+// result is a pointer (an lvalue referring) to the T sub-object of
+// the most derived object.
+//
+// The mention of "lvalue" in the text above appears to be a
+// defect that is being corrected by the response to UK65 (see
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2841.html).
+
+#if 0
+void expr_typeid_1()
+{
+    // expr.typeid/1: The result of a typeid expression is an lvalue...
+    ASSERT_LVALUE(typeid(1));
+}
+#endif
+
+void expr_static_cast_1(int x)
+{
+    // expr.static.cast/1: The result of the expression
+    // static_cast<T>(v) is the result of converting the expression v
+    // to type T. If T is a reference type, the result is an lvalue;
+    // otherwise, the result is an rvalue.
+    ASSERT_LVALUE(static_cast<int&>(x));
+    ASSERT_RVALUE(static_cast<int>(x));
+}
+
+void expr_reinterpret_cast_1()
+{
+    // expr.reinterpret.cast/1: The result of the expression
+    // reinterpret_cast<T>(v) is the result of converting the
+    // expression v to type T. If T is a reference type, the result is
+    // an lvalue; otherwise, the result is an rvalue
+    ASSERT_RVALUE(reinterpret_cast<int*>(0));
+    char const v = 0;
+    ASSERT_LVALUE(reinterpret_cast<char const&>(v));
+}
+
+void expr_unary_op_1(int* pointer, struct incomplete* pointerToIncompleteType)
+{
+    // expr.unary.op/1: The unary * operator performs indirection: the
+    // expression to which it is applied shall be a pointer to an
+    // object type, or a pointer to a function type and the result is
+    // an lvalue referring to the object or function to which the
+    // expression points.  
+    ASSERT_LVALUE(*pointer);
+    ASSERT_LVALUE(*Function);
+
+    // [Note: a pointer to an incomplete type
+    // (other than cv void ) can be dereferenced. ]
+    ASSERT_LVALUE(*pointerToIncompleteType);
+}
+
+void expr_pre_incr_1(int operand)
+{
+    // expr.pre.incr/1: The operand of prefix ++ ... shall be a
+    // modifiable lvalue.... The value is the new value of the
+    // operand; it is an lvalue.
+    ASSERT_LVALUE(++operand);
+}
+
+void expr_cast_1(int x)
+{
+    // expr.cast/1: The result of the expression (T) cast-expression
+    // is of type T. The result is an lvalue if T is a reference type,
+    // otherwise the result is an rvalue.
+    ASSERT_LVALUE((void(&)())expr_cast_1);
+    ASSERT_LVALUE((int&)x);
+    ASSERT_RVALUE((void(*)())expr_cast_1);
+    ASSERT_RVALUE((int)x);
+}
+
+void expr_mptr_oper()
+{
+    // expr.mptr.oper/6: The result of a .* expression is an lvalue
+    // only if its first operand is an lvalue and its second operand
+    // is a pointer to data member... (cont'd)
+    typedef Class MakeRValue;
+    ASSERT_RVALUE(MakeRValue().*(&Class::dataMember));
+    ASSERT_RVALUE(MakeRValue().*(&Class::NonstaticMemberFunction));
+    Class lvalue;
+    ASSERT_LVALUE(lvalue.*(&Class::dataMember));
+    ASSERT_RVALUE(lvalue.*(&Class::NonstaticMemberFunction));
+    
+    // (cont'd)...The result of an ->* expression is an lvalue only
+    // if its second operand is a pointer to data member. If the
+    // second operand is the null pointer to member value (4.11), the
+    // behavior is undefined.
+    ASSERT_LVALUE((&lvalue)->*(&Class::dataMember));
+    ASSERT_RVALUE((&lvalue)->*(&Class::NonstaticMemberFunction));
+}
+
+void expr_cond(bool cond)
+{
+    // 5.16 Conditional operator [expr.cond]
+    //
+    // 2 If either the second or the third operand has type (possibly
+    // cv-qualified) void, then the lvalue-to-rvalue (4.1),
+    // array-to-pointer (4.2), and function-to-pointer (4.3) standard
+    // conversions are performed on the second and third operands, and one
+    // of the following shall hold:
+    //
+    // — The second or the third operand (but not both) is a
+    // throw-expression (15.1); the result is of the type of the other and
+    // is an rvalue.
+
+    Class classLvalue;
+    ASSERT_RVALUE(cond ? throw 1 : (void)0);
+    ASSERT_RVALUE(cond ? (void)0 : throw 1);
+    ASSERT_RVALUE(cond ? throw 1 : classLvalue);
+    ASSERT_RVALUE(cond ? classLvalue : throw 1);
+
+    // — Both the second and the third operands have type void; the result
+    // is of type void and is an rvalue. [Note: this includes the case
+    // where both operands are throw-expressions. ]
+    ASSERT_RVALUE(cond ? (void)1 : (void)0);
+    ASSERT_RVALUE(cond ? throw 1 : throw 0);
+    
+    // expr.cond/4: If the second and third operands are lvalues and
+    // have the same type, the result is of that type and is an
+    // lvalue.
+    ASSERT_LVALUE(cond ? classLvalue : classLvalue);
+    int intLvalue = 0;
+    ASSERT_LVALUE(cond ? intLvalue : intLvalue);
+    
+    // expr.cond/5:Otherwise, the result is an rvalue.
+    typedef Class MakeRValue;
+    ASSERT_RVALUE(cond ? MakeRValue() : classLvalue);
+    ASSERT_RVALUE(cond ? classLvalue : MakeRValue());
+    ASSERT_RVALUE(cond ? MakeRValue() : MakeRValue());
+    ASSERT_RVALUE(cond ? classLvalue : intLvalue);
+    ASSERT_RVALUE(cond ? intLvalue : int());
+}
+
+void expr_ass_1(int x)
+{
+    // expr.ass/1: There are several assignment operators, all of
+    // which group right-to-left. All require a modifiable lvalue as
+    // their left operand, and the type of an assignment expression is
+    // that of its left operand. The result of the assignment
+    // operation is the value stored in the left operand after the
+    // assignment has taken place; the result is an lvalue.
+    ASSERT_LVALUE(x = 1);
+    ASSERT_LVALUE(x += 1);
+    ASSERT_LVALUE(x -= 1);
+    ASSERT_LVALUE(x *= 1);
+    ASSERT_LVALUE(x /= 1);
+    ASSERT_LVALUE(x %= 1);
+    ASSERT_LVALUE(x ^= 1);
+    ASSERT_LVALUE(x &= 1);
+    ASSERT_LVALUE(x |= 1);
+}
+
+void expr_comma(int x)
+{
+    // expr.comma: A pair of expressions separated by a comma is
+    // evaluated left-to-right and the value of the left expression is
+    // discarded... result is an lvalue if its right operand is.
+
+    // Can't use the ASSERT_XXXX macros without adding parens around
+    // the comma expression.
+    static_assert(__is_lvalue_expr(x,x), "expected an lvalue");
+    static_assert(__is_rvalue_expr(x,1), "expected an rvalue");
+    static_assert(__is_lvalue_expr(1,x), "expected an lvalue");
+    static_assert(__is_rvalue_expr(1,1), "expected an rvalue");
+}
+
+#if 0
+template<typename T> void f();
+
+// FIXME These currently fail
+void expr_fun_lvalue()
+{
+  ASSERT_LVALUE(&f<int>);
+}
+
+void expr_fun_rvalue()
+{
+  ASSERT_RVALUE(f<int>);
+}
+#endif
+
+template <int NonTypeNonReferenceParameter, int& NonTypeReferenceParameter>
+void check_temp_param_6()
+{
+    ASSERT_RVALUE(NonTypeNonReferenceParameter);
+    ASSERT_LVALUE(NonTypeReferenceParameter);
+}
+
+int AnInt = 0;
+
+void temp_param_6()
+{
+    check_temp_param_6<3,AnInt>();
+}
index 98edd521ef4bf2b032628feab996f1c47ef3812e..a50c987b3c25b86951ab4f188a0cb08fe348ad03 100644 (file)
@@ -1789,6 +1789,7 @@ public:
   void VisitWhileStmt(WhileStmt *W);
   void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
   void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
+  void VisitExpressionTraitExpr(ExpressionTraitExpr *E);
   void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U);
   void VisitVAArgExpr(VAArgExpr *E);
   void VisitSizeOfPackExpr(SizeOfPackExpr *E);
@@ -2077,6 +2078,10 @@ void EnqueueVisitor::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
   AddTypeLoc(E->getLhsTypeSourceInfo());
 }
 
+void EnqueueVisitor::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+  EnqueueChildren(E);
+}
+
 void EnqueueVisitor::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U) {
   VisitOverloadExpr(U);
   if (!U->isImplicitAccess())
index b3ad83daafa6f7940f4f63177cace358f536e040..81beba822f9166e62633e879889d30bcd6a97ff1 100644 (file)
@@ -151,6 +151,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
   case Stmt::UnresolvedLookupExprClass:   
   case Stmt::UnaryTypeTraitExprClass:     
   case Stmt::BinaryTypeTraitExprClass:     
+  case Stmt::ExpressionTraitExprClass:     
   case Stmt::DependentScopeDeclRefExprClass:  
   case Stmt::CXXBindTemporaryExprClass:   
   case Stmt::ExprWithCleanupsClass: