[cfe-commits] r81576 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/conversion-delete-expr.cpp

Fariborz Jahanian fjahanian at apple.com
Sat Sep 12 11:34:38 PDT 2009


On Sep 11, 2009, at 3:37 PM, Douglas Gregor wrote:

>
> On Sep 11, 2009, at 2:44 PM, Fariborz Jahanian wrote:
>
>> Author: fjahanian
>> Date: Fri Sep 11 16:44:33 2009
>> New Revision: 81576
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=81576&view=rev
>> Log:
>> Patch to build visible conversion function list lazily and make its
>> first use in calling the conversion function on delete statements.
>
> Cool.
>
>> Added:
>>   cfe/trunk/test/SemaCXX/conversion-delete-expr.cpp
>> Modified:
>>   cfe/trunk/include/clang/AST/DeclCXX.h
>>   cfe/trunk/lib/AST/DeclCXX.cpp
>>   cfe/trunk/lib/Sema/SemaExprCXX.cpp
>>
>> Modified: cfe/trunk/include/clang/AST/DeclCXX.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=81576&r1=81575&r2=81576&view=diff
>>
>> =
>> =
>> =
>> =
>> =
>> =
>> =
>> =
>> =
>> =====================================================================
>> --- cfe/trunk/include/clang/AST/DeclCXX.h (original)
>> +++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Sep 11 16:44:33 2009
>> @@ -367,9 +367,15 @@
>>  /// Conversions - Overload set containing the conversion functions
>>  /// of this C++ class (but not its inherited conversion
>>  /// functions). Each of the entries in this overload set is a
>> -  /// CXXConversionDecl.
>> +  /// CXXConversionDecl.
>>  OverloadedFunctionDecl Conversions;
>>
>> +  /// VisibleConversions - Overload set containing the conversion  
>> functions
>> +  /// of this C++ class and all those inherited conversion  
>> functions that
>> +  /// are visible in this class. Each of the entries in this  
>> overload set is
>> +  /// a CXXConversionDecl or a FunctionTemplateDecl.
>> +  OverloadedFunctionDecl VisibleConversions;
>> +
>>  /// \brief The template or declaration that this declaration
>>  /// describes or was instantiated from, respectively.
>>  ///
>> @@ -570,6 +576,20 @@
>>    return &Conversions;
>>  }
>>
>> +  /// getVisibleConversionFunctions - get all conversion functions  
>> visible
>> +  /// in current class; including conversion function templates.
>> +  OverloadedFunctionDecl *getVisibleConversionFunctions(ASTContext  
>> &Context,
>> +                                                         
>> CXXRecordDecl *RD);
>
> The "RD" parameter is an implementation detail; it shouldn't leak  
> into the interface. Please provide a version of  
> getVisibleConversionFunctions that doesn't have this parameter, so  
> that clients don't have to worry about it.

Done.

>
>
>> +  /// addVisibleConversionFunction - Add a new conversion function  
>> to the
>> +  /// list of visible conversion functions.
>> +  void addVisibleConversionFunction(ASTContext &Context,
>> +                                    CXXConversionDecl *ConvDecl);
>> +
>> +  /// \brief Add a new conversion function template to the list of  
>> visible
>> +  /// conversion functions.
>> +  void addVisibleConversionFunction(ASTContext &Context,
>> +                                    FunctionTemplateDecl *ConvDecl);
>> +
>
> In all three of the new functions, you can remove the ASTContext  
> parameter. Instead, use Decl::getASTContext().
Done. There are more and I will clean them up shortly.

>
>
>> +/// getVisibleConversionFunctions - get all conversion functions  
>> visible
>> +/// in current class; including conversion function templates.
>> +OverloadedFunctionDecl *
>> +CXXRecordDecl::getVisibleConversionFunctions(ASTContext &Context,
>> +                                             CXXRecordDecl *RD) {
>> +  // If visible conversion list is already evaluated, return it.
>> +  if (RD == this &&
>> +      VisibleConversions.function_begin() !=  
>> VisibleConversions.function_end())
>> +    return &VisibleConversions;
>
> Checking whether VisibleConversions is empty isn't the same as  
> checking whether we've already tried to compute visible conversions.  
> With this formulation, we could spend a lot of time traversing a  
> class hierarchy that has no user-defined conversions anywhere in it.  
> Why not have a ComputedVisibleConversions bit in the CXXRecordDecl?

Good catch, oversight on my part. Fixed.

>
>
>> +  QualType ClassType = Context.getTypeDeclType(this);
>> +  if (const RecordType *Record = ClassType->getAs<RecordType>()) {
>> +    OverloadedFunctionDecl *Conversions
>> +      = cast<CXXRecordDecl>(Record->getDecl())- 
>> >getConversionFunctions();
>> +    for (OverloadedFunctionDecl::function_iterator
>> +         Func = Conversions->function_begin(),
>> +         FuncEnd = Conversions->function_end();
>> +         Func != FuncEnd; ++Func) {
>> +      if (FunctionTemplateDecl *ConversionTemplate =
>> +            dyn_cast<FunctionTemplateDecl>(*Func)) {
>> +        RD->addVisibleConversionFunction(Context,  
>> ConversionTemplate);
>> +        continue;
>> +      }
>
> Conversion templates can shadow other conversion templates, too, e.g.,
>
>  struct Base {
>    template<typename T> operator T*() const;
>  };
>
>  struct Derived : Base {
>    template<typename T> operator T*() const; // hides base conversion
>  };
>
> so we'll need to check that as well.
We now do. Added a test case for this.

>
>
>> +      CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
>> +      bool Candidate = true;
>> +      // Only those conversions not exact match of conversions in  
>> current
>> +      // class are candidateconversion routines.
>> +      if (RD != this) {
>> +        OverloadedFunctionDecl *TopConversions = RD- 
>> >getConversionFunctions();
>> +        QualType ConvType = Context.getCanonicalType(Conv- 
>> >getType());
>> +        for (OverloadedFunctionDecl::function_iterator
>> +             TFunc = TopConversions->function_begin(),
>> +             TFuncEnd = TopConversions->function_end();
>> +             TFunc != TFuncEnd; ++TFunc) {
>> +          CXXConversionDecl *TopConv =  
>> cast<CXXConversionDecl>(*TFunc);
>
> Can't *TFunc be a FunctionTemplateDecl? It looks like it from the  
> code below, under
Yes, fixed.

>
>
>  if (Candidate)
>
>> +          QualType TConvType = Context.getCanonicalType(TopConv- 
>> >getType());
>> +          if (ConvType == TConvType) {
>> +            Candidate = false;
>> +            break;
>> +          }
>> +        }
>> +      }
>
> This is an O(n^2) algorithm :(
Yes. I have added a FIXME. Will look at it.

>
>
> Also, you'll need to check cv-qualifiers on the functions. For  
> example, I don't think there's any hiding in this example:
>
>  struct Base {
>    operator int();
>  };
>
>  struct Derived : Base {
>    operator int() const; // not the same function as Base's non- 
> const operator int()
>  };
>

This just works because QualType for the two conversions don;t match.  
However, we have no overload resolution
to select one over the other in a delete statement. I have added a  
test case and FIXME in the test case for future work.

> Finally, there may be multiple bases with the same conversion. Both  
> conversion functions need to show up, e.g.,
>
>  struct Base1 {
>    operator int();
>  };
>
>  struct Base2 {
>    operator int();
>  };
>
>  struct Derived : Base1, Base2 {
>    // two operator int()s are visible here
>  };
>

Yes.

Fixed in TOT: http://llvm.org/viewvc/llvm-project?view=rev&revision=81618

- Fariborz

>  - Doug




More information about the cfe-commits mailing list