[cfe-commits] PATCH [1/2]: Implementation of Embarcadero expression traits

Douglas Gregor dgregor at apple.com
Mon Feb 21 17:43:49 PST 2011


On Feb 18, 2011, at 2:53 PM, John Wiegley wrote:

> 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.
>> From 17936dde6e7160758a9edd64a4a734cb51603a81 Mon Sep 17 00:00:00 2001
> From: Dave Abrahams <dave at boostpro.com>
> Date: Sat, 8 Jan 2011 08:52:37 -0500
> Subject: [PATCH 1/2] Implementation of expression traits (__is_lvalue_expr/__is_rvalue_expr)
> 
> ---
> include/clang/AST/EvaluatedExprVisitor.h   |    1 +
> include/clang/AST/ExprCXX.h                |   54 +++
> include/clang/AST/RecursiveASTVisitor.h    |    4 +
> include/clang/Basic/ExpressionTraits.h     |   25 ++
> include/clang/Basic/StmtNodes.td           |    1 +
> include/clang/Basic/TokenKinds.def         |    4 +
> include/clang/Parse/Parser.h               |    4 +
> include/clang/Sema/Sema.h                  |   13 +
> include/clang/Serialization/ASTBitCodes.h  |    1 +
> lib/AST/ExprCXX.cpp                        |    8 +
> lib/AST/ExprClassification.cpp             |    1 +
> lib/AST/ExprConstant.cpp                   |    5 +
> lib/AST/ItaniumMangle.cpp                  |    1 +
> lib/AST/StmtPrinter.cpp                    |   15 +
> lib/AST/StmtProfile.cpp                    |    6 +
> lib/CodeGen/CGExprScalar.cpp               |    4 +
> lib/Parse/ParseExpr.cpp                    |    8 +
> lib/Parse/ParseExprCXX.cpp                 |   30 ++
> lib/Sema/SemaExprCXX.cpp                   |   39 ++
> lib/Sema/TreeTransform.h                   |   29 ++
> lib/Serialization/ASTReaderStmt.cpp        |    4 +
> lib/StaticAnalyzer/Checkers/ExprEngine.cpp |    1 +
> test/SemaCXX/expression-traits.cpp         |  609 ++++++++++++++++++++++++++++
> tools/libclang/CIndex.cpp                  |    5 +
> tools/libclang/CXCursor.cpp                |    1 +
> 25 files changed, 873 insertions(+), 0 deletions(-)
> create mode 100644 include/clang/Basic/ExpressionTraits.h
> create mode 100644 test/SemaCXX/expression-traits.cpp
> 
> diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h
> index be606e0..061f0ac 100644
> --- a/include/clang/AST/EvaluatedExprVisitor.h
> +++ b/include/clang/AST/EvaluatedExprVisitor.h
> @@ -38,6 +38,7 @@ public:
>   void VisitDeclRefExpr(DeclRefExpr *E) { }
>   void VisitOffsetOfExpr(OffsetOfExpr *E) { }
>   void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { }
> +  void VisitExpressionTraitExpr(ExpressionTraitExpr *E) { }
>   void VisitBlockExpr(BlockExpr *E) { }
>   void VisitCXXUuidofExpr(CXXUuidofExpr *E) { }  
>   void VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { }
> diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
> index c0e35e3..26f0495 100644
> --- a/include/clang/AST/ExprCXX.h
> +++ b/include/clang/AST/ExprCXX.h
> @@ -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"
> @@ -1559,6 +1560,59 @@ 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() { }
> +
> +  virtual SourceRange getSourceRange() const { return SourceRange(Loc, RParen);}

getSourceRange() should not be "virtual". We recently devirtualized Stmt and Expr nodes.

> +  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
> +  virtual child_iterator child_begin();
> +  virtual child_iterator child_end();
> +
> +  friend class ASTStmtReader;
> +};
> +
> +
> /// \brief A reference to an overloaded function set, either an
> /// \t UnresolvedLookupExpr or an \t UnresolvedMemberExpr.
> class OverloadExpr : public Expr {
> diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
> index 0a98bea..f24b978 100644
> --- a/include/clang/AST/RecursiveASTVisitor.h
> +++ b/include/clang/AST/RecursiveASTVisitor.h
> @@ -1769,6 +1769,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
> index 0000000..403a59a
> --- /dev/null
> +++ b/include/clang/Basic/ExpressionTraits.h
> @@ -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
> diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
> index 58db87b..42a9514 100644
> --- a/include/clang/Basic/StmtNodes.td
> +++ b/include/clang/Basic/StmtNodes.td
> @@ -100,6 +100,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>;
> diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
> index 5c21cd6..891bce2 100644
> --- a/include/clang/Basic/TokenKinds.def
> +++ b/include/clang/Basic/TokenKinds.def
> @@ -328,6 +328,10 @@ KEYWORD(__is_union                  , KEYCXX)
> // Tentative name - there's no implementation of std::is_literal_type yet.
> KEYWORD(__is_literal                , KEYCXX)
> 
> +// Embarcadero Expression Traits
> +KEYWORD(__is_lvalue_expr            , KEYCXX)
> +KEYWORD(__is_rvalue_expr            , KEYCXX)
> +
> // Apple Extension.
> KEYWORD(__private_extern__          , KEYALL)
> 
> diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
> index f1cee27..506ec84 100644
> --- a/include/clang/Parse/Parser.h
> +++ b/include/clang/Parse/Parser.h
> @@ -1715,6 +1715,10 @@ private:
>   // GNU G++: Type Traits [Type-Traits.html in the GCC manual]
>   ExprResult ParseUnaryTypeTrait();
>   ExprResult ParseBinaryTypeTrait();
> +    
> +  //===--------------------------------------------------------------------===//
> +  // Embarcadero: Expression Traits
> +  ExprResult ParseExpressionTrait();
> 
>   //===--------------------------------------------------------------------===//
>   // Preprocessor code-completion pass-through
> diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
> index 8c48fc5..b9d0c6a 100644
> --- a/include/clang/Sema/Sema.h
> +++ b/include/clang/Sema/Sema.h
> @@ -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"
> @@ -2393,6 +2394,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,
> diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
> index 5c9a308..645c790 100644
> --- a/include/clang/Serialization/ASTBitCodes.h
> +++ b/include/clang/Serialization/ASTBitCodes.h
> @@ -939,6 +939,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
> diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
> index a11d05a..85a5c90 100644
> --- a/lib/AST/ExprCXX.cpp
> +++ b/lib/AST/ExprCXX.cpp
> @@ -377,6 +377,14 @@ Stmt::child_iterator BinaryTypeTraitExpr::child_end() {
>   return child_iterator();
> }
> 
> +//ExpressionTraitExpr
> +Stmt::child_iterator ExpressionTraitExpr::child_begin() {
> +  return child_iterator();
> +}
> +Stmt::child_iterator ExpressionTraitExpr::child_end() {
> +  return child_iterator();
> +}

These functions should return child iterators for &QueriedExpression and &QueriedExpression +1, respectively.

> // DependentScopeDeclRefExpr
> DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T,
>                             NestedNameSpecifier *Qualifier,
> diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
> index c9f4fa8..9dd1bf0 100644
> --- a/lib/AST/ExprClassification.cpp
> +++ b/lib/AST/ExprClassification.cpp
> @@ -146,6 +146,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:
> diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
> index 0a7a9d2..9e1a786 100644
> --- a/lib/AST/ExprConstant.cpp
> +++ b/lib/AST/ExprConstant.cpp
> @@ -958,6 +958,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));
>   }
> @@ -2646,6 +2650,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:
> diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
> index a84df12..b8cd41a 100644
> --- a/lib/AST/ItaniumMangle.cpp
> +++ b/lib/AST/ItaniumMangle.cpp
> @@ -1729,6 +1729,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: {
> diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
> index 2ed2c92..4ec3aa2 100644
> --- a/lib/AST/StmtPrinter.cpp
> +++ b/lib/AST/StmtPrinter.cpp
> @@ -1237,6 +1237,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) << ")";
> @@ -1248,6 +1257,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());
> diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
> index 842a2d9..044332f 100644
> --- a/lib/AST/StmtProfile.cpp
> +++ b/lib/AST/StmtProfile.cpp
> @@ -779,6 +779,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);
> diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
> index e309e36..b61192e 100644
> --- a/lib/CodeGen/CGExprScalar.cpp
> +++ b/lib/CodeGen/CGExprScalar.cpp
> @@ -362,6 +362,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
> diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
> index 5928871..2e6fc00 100644
> --- a/lib/Parse/ParseExpr.cpp
> +++ b/lib/Parse/ParseExpr.cpp
> @@ -541,6 +541,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,
> @@ -992,6 +996,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);
> diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
> index e769eca..a854a74 100644
> --- a/lib/Parse/ParseExprCXX.cpp
> +++ b/lib/Parse/ParseExprCXX.cpp
> @@ -1832,6 +1832,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.
> @@ -1897,6 +1905,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:
> +/// [EMBT]            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.
> diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
> index f886e17..e3eb129 100644
> --- a/lib/Sema/SemaExprCXX.cpp
> +++ b/lib/Sema/SemaExprCXX.cpp
> @@ -2636,6 +2636,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, KWLoc);

This makes me wonder if this code correctly handles code like

	template<typename T> void f();

  __is_lvalue_expr(&f<int>);

or

  __is_rvalue_expr(f<int>);

?

> +    if (PE.isInvalid()) return ExprError();
> +    return BuildExpressionTrait(ET, KWLoc, PE.take(), RParen);
> +  }
> +
> +  bool value = false;

LLVM coding conventions suggest capitalizing "value" to "Value", here.

> +  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(Expr *&lex, Expr *&rex,
>                                             ExprValueKind &VK,
>                                             SourceLocation Loc,
> diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
> index 2a82869..0f52aaa 100644
> --- a/lib/Sema/TreeTransform.h
> +++ b/lib/Sema/TreeTransform.h
> @@ -1872,6 +1872,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.
>   ///
> @@ -6519,6 +6530,24 @@ TreeTransform<Derived>::TransformBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
> 
> 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(
>                                                DependentScopeDeclRefExpr *E) {
>   NestedNameSpecifier *NNS
> diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
> index 8bd94b4..82719f5 100644
> --- a/lib/Serialization/ASTReaderStmt.cpp
> +++ b/lib/Serialization/ASTReaderStmt.cpp
> @@ -1853,6 +1853,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;
> diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
> index e2ad17e..5942955 100644
> --- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
> +++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
> @@ -833,6 +833,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
> index 0000000..051b19e
> --- /dev/null
> +++ b/test/SemaCXX/expression-traits.cpp
> @@ -0,0 +1,609 @@
> +// RUN: %clang_cc1 -fsyntax-only -verify %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 0
> +#include <typeinfo>
> +#endif

Why the #if 0 block?

> +#ifndef __GXX_EXPERIMENTAL_CXX0X__

How about 

  #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; }
> +
> +    template <class T>
> +    int& NestedMemfunTemplate() { return variable; }
> +
> +    int operator*() const;
> +
> +    template <class T>
> +    int operator+(T) const;
> +
> +    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 from context}}
> +        
> +        __is_lvalue_expr(::Class::NestedMemfunTemplate);  // qualified-id: template \
> +        // expected-error{{cannot resolve overloaded function from context}}
> +        
> +        __is_lvalue_expr(::Class::operator+);             // operator-function-id: template \
> +        // expected-error{{cannot resolve overloaded function 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");
> +}
> +
> +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>();
> +}
> diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
> index 32e0039..b8eab67 100644
> --- a/tools/libclang/CIndex.cpp
> +++ b/tools/libclang/CIndex.cpp
> @@ -1636,6 +1636,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);
> @@ -1921,6 +1922,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())
> diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
> index 7ae9f7d..da00eee 100644
> --- a/tools/libclang/CXCursor.cpp
> +++ b/tools/libclang/CXCursor.cpp
> @@ -149,6 +149,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: 
> -- 
> 1.7.4.1

	- Doug



More information about the cfe-commits mailing list