From d7e7b8e4115d34c42b3ba479ff7615a7efbf25fc Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Tue, 24 Feb 2009 22:18:39 +0000 Subject: [PATCH] first wave of fixes for @encode sema support. This is part of PR3648. The big difference here is that (like string literal) @encode has array type, not pointer type. llvm-svn: 65391 --- clang/include/clang/AST/ExprObjC.h | 4 ++- clang/lib/AST/Expr.cpp | 4 ++- clang/lib/AST/ExprConstant.cpp | 1 + clang/lib/CodeGen/CGExpr.cpp | 34 ++++++++++++++++---------- clang/lib/CodeGen/CGExprConstant.cpp | 27 +++++++++++++++++--- clang/lib/CodeGen/CGExprScalar.cpp | 21 +++------------- clang/lib/CodeGen/CodeGenFunction.h | 1 + clang/lib/CodeGen/CodeGenModule.cpp | 28 +++++++++++++++------ clang/lib/CodeGen/CodeGenModule.h | 5 ++++ clang/lib/Sema/SemaDecl.cpp | 4 +-- clang/lib/Sema/SemaExprObjC.cpp | 15 ++++++++++-- clang/test/CodeGenObjC/encode-test-3.m | 7 ++++-- 12 files changed, 101 insertions(+), 50 deletions(-) diff --git a/clang/include/clang/AST/ExprObjC.h b/clang/include/clang/AST/ExprObjC.h index 9483833a6e7f..f74e2ab2f93e 100644 --- a/clang/include/clang/AST/ExprObjC.h +++ b/clang/include/clang/AST/ExprObjC.h @@ -54,7 +54,9 @@ public: static ObjCStringLiteral* CreateImpl(llvm::Deserializer& D, ASTContext& C); }; -/// ObjCEncodeExpr, used for @encode in Objective-C. +/// ObjCEncodeExpr, used for @encode in Objective-C. @encode has the same type +/// and behavior as StringLiteral except that the string initializer is obtained +/// from ASTContext with the encoding type as an argument. class ObjCEncodeExpr : public Expr { QualType EncType; SourceLocation AtLoc, RParenLoc; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 3aea3e324ba4..d551eac3006f 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -478,7 +478,8 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { // the type looks fine, now check the expression switch (getStmtClass()) { - case StringLiteralClass: // C99 6.5.1p4 + case StringLiteralClass: // C99 6.5.1p4 + case ObjCEncodeExprClass: // @encode behaves like its string in every way. return LV_Valid; case ArraySubscriptExprClass: // C99 6.5.3p4 (e1[e2] == (*((e1)+(e2)))) // For vectors, make sure base is an lvalue (i.e. not a function call). @@ -829,6 +830,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { switch (getStmtClass()) { default: break; case StringLiteralClass: + case ObjCEncodeExprClass: return true; case CompoundLiteralExprClass: { // This handles gcc's extension that allows global initializers like diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index bfba5984b036..65a107bb236d 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -153,6 +153,7 @@ public: APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E); APValue VisitMemberExpr(MemberExpr *E); APValue VisitStringLiteral(StringLiteral *E) { return APValue(E, 0); } + APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E, 0); } APValue VisitArraySubscriptExpr(ArraySubscriptExpr *E); APValue VisitUnaryDeref(UnaryOperator *E); // FIXME: Missing: __extension__, __real__, __imag__, __builtin_choose_expr diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 0449900a0f88..e353ab49c303 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -148,6 +148,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitPredefinedLValue(cast(E)); case Expr::StringLiteralClass: return EmitStringLiteralLValue(cast(E)); + case Expr::ObjCEncodeExprClass: + return EmitObjCEncodeExprLValue(cast(E)); case Expr::CXXConditionDeclExprClass: return EmitCXXConditionDeclLValue(cast(E)); @@ -668,7 +670,8 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { default: assert(0 && "Unknown unary operator lvalue!"); case UnaryOperator::Deref: { - QualType T = E->getSubExpr()->getType()->getAsPointerType()->getPointeeType(); + QualType T = + E->getSubExpr()->getType()->getAsPointerType()->getPointeeType(); LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()), ExprTy->getAsPointerType()->getPointeeType() .getCVRQualifiers(), @@ -697,22 +700,27 @@ LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) { return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromLiteral(E), 0); } +LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) { + return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromObjCEncode(E), 0); +} + + LValue CodeGenFunction::EmitPredefinedFunctionName(unsigned Type) { std::string GlobalVarName; switch (Type) { - default: - assert(0 && "Invalid type"); - case PredefinedExpr::Func: - GlobalVarName = "__func__."; - break; - case PredefinedExpr::Function: - GlobalVarName = "__FUNCTION__."; - break; - case PredefinedExpr::PrettyFunction: - // FIXME:: Demangle C++ method names - GlobalVarName = "__PRETTY_FUNCTION__."; - break; + default: + assert(0 && "Invalid type"); + case PredefinedExpr::Func: + GlobalVarName = "__func__."; + break; + case PredefinedExpr::Function: + GlobalVarName = "__FUNCTION__."; + break; + case PredefinedExpr::PrettyFunction: + // FIXME:: Demangle C++ method names + GlobalVarName = "__PRETTY_FUNCTION__."; + break; } std::string FunctionName; diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 1141c0da8aa4..487b274f1c77 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -76,7 +76,10 @@ public: cast(ConvertType(ILE->getType())); unsigned NumInitElements = ILE->getNumInits(); // FIXME: Check for wide strings - if (NumInitElements > 0 && isa(ILE->getInit(0)) && + // FIXME: Check for NumInitElements exactly equal to 1?? + if (NumInitElements > 0 && + (isa(ILE->getInit(0)) || + isa(ILE->getInit(0))) && ILE->getType()->getArrayElementTypeNoTypeQual()->isCharType()) return Visit(ILE->getInit(0)); const llvm::Type *ElemTy = AType->getElementType(); @@ -346,12 +349,26 @@ public: llvm::Constant *VisitStringLiteral(StringLiteral *E) { assert(!E->getType()->isPointerType() && "Strings are always arrays"); - // Otherwise this must be a string initializing an array in a static - // initializer. Don't emit it as the address of the string, emit the string - // data itself as an inline array. + // This must be a string initializing an array in a static initializer. + // Don't emit it as the address of the string, emit the string data itself + // as an inline array. return llvm::ConstantArray::get(CGM.GetStringForStringLiteral(E), false); } + llvm::Constant *VisitObjCEncodeExpr(ObjCEncodeExpr *E) { + // This must be an @encode initializing an array in a static initializer. + // Don't emit it as the address of the string, emit the string data itself + // as an inline array. + std::string Str; + CGM.getContext().getObjCEncodingForType(E->getEncodedType(), Str); + const ConstantArrayType *CAT = cast(E->getType()); + + // Resize the string to the right size, adding zeros at the end, or + // truncating as needed. + Str.resize(CAT->getSize().getZExtValue(), '\0'); + return llvm::ConstantArray::get(Str, false); + } + llvm::Constant *VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } @@ -398,6 +415,8 @@ public: } case Expr::StringLiteralClass: return CGM.GetAddrOfConstantStringFromLiteral(cast(E)); + case Expr::ObjCEncodeExprClass: + return CGM.GetAddrOfConstantStringFromObjCEncode(cast(E)); case Expr::ObjCStringLiteralClass: { ObjCStringLiteral* SL = cast(E); std::string S(SL->getString()->getStrData(), diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index a271e76bf1a5..4a2fe997d36e 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -165,6 +165,10 @@ public: return EmitLoadOfLValue(E); } Value *VisitStringLiteral(Expr *E) { return EmitLValue(E).getAddress(); } + Value *VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { + return EmitLValue(E).getAddress(); + } + Value *VisitPredefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); } Value *VisitInitListExpr(InitListExpr *E) { @@ -329,7 +333,6 @@ public: Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) { return CGF.EmitObjCStringLiteral(E); } - Value *VisitObjCEncodeExpr(const ObjCEncodeExpr *E); }; } // end anonymous namespace. @@ -1385,22 +1388,6 @@ Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { return Builder.CreateLoad(ArgPtr); } -Value *ScalarExprEmitter::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { - std::string str; - CGF.getContext().getObjCEncodingForType(E->getEncodedType(), str); - - llvm::Constant *C = llvm::ConstantArray::get(str); - C = new llvm::GlobalVariable(C->getType(), true, - llvm::GlobalValue::InternalLinkage, - C, ".str", &CGF.CGM.getModule()); - llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty); - llvm::Constant *Zeros[] = { Zero, Zero }; - C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2); - - return C; -} - - Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *BE) { llvm::Constant *C = CGF.BuildBlockLiteralTmp(BE); return C; diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index e2b4fedfd560..f13e79ae1d69 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -628,6 +628,7 @@ public: LValue EmitVAArgExprLValue(const VAArgExpr *E); LValue EmitDeclRefLValue(const DeclRefExpr *E); LValue EmitStringLiteralLValue(const StringLiteral *E); + LValue EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E); LValue EmitPredefinedFunctionName(unsigned Type); LValue EmitPredefinedLValue(const PredefinedExpr *E); LValue EmitUnaryOpLValue(const UnaryOperator *E); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index ccba324aa024..95490df46ba9 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1098,6 +1098,21 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) { return GetAddrOfConstantString(GetStringForStringLiteral(S)); } +/// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant +/// array for the given ObjCEncodeExpr node. +llvm::Constant * +CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) { + std::string Str; + getContext().getObjCEncodingForType(E->getEncodedType(), Str); + + llvm::Constant *C = llvm::ConstantArray::get(Str); + C = new llvm::GlobalVariable(C->getType(), true, + llvm::GlobalValue::InternalLinkage, + C, ".str", &getModule()); + return C; +} + + /// GenerateWritableString -- Creates storage for a string literal. static llvm::Constant *GenerateStringLiteral(const std::string &str, bool constant, @@ -1107,13 +1122,10 @@ static llvm::Constant *GenerateStringLiteral(const std::string &str, llvm::Constant *C = llvm::ConstantArray::get(str, false); // Create a global variable for this string - C = new llvm::GlobalVariable(C->getType(), constant, - llvm::GlobalValue::InternalLinkage, - C, - GlobalName ? GlobalName : ".str", - &CGM.getModule()); - - return C; + return new llvm::GlobalVariable(C->getType(), constant, + llvm::GlobalValue::InternalLinkage, + C, GlobalName ? GlobalName : ".str", + &CGM.getModule()); } /// GetAddrOfConstantString - Returns a pointer to a character array @@ -1134,7 +1146,7 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str, ConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]); if (Entry.getValue()) - return Entry.getValue(); + return Entry.getValue(); // Create a global variable for this. llvm::Constant *C = GenerateStringLiteral(str, true, *this, GlobalName); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 913e4bc4b158..3a98bb7d438d 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -41,6 +41,7 @@ namespace clang { class ObjCImplementationDecl; class ObjCCategoryImplDecl; class ObjCProtocolDecl; + class ObjCEncodeExpr; class BlockExpr; class Decl; class Expr; @@ -212,6 +213,10 @@ public: /// for the given string literal. llvm::Constant *GetAddrOfConstantStringFromLiteral(const StringLiteral *S); + /// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant + /// array for the given ObjCEncodeExpr node. + llvm::Constant *GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *); + /// GetAddrOfConstantString - Returns a pointer to a character array /// containing the literal. This contents are exactly that of the given /// string, i.e. it will not be null terminated automatically; see diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2af6ab1bb32f..373296fb58e9 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1178,8 +1178,8 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, InitListExpr *InitList = dyn_cast(Init); if (!InitList) { // FIXME: Handle wide strings - if (StringLiteral *strLiteral = IsStringLiteralInit(Init, DeclType)) - return CheckStringLiteralInit(strLiteral, DeclType); + if (StringLiteral *StrLiteral = IsStringLiteralInit(Init, DeclType)) + return CheckStringLiteralInit(StrLiteral, DeclType); // C++ [dcl.init]p14: // -- If the destination type is a (possibly cv-qualified) class diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 9bcc81028d2e..7696cf06084b 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -95,8 +95,19 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation RParenLoc) { QualType EncodedType = QualType::getFromOpaquePtr(ty); - QualType Ty = Context.getPointerType(Context.CharTy); - return new (Context) ObjCEncodeExpr(Ty, EncodedType, AtLoc, RParenLoc); + std::string Str; + Context.getObjCEncodingForType(EncodedType, Str); + + // The type of @encode is the same as the type of the corresponding string, + // which is an array type. + QualType StrTy = Context.CharTy; + // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). + if (getLangOptions().CPlusPlus) + StrTy.addConst(); + StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1), + ArrayType::Normal, 0); + + return new (Context) ObjCEncodeExpr(StrTy, EncodedType, AtLoc, RParenLoc); } Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, diff --git a/clang/test/CodeGenObjC/encode-test-3.m b/clang/test/CodeGenObjC/encode-test-3.m index 8bd4421d6c15..c10db091ccdd 100644 --- a/clang/test/CodeGenObjC/encode-test-3.m +++ b/clang/test/CodeGenObjC/encode-test-3.m @@ -2,10 +2,13 @@ // RUN: grep -e "\^i" %t | count 1 && // RUN: grep -e "\[0i\]" %t | count 1 -int main() -{ +int main() { int n; const char * inc = @encode(int[]); const char * vla = @encode(int[n]); } + +// PR3648 +int a[sizeof(@encode(int)) == 2 ? 1 : -1]; // Type is char[2] +char (*c)[2] = &@encode(int); // @encode is an lvalue