[cfe-dev] Bug in clang parsing pointer to an array in function parameter list

Steve Naroff snaroff at apple.com
Sun Sep 9 15:52:41 PDT 2007


On Sep 9, 2007, at 3:32 PM, Justin Handville wrote:

> With the following patch, I can now compile and execute this source  
> file:
>
> int puts(char*);
>
> int main(int argc, char* argv[])
> {
>   char* foo = argv[0];
>
>   puts(foo);
>
>   return 0;
> }
>

Justin,

I'm a bit confused. The front-end (Sema::ParseParamDeclarator)  
already converts argv from "char *[]" to "char **".

See the "DeclRefExpr" node below (on line 6).

I don't know why the code generator would need to fiddle with this.

Chris will need to advise...

snaroff

[dylan:~/llvm/tools/clang] admin% ../../Debug/bin/clang justin.c - 
parse-ast-dump

int puts(char *);

int main(int argc, char *argv[])
(CompoundStmt 0x3105ed0 <justin.c:5:1, line:11:1>
   (DeclStmt 0x3105bf0 <:0:0>
     0x3105dd0 "char *foo =
       (ArraySubscriptExpr 0x3105db0 <justin.c:6:15, col:21> 'char *'
         (DeclRefExpr 0x3105d70 <col:15> 'char **' Decl='argv'  
0x3105d40)
         (IntegerLiteral 0x3105d90 <col:20> 'int' 0))")
   (CallExpr 0x3105e70 <line:8:3, col:11> 'int'
     (ImplicitCastExpr 0x3105e60 <col:3> 'int (*)(char *)'
       (DeclRefExpr 0x3105e00 <col:3> 'int (char *)' Decl='puts'  
0x3105c20))
     (DeclRefExpr 0x3105e20 <col:8> 'char *' Decl='foo' 0x3105dd0))
   (ReturnStmt 0x3105ec0 <line:10:3, col:10>
     (IntegerLiteral 0x3105ea0 <col:10> 'int' 0)))


> Here's the patch.  I'm curious to see if this will work in all cases.
> I am still adding test cases to the build, so it is a bit
> experimental:
>
> ndex: CodeGen/CodeGenFunction.h
> ===================================================================
> --- CodeGen/CodeGenFunction.h   (revision 41790)
> +++ CodeGen/CodeGenFunction.h   (working copy)
> @@ -237,6 +237,11 @@
>    };
>    llvm::SmallVector<BreakContinue, 8> BreakContinueStack;
>
> +  static bool
> +  isCompatibleDeclPointerType(
> +    const llvm::Type* Arg,
> +    const llvm::Type* DeclPtr);
> +
>  public:
>    CodeGenFunction(CodeGenModule &cgm);
>
> Index: CodeGen/CGDecl.cpp
> ===================================================================
> --- CodeGen/CGDecl.cpp  (revision 41790)
> +++ CodeGen/CGDecl.cpp  (working copy)
> @@ -96,11 +96,69 @@
>    }
>  }
>
> +bool
> +CodeGenFunction::isCompatibleDeclPointerType(
> +  const llvm::Type* ArgType,
> +  const llvm::Type* DeclType)
> +{
> +  if(
> +      ArgType->getTypeID() != llvm::Type::PointerTyID
> +   || DeclType->getTypeID() != llvm::Type::PointerTyID)
> +  {
> +    return false;
> +  }
> +
> +  while(
> +      ArgType->getNumContainedTypes() == 1
> +   && DeclType->getNumContainedTypes() == 1)
> +  {
> +    const llvm::Type* ArgContainedType = ArgType->getContainedType 
> (0);
> +    const llvm::Type* DeclContainedType = DeclType- 
> >getContainedType(0);
> +
> +    //if the two contained types point to the same
> +    //location, then these pointer types are compatible
> +    if(
> +      ArgContainedType == DeclContainedType)
> +    {
> +      return true;
> +    }
> +    //is the pointer indirection level different?
> +    else if(
> +      ArgContainedType->getNumContainedTypes() !=
> +        DeclContainedType->getNumContainedTypes())
> +    {
> +      break;
> +    }
> +    //are these compatible pointer / array types?
> +    else if(
> +        llvm::SequentialType::classof(ArgContainedType)
> +     && llvm::SequentialType::classof(DeclContainedType))
> +    {
> +      if( ArgContainedType->getNumContainedTypes() != 1 )
> +      {
> +        //FIXME will this ever happen with arrays / pointers?
> +        break;
> +      }
> +
> +      ArgType = ArgContainedType;
> +      DeclType = DeclContainedType;
> +    }
> +    else
> +    {
> +      //one or more of these is something other than an array /  
> pointer
> +      break;
> +    }
> +  }
> +
> +  return false;
> +}
> +
>  /// Emit an alloca for the specified parameter and set up  
> LocalDeclMap.
>  void CodeGenFunction::EmitParmDecl(const ParmVarDecl &D,  
> llvm::Value *Arg) {
>    QualType Ty = D.getCanonicalType();
>
>    llvm::Value *DeclPtr;
> +
>    if (!Ty->isConstantSizeType(getContext())) {
>      // Variable sized values always are passed by-reference.
>      DeclPtr = Arg;
> @@ -111,7 +169,19 @@
>        // TODO: Alignment
>        DeclPtr = new llvm::AllocaInst(LTy, 0, std::string(D.getName 
> ())+".addr",
>                                       AllocaInsertPt);
> -
> +
> +      //do we need to perform an implicit conversion?
> +      if( isCompatibleDeclPointerType(Arg->getType(), DeclPtr- 
> >getType()) )
> +      {
> +        llvm::Value* CastPtr =
> +          Builder.CreateBitCast(
> +            Arg,
> +            LTy,
> +            (std::string(D.getName()) + ".implconv").c_str());
> +
> +        Arg = CastPtr;
> +      }
> +
>        // Store the initial value into the alloca.
>        Builder.CreateStore(Arg, DeclPtr);
>      } else {
>
> On 9/9/07, Justin Handville <uniheliodem at gmail.com> wrote:
>> Perhaps the better question to ask is where should this transform  
>> occur?
>>
>> On 9/9/07, Justin Handville <uniheliodem at gmail.com> wrote:
>>> The following code snippet generates an assert when compiled with
>>> clang -emit-llvm
>>>
>>> int main(int argc, char* argv[])
>>> {
>>>   return 0;
>>> }
>>>
>>> Assert:
>>>
>>> Assertion failed: (getOperand(0)->getType() ==
>>> cast<PointerType>(getOperand(1)->getType())->getElementType() &&  
>>> "Ptr
>>> must be a pointer to Val type!"), function AssertOK, file
>>> Instructions.cpp, line 796.
>>>
>>> The problem here is at line 116 of CGDecl.cpp:
>>>
>>>     if (LTy->isFirstClassType()) {
>>>       // TODO: Alignment
>>>       DeclPtr = new llvm::AllocaInst(LTy, 0, std::string(D.getName 
>>> ())+".addr",
>>>                                      AllocaInsertPt);
>>>
>>>       // Store the initial value into the alloca.
>>>       Builder.CreateStore(Arg, DeclPtr);  //attempting to store
>>> char*[] as char**
>>>
>>> The problem is that llvm treats char*[] and char** as two distinct
>>> types as far as I can tell.  EmitParmDecl should convert the type  
>>> to a
>>> char** before calling CreateStore, since this is how the argument
>>> would be passed in C ABI.
>>>
>>> I assume that a transform step should be added before the  
>>> CreateStore
>>> that could normalize the argument to match the declptr.  I assume a
>>> good approach would be to descend through both Arg and DeclPtr,
>>> transforming Arg to match DeclPtr where compatible, or raising an
>>> appropriate diagnostic error if such a transformation is not  
>>> possible.
>>>
>>> If I can get some approval that this route would work in this case,
>>> then I will go ahead and submit the patch.
>>>
>>> Thanks,
>>> Justin
>>>
>>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev




More information about the cfe-dev mailing list