[cfe-commits] r59148 - in /cfe/trunk: Driver/RewriteObjC.cpp include/clang/AST/Expr.h include/clang/AST/TypeOrdering.h include/clang/Basic/DiagnosticKinds.def lib/AST/Expr.cpp lib/AST/StmtSerialization.cpp lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h test/SemaCXX/overloaded-builtin-operators.cpp

Douglas Gregor dgregor at apple.com
Thu Nov 13 11:56:17 PST 2008


On Nov 12, 2008, at 5:01 PM, Chris Lattner wrote:

> On Nov 12, 2008, at 9:17 AM, Douglas Gregor wrote:
>> URL: http://llvm.org/viewvc/llvm-project?rev=59148&view=rev
>> Log:
>> Implement support for operator overloading using candidate operator
>> functions for built-in operators, e.g., the builtin
>
> Nice,
>
>> As part of this change, ImplicitCastExpr can now be an lvalue.
>> +++ cfe/trunk/include/clang/AST/Expr.h Wed Nov 12 11:17:38 2008
>> @@ -834,14 +834,23 @@
>> /// (*f)(), float->double, short->int, etc.
>> ///
>> class ImplicitCastExpr : public CastExpr {
>> +  /// LvalueCast - Whether this cast produces an lvalue.
>> +  bool LvalueCast;
>> +
>> public:
>
> What cases can implicit casts be lvalues?  Please improve the class
> comment above to explain what invariants hold and what cases this can
> occur with.

It happens when binding a value to a reference. I've fix the comment  
accordingly.

>> = 
>> =====================================================================
>> --- cfe/trunk/include/clang/AST/TypeOrdering.h (original)
>> @@ -17,6 +17,7 @@
>> #define LLVM_CLANG_TYPE_ORDERING_H
>>
>> #include "clang/AST/Type.h"
>> +#include "llvm/ADT/DenseMap.h"
>
> You can just use forward declaration:
>
> template<typename T>
> struct DenseMapInfo;

Okay.

>
>> +    static bool isPod() {
>> +      // QualType isn't *technically* a POD type. However, we can  
>> get
>> +      // away with calling it a POD type since its copy constructor,
>> +      // copy assignment operator, and destructor are all trivial.
>> +      return true;
>> +    }
>
> Yeah, interesting point.  This method should really be named
> 'actsLikePodType' or something :)

isStandardLayoutType, for the C++0x'ers around...

>
>> +++ cfe/trunk/lib/AST/Expr.cpp Wed Nov 12 11:17:38 2008
>> @@ -389,8 +389,28 @@
>>        cast<UnaryOperator>(this)->getOpcode() ==
>> UnaryOperator::Extension)
>>      return cast<UnaryOperator>(this)->getSubExpr()-
>>> isLvalue(Ctx);  // GNU.
>>    break;
>> +  case ImplicitCastExprClass:
>> +    return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid
>> +                                                       :
>> LV_InvalidExpression;
>>  case ParenExprClass: // C99 6.5.1p5
>>    return cast<ParenExpr>(this)->getSubExpr()->isLvalue(Ctx);
>> +  case BinaryOperatorClass:
>> +  case CompoundAssignOperatorClass: {
>> +    const BinaryOperator *BinOp = cast<BinaryOperator>(this);
>> +    if (BinOp->isAssignmentOp()) {
>> +      if (Ctx.getLangOptions().CPlusPlus)
>> +        // C++ [expr.ass]p1:
>> +        //   The result of an assignment operation [...] is an
>> lvalue.
>> +        return LV_Valid;
>> +      else
>> +        // C99 6.5.16:
>> +        //   An assignment expression [...] is not an lvalue.
>> +        return LV_InvalidExpression;
>> +    } else
>> +      return LV_InvalidExpression;
>> +
>
> Would it be reasonable to restructure this to reduce nesting, e.g.:
>
> if (!BinOp->isAssignmentOp())
>   return LV_InvalidExpression;
>
> if (Ctx.getLangOptions().CPlusPlus)
>   return LV_Valid;
>
> return LV_InvalidExpression;
>
> ?  This makes it more obvious that the break it dead too.

Sure.

>
>> +QualType Sema::UsualArithmeticConversionsType(QualType lhs,
>> QualType rhs) {
>> +  // Perform the usual unary conversions. We do this early so that
>> +  // integral promotions to "int" can allow us to exit early, in the
>> +  // lhs == rhs check. Also, for conversion purposes, we ignore any
>> +  // qualifiers.  For example, "const float" and "float" are
>> +  // equivalent.
>> +  if (lhs->isPromotableIntegerType())
>> +    lhs = Context.IntTy;
>> +  else
>> +    lhs = Context.getCanonicalType(lhs).getUnqualifiedType();
>> +
>> +  if (rhs->isPromotableIntegerType())
>> +    rhs = Context.IntTy;
>> +  else
>> +    rhs = Context.getCanonicalType(rhs).getUnqualifiedType();
>
> Why strip off typedefs here?  It would be much better to preserve
> them, because AFAIK, lhs/rhs end up in the AST.

Huh, why did I do that? Fixed now.

>
>> +/// BuiltinCandidateTypeSet - A set of types that will be used for
>> the
>> +/// candidate operator functions for built-in operators (C++
>> +/// [over.built]). The types are separated into pointer types and
>> +/// enumeration types.
>> +class BuiltinCandidateTypeSet  {
>> +  /// TypeSet - A set of types.
>> +  typedef llvm::DenseSet<QualType> TypeSet;
>
> Is this usually small?  DenseSet is good for very large sets, but it
> does a heap allocation on the first insertion.

Ouch! That's good to know...

>  You might want to use
> SmallSet<QualType, 8> or something, which keeps avoids an allocation
> for sizes up to 8, but falls back to std::set after that.  Iteration
> over a SmallSet is also much faster than iteration over an extremely
> sparse DenseSet.
>
> Another option is SmallPtr<something*, 8> (which is specialized to use
> SmallPtrSet) which falls back to an equivalent to DenseSet (but
> actually slightly better) when the set grows beyond 8 elements.  If
> you like this approach, you could either forcibly cast QualType into a
> pointer, or make a nicer specialization of SmallSet that uses
> SmallPtrSet or something.

Okay, I'll pick one of these and leave a FIXME to revisit this once we  
can parse real C++ code. I'm guessing we'll see a bimodal distribution  
in the number of types here, with most cases having no entries and a  
small number of cases having many entries.

Thanks for the review!

   - Doug




More information about the cfe-commits mailing list