diff options
Diffstat (limited to 'lib')
128 files changed, 7725 insertions, 5149 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index cc7055d..74e74e7 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -55,44 +56,43 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, } ASTContext::~ASTContext() { - // Deallocate all the types. - while (!Types.empty()) { - Types.back()->Destroy(*this); - Types.pop_back(); - } + if (FreeMemory) { + // Deallocate all the types. + while (!Types.empty()) { + Types.back()->Destroy(*this); + Types.pop_back(); + } - { - llvm::FoldingSet<ExtQuals>::iterator - I = ExtQualNodes.begin(), E = ExtQualNodes.end(); - while (I != E) + for (llvm::FoldingSet<ExtQuals>::iterator + I = ExtQualNodes.begin(), E = ExtQualNodes.end(); I != E; ) { + // Increment in loop to prevent using deallocated memory. Deallocate(&*I++); + } } - { - llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>::iterator - I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); - while (I != E) { - ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second); - delete R; - } + for (llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>::iterator + I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); I != E; ) { + // Increment in loop to prevent using deallocated memory. + ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second); + delete R; } - { - llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*>::iterator - I = ObjCLayouts.begin(), E = ObjCLayouts.end(); - while (I != E) { - ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second); - delete R; - } + for (llvm::DenseMap<const ObjCContainerDecl*, + const ASTRecordLayout*>::iterator + I = ObjCLayouts.begin(), E = ObjCLayouts.end(); I != E; ) { + // Increment in loop to prevent using deallocated memory. + ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second); + delete R; } // Destroy nested-name-specifiers. for (llvm::FoldingSet<NestedNameSpecifier>::iterator NNS = NestedNameSpecifiers.begin(), NNSEnd = NestedNameSpecifiers.end(); - NNS != NNSEnd; - /* Increment in loop */) + NNS != NNSEnd; ) { + // Increment in loop to prevent using deallocated memory. (*NNS++).Destroy(*this); + } if (GlobalNestedNameSpecifier) GlobalNestedNameSpecifier->Destroy(*this); @@ -694,13 +694,6 @@ ASTContext::getTypeInfo(const Type *T) { break; } break; - case Type::FixedWidthInt: - // FIXME: This isn't precisely correct; the width/alignment should depend - // on the available types for the target - Width = cast<FixedWidthIntType>(T)->getWidth(); - Width = std::max(llvm::NextPowerOf2(Width - 1), (uint64_t)8); - Align = Width; - break; case Type::ObjCObjectPointer: Width = Target.getPointerWidth(0); Align = Target.getPointerAlign(0); @@ -818,6 +811,15 @@ ASTContext::getTypeInfo(const Type *T) { return std::make_pair(Width, Align); } +/// getTypeSizeInChars - Return the size of the specified type, in characters. +/// This method does not work on incomplete types. +CharUnits ASTContext::getTypeSizeInChars(QualType T) { + return CharUnits::fromRaw(getTypeSize(T) / getCharWidth()); +} +CharUnits ASTContext::getTypeSizeInChars(const Type *T) { + return CharUnits::fromRaw(getTypeSize(T) / getCharWidth()); +} + /// getPreferredTypeAlign - Return the "preferred" alignment of the specified /// type for the current target in bits. This can be different than the ABI /// alignment in cases where it is beneficial for performance to overalign @@ -1056,9 +1058,7 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, // Add in synthesized ivar count if laying out an implementation. if (Impl) { - unsigned FieldCount = D->ivar_size(); unsigned SynthCount = CountSynthesizedIvars(D); - FieldCount += SynthCount; // If there aren't any sythesized ivars then reuse the interface // entry. Note we can't cache this because we simply free all // entries later; however we shouldn't look up implementations @@ -1267,15 +1267,6 @@ QualType ASTContext::getComplexType(QualType T) { return QualType(New, 0); } -QualType ASTContext::getFixedWidthIntType(unsigned Width, bool Signed) { - llvm::DenseMap<unsigned, FixedWidthIntType*> &Map = Signed ? - SignedFixedWidthIntTypes : UnsignedFixedWidthIntTypes; - FixedWidthIntType *&Entry = Map[Width]; - if (!Entry) - Entry = new FixedWidthIntType(Width, Signed); - return QualType(Entry, 0); -} - /// getPointerType - Return the uniqued reference to the type for a pointer to /// the specified type. QualType ASTContext::getPointerType(QualType T) { @@ -2381,6 +2372,42 @@ CanQualType ASTContext::getCanonicalType(QualType T) { VAT->getBracketsRange())); } +QualType ASTContext::getUnqualifiedArrayType(QualType T, + Qualifiers &Quals) { + assert(T.isCanonical() && "Only operates on canonical types"); + if (!isa<ArrayType>(T)) { + Quals = T.getLocalQualifiers(); + return T.getLocalUnqualifiedType(); + } + + assert(!T.hasQualifiers() && "canonical array type has qualifiers!"); + const ArrayType *AT = cast<ArrayType>(T); + QualType Elt = AT->getElementType(); + QualType UnqualElt = getUnqualifiedArrayType(getCanonicalType(Elt), Quals); + if (Elt == UnqualElt) + return T; + + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) { + return getConstantArrayType(UnqualElt, CAT->getSize(), + CAT->getSizeModifier(), 0); + } + + if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(T)) { + return getIncompleteArrayType(UnqualElt, IAT->getSizeModifier(), 0); + } + + if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(T)) { + return getVariableArrayType(UnqualElt, VAT->getSizeExpr()->Retain(), + VAT->getSizeModifier(), 0, + SourceRange()); + } + + const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T); + return getDependentSizedArrayType(UnqualElt, DSAT->getSizeExpr()->Retain(), + DSAT->getSizeModifier(), 0, + SourceRange()); +} + DeclarationName ASTContext::getNameForTemplate(TemplateName Name) { if (TemplateDecl *TD = Name.getAsTemplateDecl()) return TD->getDeclName(); @@ -2682,12 +2709,6 @@ unsigned ASTContext::getIntegerRank(Type *T) { if (T->isSpecificBuiltinType(BuiltinType::Char32)) T = getFromTargetType(Target.getChar32Type()).getTypePtr(); - // There are two things which impact the integer rank: the width, and - // the ordering of builtins. The builtin ordering is encoded in the - // bottom three bits; the width is encoded in the bits above that. - if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T)) - return FWIT->getWidth() << 3; - switch (cast<BuiltinType>(T)->getKind()) { default: assert(0 && "getIntegerRank(): not a built-in integer"); case BuiltinType::Bool: @@ -4500,9 +4521,6 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { return QualType(); } - case Type::FixedWidthInt: - // Distinct fixed-width integers are not compatible. - return QualType(); case Type::TemplateSpecialization: assert(false && "Dependent types have no size"); break; @@ -4518,9 +4536,6 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { unsigned ASTContext::getIntWidth(QualType T) { if (T->isBooleanType()) return 1; - if (FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) { - return FWIT->getWidth(); - } if (EnumType *ET = dyn_cast<EnumType>(T)) T = ET->getDecl()->getIntegerType(); // For builtin types, just use the standard type sizing method diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 0f0b22d..5aecf87 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -16,6 +16,7 @@ add_clang_library(clangAST Expr.cpp ExprCXX.cpp ExprConstant.cpp + FullExpr.cpp InheritViz.cpp NestedNameSpecifier.cpp ParentMap.cpp diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 4d0d422..e112fa3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -19,6 +19,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/Stmt.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" @@ -91,6 +92,34 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg); } +Expr *ParmVarDecl::getDefaultArg() { + assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!"); + assert(!hasUninstantiatedDefaultArg() && + "Default argument is not yet instantiated!"); + + Expr *Arg = getInit(); + if (CXXExprWithTemporaries *E = dyn_cast_or_null<CXXExprWithTemporaries>(Arg)) + return E->getSubExpr(); + + return Arg; +} + +unsigned ParmVarDecl::getNumDefaultArgTemporaries() const { + if (const CXXExprWithTemporaries *E = + dyn_cast<CXXExprWithTemporaries>(getInit())) + return E->getNumTemporaries(); + + return 0; +} + +CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) { + assert(getNumDefaultArgTemporaries() && + "Default arguments does not have any temporaries!"); + + CXXExprWithTemporaries *E = cast<CXXExprWithTemporaries>(getInit()); + return E->getTemporary(i); +} + SourceRange ParmVarDecl::getDefaultArgRange() const { if (const Expr *E = getInit()) return E->getSourceRange(); @@ -183,6 +212,9 @@ TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, return new (C) TypedefDecl(DC, L, Id, TInfo); } +// Anchor TypedefDecl's vtable here. +TypedefDecl::~TypedefDecl() {} + EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation TKL, EnumDecl *PrevDecl) { @@ -426,11 +458,6 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { return getNameAsString(); while (Ctx) { - if (Ctx->isFunctionOrMethod()) - // FIXME: That probably will happen, when D was member of local - // scope class/struct/union. How do we handle this case? - break; - if (const ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); @@ -440,6 +467,48 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { TemplateArgs.flat_size(), P); Names.push_back(Spec->getIdentifier()->getNameStart() + TemplateArgsStr); + } else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(Ctx)) { + if (ND->isAnonymousNamespace()) + Names.push_back("<anonymous namespace>"); + else + Names.push_back(ND->getNameAsString()); + } else if (const RecordDecl *RD = dyn_cast<RecordDecl>(Ctx)) { + if (!RD->getIdentifier()) { + std::string RecordString = "<anonymous "; + RecordString += RD->getKindName(); + RecordString += ">"; + Names.push_back(RecordString); + } else { + Names.push_back(RD->getNameAsString()); + } + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Ctx)) { + std::string Proto = FD->getNameAsString(); + + const FunctionProtoType *FT = 0; + if (FD->hasWrittenPrototype()) + FT = dyn_cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>()); + + Proto += "("; + if (FT) { + llvm::raw_string_ostream POut(Proto); + unsigned NumParams = FD->getNumParams(); + for (unsigned i = 0; i < NumParams; ++i) { + if (i) + POut << ", "; + std::string Param; + FD->getParamDecl(i)->getType().getAsStringInternal(Param, P); + POut << Param; + } + + if (FT->isVariadic()) { + if (NumParams > 0) + POut << ", "; + POut << "..."; + } + } + Proto += ")"; + + Names.push_back(Proto); } else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx)) Names.push_back(ND->getNameAsString()); else diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 292a3ed..bbbb19a 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -164,8 +164,7 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context, if (isa<FunctionTemplateDecl>(*Con)) continue; - if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context, - FoundTQs)) { + if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(FoundTQs)) { if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) || (!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const))) return cast<CXXConstructorDecl>(*Con); @@ -246,7 +245,7 @@ CXXRecordDecl::addedConstructor(ASTContext &Context, // Note when we have a user-declared copy constructor, which will // suppress the implicit declaration of a copy constructor. - if (ConDecl->isCopyConstructor(Context)) { + if (ConDecl->isCopyConstructor()) { UserDeclaredCopyConstructor = true; // C++ [class.copy]p6: @@ -757,8 +756,7 @@ bool CXXConstructorDecl::isDefaultConstructor() const { } bool -CXXConstructorDecl::isCopyConstructor(ASTContext &Context, - unsigned &TypeQuals) const { +CXXConstructorDecl::isCopyConstructor(unsigned &TypeQuals) const { // C++ [class.copy]p2: // A non-template constructor for class X is a copy constructor // if its first parameter is of type X&, const X&, volatile X& or @@ -779,6 +777,8 @@ CXXConstructorDecl::isCopyConstructor(ASTContext &Context, return false; // Is it a reference to our class type? + ASTContext &Context = getASTContext(); + CanQualType PointeeType = Context.getCanonicalType(ParamRefType->getPointeeType()); CanQualType ClassTy @@ -874,7 +874,11 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, isa<CXXRecordDecl>(D) || isa<FunctionTemplateDecl>(D) || isa<ClassTemplateDecl>(D)); - assert(D->getFriendObjectKind()); + + // As a temporary hack, we permit template instantiation to point + // to the original declaration when instantiating members. + assert(D->getFriendObjectKind() || + (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind())); } #endif diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp index 5bdc881..434bf00 100644 --- a/lib/AST/DeclGroup.cpp +++ b/lib/AST/DeclGroup.cpp @@ -32,6 +32,7 @@ DeclGroup::DeclGroup(unsigned numdecls, Decl** decls) : NumDecls(numdecls) { } void DeclGroup::Destroy(ASTContext& C) { + // Decls are destroyed by the DeclContext. this->~DeclGroup(); C.Deallocate((void*) this); } diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 0ce03c2..60c40e2 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -210,7 +210,7 @@ std::string DeclarationName::getAsString() const { } case CXXOperatorName: { - static const char *OperatorNames[NUM_OVERLOADED_OPERATORS] = { + static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = { 0, #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ Spelling, diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 139e04b..04a6abc 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -174,6 +174,8 @@ std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT, if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { if (MD->isVirtual()) Out << "virtual "; + if (MD->isStatic()) + Out << "static "; } PrintingPolicy Policy(Context.getLangOptions()); @@ -203,6 +205,14 @@ std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT, } Proto += ")"; + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + Qualifiers ThisQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers()); + if (ThisQuals.hasConst()) + Proto += " const"; + if (ThisQuals.hasVolatile()) + Proto += " volatile"; + } + if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD)) AFT->getResultType().getAsStringInternal(Proto, Policy); @@ -398,14 +408,20 @@ void CallExpr::DoDestroy(ASTContext& C) { C.Deallocate(this); } -FunctionDecl *CallExpr::getDirectCallee() { +Decl *CallExpr::getCalleeDecl() { Expr *CEE = getCallee()->IgnoreParenCasts(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) - return dyn_cast<FunctionDecl>(DRE->getDecl()); + return DRE->getDecl(); + if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE)) + return ME->getMemberDecl(); return 0; } +FunctionDecl *CallExpr::getDirectCallee() { + return dyn_cast_or_null<FunctionDecl>(getCalleeDecl()); +} + /// setNumArgs - This changes the number of arguments present in this call. /// Any orphaned expressions are deleted by this, and any new operands are set /// to null. @@ -858,7 +874,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case CXXMemberCallExprClass: { // If this is a direct call, get the callee. const CallExpr *CE = cast<CallExpr>(this); - if (const FunctionDecl *FD = CE->getDirectCallee()) { + if (const Decl *FD = CE->getCalleeDecl()) { // If the callee has attribute pure, const, or warn_unused_result, warn // about it. void foo() { strlen("bar"); } should warn. // @@ -1047,8 +1063,13 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { // -- If E2 is a non-static data member [...]. If E1 is an // lvalue, then E1.E2 is an lvalue. - if (isa<FieldDecl>(Member)) - return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx); + if (isa<FieldDecl>(Member)) { + if (m->isArrow()) + return LV_Valid; + Expr *BaseExp = m->getBase(); + return (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) ? + LV_SubObjCPropertySetting : BaseExp->isLvalue(Ctx); + } // -- If it refers to a static member function [...], then // E1.E2 is an lvalue. @@ -1065,9 +1086,13 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { // Not an lvalue. return LV_InvalidExpression; } - + // C99 6.5.2.3p4 - return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx); + if (m->isArrow()) + return LV_Valid; + Expr *BaseExp = m->getBase(); + return (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) ? + LV_SubObjCPropertySetting : BaseExp->isLvalue(Ctx); } case UnaryOperatorClass: if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref) @@ -1204,6 +1229,16 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; } + case Expr::CXXExprWithTemporariesClass: + return cast<CXXExprWithTemporaries>(this)->getSubExpr()->isLvalue(Ctx); + + case Expr::ObjCMessageExprClass: + if (const ObjCMethodDecl *Method + = cast<ObjCMessageExpr>(this)->getMethodDecl()) + if (Method->getResultType()->isLValueReferenceType()) + return LV_Valid; + break; + default: break; } @@ -1244,6 +1279,7 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { } return MLV_InvalidExpression; case LV_MemberFunction: return MLV_MemberFunction; + case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting; } // The following is illegal: @@ -1996,7 +2032,7 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, QualType retType, ObjCMethodDecl *mproto, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType), SelName(selInfo), + : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; SubExprs = new Stmt*[NumArgs+1]; @@ -2015,7 +2051,7 @@ ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, QualType retType, ObjCMethodDecl *mproto, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType), SelName(selInfo), + : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; SubExprs = new Stmt*[NumArgs+1]; @@ -2033,7 +2069,7 @@ ObjCMessageExpr::ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo, QualType retType, ObjCMethodDecl *mproto, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned nargs) -: Expr(ObjCMessageExprClass, retType), SelName(selInfo), +: Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; SubExprs = new Stmt*[NumArgs+1]; diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index a9f96ad..81584b7 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -282,6 +282,18 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const { } } +SourceRange CXXConstructExpr::getSourceRange() const { + // FIXME: Should we know where the parentheses are, if there are any? + for (std::reverse_iterator<Stmt**> I(&Args[NumArgs]), E(&Args[0]); I!=E;++I) { + // Ignore CXXDefaultExprs when computing the range, as they don't + // have a range. + if (!isa<CXXDefaultArgExpr>(*I)) + return SourceRange(Loc, (*I)->getLocEnd()); + } + + return SourceRange(Loc); +} + SourceRange CXXOperatorCallExpr::getSourceRange() const { OverloadedOperatorKind Kind = getOperator(); if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) { @@ -340,6 +352,21 @@ const char *CXXNamedCastExpr::getCastName() const { } } +CXXDefaultArgExpr * +CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc, + ParmVarDecl *Param, Expr *SubExpr) { + void *Mem = C.Allocate(sizeof(CXXDefaultArgExpr) + sizeof(Stmt *)); + return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param, + SubExpr); +} + +void CXXDefaultArgExpr::DoDestroy(ASTContext &C) { + if (Param.getInt()) + getExpr()->Destroy(C); + this->~CXXDefaultArgExpr(); + C.Deallocate(this); +} + CXXTemporary *CXXTemporary::Create(ASTContext &C, const CXXDestructorDecl *Destructor) { return new (C) CXXTemporary(Destructor); @@ -372,34 +399,40 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, Expr **Args, unsigned NumArgs, SourceLocation rParenLoc) - : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, Cons, - false, Args, NumArgs), + : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, tyBeginLoc, + Cons, false, Args, NumArgs), TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) { } CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, + SourceLocation Loc, CXXConstructorDecl *D, bool Elidable, - Expr **Args, unsigned NumArgs) { - return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, D, Elidable, - Args, NumArgs); + Expr **Args, unsigned NumArgs, + bool ZeroInitialization) { + return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, + Elidable, Args, NumArgs, ZeroInitialization); } CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, + SourceLocation Loc, CXXConstructorDecl *D, bool elidable, - Expr **args, unsigned numargs) + Expr **args, unsigned numargs, + bool ZeroInitialization) : Expr(SC, T, T->isDependentType(), (T->isDependentType() || CallExpr::hasAnyValueDependentArguments(args, numargs))), - Constructor(D), Elidable(elidable), Args(0), NumArgs(numargs) { - if (NumArgs) { - Args = new (C) Stmt*[NumArgs]; - - for (unsigned i = 0; i != NumArgs; ++i) { - assert(args[i] && "NULL argument in CXXConstructExpr"); - Args[i] = args[i]; - } + Constructor(D), Loc(Loc), Elidable(elidable), + ZeroInitialization(ZeroInitialization), Args(0), NumArgs(numargs) +{ + if (NumArgs) { + Args = new (C) Stmt*[NumArgs]; + + for (unsigned i = 0; i != NumArgs; ++i) { + assert(args[i] && "NULL argument in CXXConstructExpr"); + Args[i] = args[i]; } + } } CXXConstructExpr::CXXConstructExpr(EmptyShell Empty, ASTContext &C, @@ -420,12 +453,10 @@ void CXXConstructExpr::DoDestroy(ASTContext &C) { CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, CXXTemporary **temps, - unsigned numtemps, - bool shoulddestroytemps) + unsigned numtemps) : Expr(CXXExprWithTemporariesClass, subexpr->getType(), subexpr->isTypeDependent(), subexpr->isValueDependent()), - SubExpr(subexpr), Temps(0), NumTemps(numtemps), - ShouldDestroyTemps(shoulddestroytemps) { + SubExpr(subexpr), Temps(0), NumTemps(numtemps) { if (NumTemps > 0) { Temps = new CXXTemporary*[NumTemps]; for (unsigned i = 0; i < NumTemps; ++i) @@ -436,10 +467,8 @@ CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C, Expr *SubExpr, CXXTemporary **Temps, - unsigned NumTemps, - bool ShouldDestroyTemps){ - return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps, - ShouldDestroyTemps); + unsigned NumTemps) { + return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps); } void CXXExprWithTemporaries::DoDestroy(ASTContext &C) { diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 13831dc..06afec7 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -222,7 +222,6 @@ public: APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } APValue VisitDeclRefExpr(DeclRefExpr *E); - APValue VisitBlockExpr(BlockExpr *E); APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E, 0); } APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E); APValue VisitMemberExpr(MemberExpr *E); @@ -270,13 +269,6 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) { return APValue(); } -APValue LValueExprEvaluator::VisitBlockExpr(BlockExpr *E) { - if (E->hasBlockDeclRefExprs()) - return APValue(); - - return APValue(E, 0); -} - APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { if (!Info.AnyLValue && !E->isFileScope()) return APValue(); @@ -366,7 +358,7 @@ public: APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } APValue VisitBinaryOperator(const BinaryOperator *E); - APValue VisitCastExpr(const CastExpr* E); + APValue VisitCastExpr(CastExpr* E); APValue VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } APValue VisitUnaryAddrOf(const UnaryOperator *E); @@ -443,23 +435,49 @@ APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { } -APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { - const Expr* SubExpr = E->getSubExpr(); +APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) { + Expr* SubExpr = E->getSubExpr(); - // Check for pointer->pointer cast - if (SubExpr->getType()->isPointerType() || - SubExpr->getType()->isObjCObjectPointerType() || - SubExpr->getType()->isNullPtrType()) { - APValue Result; - if (EvaluatePointer(SubExpr, Result, Info)) + switch (E->getCastKind()) { + default: + break; + + case CastExpr::CK_Unknown: { + // FIXME: The handling for CK_Unknown is ugly/shouldn't be necessary! + + // Check for pointer->pointer cast + if (SubExpr->getType()->isPointerType() || + SubExpr->getType()->isObjCObjectPointerType() || + SubExpr->getType()->isNullPtrType() || + SubExpr->getType()->isBlockPointerType()) + return Visit(SubExpr); + + if (SubExpr->getType()->isIntegralType()) { + APValue Result; + if (!EvaluateIntegerOrLValue(SubExpr, Result, Info)) + break; + + if (Result.isInt()) { + Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); + return APValue(0, Result.getInt().getZExtValue()); + } + + // Cast is of an lvalue, no need to change value. return Result; - return APValue(); + } + break; } - if (SubExpr->getType()->isIntegralType()) { + case CastExpr::CK_NoOp: + case CastExpr::CK_BitCast: + case CastExpr::CK_AnyPointerToObjCPointerCast: + case CastExpr::CK_AnyPointerToBlockPointerCast: + return Visit(SubExpr); + + case CastExpr::CK_IntegralToPointer: { APValue Result; if (!EvaluateIntegerOrLValue(SubExpr, Result, Info)) - return APValue(); + break; if (Result.isInt()) { Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); @@ -469,14 +487,13 @@ APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { // Cast is of an lvalue, no need to change value. return Result; } - - if (SubExpr->getType()->isFunctionType() || - SubExpr->getType()->isBlockPointerType() || - SubExpr->getType()->isArrayType()) { + case CastExpr::CK_ArrayToPointerDecay: + case CastExpr::CK_FunctionToPointerDecay: { APValue Result; if (EvaluateLValue(SubExpr, Result, Info)) return Result; - return APValue(); + break; + } } return APValue(); @@ -970,8 +987,9 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { } } + // TODO: Perhaps we should let LLVM lower this? if (E->getArg(0)->HasSideEffects(Info.Ctx)) { - if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() < 2) + if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() == 0) return Success(-1ULL, E); return Success(0, E); } @@ -1290,8 +1308,6 @@ unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) { /// VisitSizeAlignOfExpr - Evaluate a sizeof or alignof with a result as the /// expression's type. bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { - QualType DstTy = E->getType(); - // Handle alignof separately. if (!E->isSizeOf()) { if (E->isArgumentType()) diff --git a/lib/AST/FullExpr.cpp b/lib/AST/FullExpr.cpp new file mode 100644 index 0000000..f47284f --- /dev/null +++ b/lib/AST/FullExpr.cpp @@ -0,0 +1,58 @@ +//===--- FullExpr.cpp - C++ full expression class ---------------*- 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 the FullExpr interface, to be used for type safe handling +// of full expressions. +// +// Full expressions are described in C++ [intro.execution]p12. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/FullExpr.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "llvm/Support/AlignOf.h" +using namespace clang; + +FullExpr FullExpr::Create(ASTContext &Context, Expr *SubExpr, + CXXTemporary **Temporaries, unsigned NumTemporaries) { + FullExpr E; + + if (!NumTemporaries) { + E.SubExpr = SubExpr; + return E; + } + + unsigned Size = sizeof(FullExpr) + + sizeof(CXXTemporary *) * NumTemporaries; + + unsigned Align = llvm::AlignOf<ExprAndTemporaries>::Alignment; + ExprAndTemporaries *ET = + static_cast<ExprAndTemporaries *>(Context.Allocate(Size, Align)); + + ET->SubExpr = SubExpr; + std::copy(Temporaries, Temporaries + NumTemporaries, ET->temps_begin()); + + return E; +} + +void FullExpr::Destroy(ASTContext &Context) { + if (Expr *E = SubExpr.dyn_cast<Expr *>()) { + E->Destroy(Context); + return; + } + + ExprAndTemporaries *ET = SubExpr.get<ExprAndTemporaries *>(); + for (ExprAndTemporaries::temps_iterator i = ET->temps_begin(), + e = ET->temps_end(); i != e; ++i) + (*i)->Destroy(Context); + + Context.Deallocate(ET); +} diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index fad80ec..7c7aeb8 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -47,17 +47,6 @@ const char *Stmt::getStmtClassName() const { return getStmtInfoTableEntry((StmtClass)sClass).Name; } -void Stmt::DestroyChildren(ASTContext &C) { - for (child_iterator I = child_begin(), E = child_end(); I !=E; ) - if (Stmt* Child = *I++) Child->Destroy(C); -} - -void Stmt::DoDestroy(ASTContext &C) { - DestroyChildren(C); - this->~Stmt(); - C.Deallocate((void *)this); -} - void Stmt::PrintStats() { // Ensure the table is primed. getStmtInfoTableEntry(Stmt::NullStmtClass); @@ -93,20 +82,6 @@ bool Stmt::CollectingStats(bool Enable) { return StatSwitch; } -void SwitchStmt::DoDestroy(ASTContext &Ctx) { - // Destroy the SwitchCase statements in this switch. In the normal - // case, this loop will merely decrement the reference counts from - // the Retain() calls in addSwitchCase(); - SwitchCase *SC = FirstCase; - while (SC) { - SwitchCase *Next = SC->getNextSwitchCase(); - SC->Destroy(Ctx); - SC = Next; - } - - Stmt::DoDestroy(Ctx); -} - void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) { if (this->Body) C.Deallocate(Body); @@ -412,6 +387,71 @@ ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc, RParenLoc = rparenloc; } +//===----------------------------------------------------------------------===// +// AST Destruction. +//===----------------------------------------------------------------------===// + +void Stmt::DestroyChildren(ASTContext &C) { + for (child_iterator I = child_begin(), E = child_end(); I !=E; ) + if (Stmt* Child = *I++) Child->Destroy(C); +} + +static void BranchDestroy(ASTContext &C, Stmt *S, Stmt **SubExprs, + unsigned NumExprs) { + // We do not use child_iterator here because that will include + // the expressions referenced by the condition variable. + for (Stmt **I = SubExprs, **E = SubExprs + NumExprs; I != E; ++I) + if (Stmt *Child = *I) Child->Destroy(C); + + S->~Stmt(); + C.Deallocate((void *) S); +} + +void Stmt::DoDestroy(ASTContext &C) { + DestroyChildren(C); + this->~Stmt(); + C.Deallocate((void *)this); +} + +void CXXCatchStmt::DoDestroy(ASTContext& C) { + if (ExceptionDecl) + ExceptionDecl->Destroy(C); + Stmt::DoDestroy(C); +} + +void DeclStmt::DoDestroy(ASTContext &C) { + // Don't use StmtIterator to iterate over the Decls, as that can recurse + // into VLA size expressions (which are owned by the VLA). Further, Decls + // are owned by the DeclContext, and will be destroyed with them. + if (DG.isDeclGroup()) + DG.getDeclGroup().Destroy(C); +} + +void IfStmt::DoDestroy(ASTContext &C) { + BranchDestroy(C, this, SubExprs, END_EXPR); +} + +void ForStmt::DoDestroy(ASTContext &C) { + BranchDestroy(C, this, SubExprs, END_EXPR); +} + +void SwitchStmt::DoDestroy(ASTContext &C) { + // Destroy the SwitchCase statements in this switch. In the normal + // case, this loop will merely decrement the reference counts from + // the Retain() calls in addSwitchCase(); + SwitchCase *SC = FirstCase; + while (SC) { + SwitchCase *Next = SC->getNextSwitchCase(); + SC->Destroy(C); + SC = Next; + } + + BranchDestroy(C, this, SubExprs, END_EXPR); +} + +void WhileStmt::DoDestroy(ASTContext &C) { + BranchDestroy(C, this, SubExprs, END_EXPR); +} //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements @@ -447,24 +487,40 @@ Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; } Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; } // IfStmt -Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; } +Stmt::child_iterator IfStmt::child_begin() { + return child_iterator(Var, &SubExprs[0]); +} +Stmt::child_iterator IfStmt::child_end() { + return child_iterator(0, &SubExprs[0]+END_EXPR); +} // SwitchStmt -Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; } +Stmt::child_iterator SwitchStmt::child_begin() { + return child_iterator(Var, &SubExprs[0]); +} +Stmt::child_iterator SwitchStmt::child_end() { + return child_iterator(0, &SubExprs[0]+END_EXPR); +} // WhileStmt -Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; } +Stmt::child_iterator WhileStmt::child_begin() { + return child_iterator(Var, &SubExprs[0]); +} +Stmt::child_iterator WhileStmt::child_end() { + return child_iterator(0, &SubExprs[0]+END_EXPR); +} // DoStmt Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; } Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; } // ForStmt -Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; } +Stmt::child_iterator ForStmt::child_begin() { + return child_iterator(CondVar, &SubExprs[0]); +} +Stmt::child_iterator ForStmt::child_end() { + return child_iterator(0, &SubExprs[0]+END_EXPR); +} // ObjCForCollectionStmt Stmt::child_iterator ObjCForCollectionStmt::child_begin() { @@ -565,12 +621,6 @@ QualType CXXCatchStmt::getCaughtType() const { return QualType(); } -void CXXCatchStmt::DoDestroy(ASTContext& C) { - if (ExceptionDecl) - ExceptionDecl->Destroy(C); - Stmt::DoDestroy(C); -} - // CXXTryStmt Stmt::child_iterator CXXTryStmt::child_begin() { return &Stmts[0]; } Stmt::child_iterator CXXTryStmt::child_end() { return &Stmts[0]+Stmts.size(); } diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp index 4f62b66..7fc7c96 100644 --- a/lib/AST/StmtIterator.cpp +++ b/lib/AST/StmtIterator.cpp @@ -65,7 +65,7 @@ void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { assert (getVAPtr() == NULL); if (inDecl()) { - assert (decl); + assert(decl); // FIXME: SIMPLIFY AWAY. if (ImmediateAdvance) @@ -74,7 +74,7 @@ void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { return; } else { - assert (inDeclGroup()); + assert(inDeclGroup()); if (ImmediateAdvance) ++DGI; @@ -113,19 +113,19 @@ bool StmtIteratorBase::HandleDecl(Decl* D) { return false; } -StmtIteratorBase::StmtIteratorBase(Decl* d) - : decl(d), RawVAPtr(DeclMode) { - assert (decl); - NextDecl(false); +StmtIteratorBase::StmtIteratorBase(Decl *d, Stmt **s) + : stmt(s), decl(d), RawVAPtr(d ? DeclMode : 0) { + if (decl) + NextDecl(false); } StmtIteratorBase::StmtIteratorBase(Decl** dgi, Decl** dge) - : DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) { + : stmt(0), DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) { NextDecl(false); } StmtIteratorBase::StmtIteratorBase(VariableArrayType* t) -: decl(0), RawVAPtr(SizeOfTypeVAMode) { + : stmt(0), decl(0), RawVAPtr(SizeOfTypeVAMode) { RawVAPtr |= reinterpret_cast<uintptr_t>(t); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index e2d772b..b74e1ef 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -540,7 +540,6 @@ StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) { void StmtProfiler::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *S) { VisitExpr(S); - ID.AddBoolean(S->shouldDestroyTemporaries()); for (unsigned I = 0, N = S->getNumTemporaries(); I != N; ++I) VisitDecl( const_cast<CXXDestructorDecl *>(S->getTemporary(I)->getDestructor())); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 687beae..e0055f1 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -387,8 +387,6 @@ bool Type::isIntegerType() const { // FIXME: In C++, enum types are never integer types. if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) return true; - if (isa<FixedWidthIntType>(CanonicalType)) - return true; if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isIntegerType(); return false; @@ -397,13 +395,11 @@ bool Type::isIntegerType() const { bool Type::isIntegralType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::LongLong; + BT->getKind() <= BuiltinType::Int128; if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) return true; // Complete enum types are integral. // FIXME: In C++, enum types are never integral. - if (isa<FixedWidthIntType>(CanonicalType)) - return true; return false; } @@ -453,16 +449,12 @@ bool Type::isAnyCharacterType() const { bool Type::isSignedIntegerType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { return BT->getKind() >= BuiltinType::Char_S && - BT->getKind() <= BuiltinType::LongLong; + BT->getKind() <= BuiltinType::Int128; } if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) return ET->getDecl()->getIntegerType()->isSignedIntegerType(); - if (const FixedWidthIntType *FWIT = - dyn_cast<FixedWidthIntType>(CanonicalType)) - return FWIT->isSigned(); - if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isSignedIntegerType(); return false; @@ -481,10 +473,6 @@ bool Type::isUnsignedIntegerType() const { if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); - if (const FixedWidthIntType *FWIT = - dyn_cast<FixedWidthIntType>(CanonicalType)) - return !FWIT->isSigned(); - if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isUnsignedIntegerType(); return false; @@ -515,8 +503,6 @@ bool Type::isRealType() const { BT->getKind() <= BuiltinType::LongDouble; if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) return TT->getDecl()->isEnum() && TT->getDecl()->isDefinition(); - if (isa<FixedWidthIntType>(CanonicalType)) - return true; if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isRealType(); return false; @@ -530,8 +516,6 @@ bool Type::isArithmeticType() const { // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). // If a body isn't seen by the time we get here, return false. return ET->getDecl()->isDefinition(); - if (isa<FixedWidthIntType>(CanonicalType)) - return true; return isa<ComplexType>(CanonicalType) || isa<VectorType>(CanonicalType); } @@ -545,8 +529,6 @@ bool Type::isScalarType() const { return true; return false; } - if (isa<FixedWidthIntType>(CanonicalType)) - return true; return isa<PointerType>(CanonicalType) || isa<BlockPointerType>(CanonicalType) || isa<MemberPointerType>(CanonicalType) || @@ -725,6 +707,7 @@ bool Type::isSpecifierType() const { case Typename: case ObjCInterface: case ObjCObjectPointer: + case Elaborated: return true; default: return false; diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 4a2b956..818657c 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -94,21 +94,6 @@ void TypePrinter::PrintBuiltin(const BuiltinType *T, std::string &S) { } } -void TypePrinter::PrintFixedWidthInt(const FixedWidthIntType *T, - std::string &S) { - // FIXME: Once we get bitwidth attribute, write as - // "int __attribute__((bitwidth(x)))". - std::string prefix = "__clang_fixedwidth"; - prefix += llvm::utostr_32(T->getWidth()); - prefix += (char)(T->isSigned() ? 'S' : 'U'); - if (S.empty()) { - S = prefix; - } else { - // Prefix the basic type, e.g. 'int X'. - S = prefix + S; - } -} - void TypePrinter::PrintComplex(const ComplexType *T, std::string &S) { Print(T->getElementType(), S); S = "_Complex " + S; diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 05e5196..97e6d91 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -105,7 +105,7 @@ void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID, } void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getAnalysisContext(), getParent(), CallSite); + Profile(ID, getAnalysisContext(), getParent(), CallSite, Block, Index); } void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) { @@ -145,8 +145,18 @@ LocationContextManager::getLocationContext(AnalysisContext *ctx, const StackFrameContext* LocationContextManager::getStackFrame(AnalysisContext *ctx, const LocationContext *parent, - const Stmt *s) { - return getLocationContext<StackFrameContext, Stmt>(ctx, parent, s); + const Stmt *s, const CFGBlock *blk, + unsigned idx) { + llvm::FoldingSetNodeID ID; + StackFrameContext::Profile(ID, ctx, parent, s, blk, idx); + void *InsertPos; + StackFrameContext *L = + cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos)); + if (!L) { + L = new StackFrameContext(ctx, parent, s, blk, idx); + Contexts.InsertNode(L, InsertPos); + } + return L; } const ScopeContext * diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index c913779..67483d9 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -294,7 +294,7 @@ namespace { } static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) { - static unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 }; + static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 }; if (i < kCFNumberCharType) return FixedSize[i-1]; diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index a38aaa7..224281b 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -479,15 +479,14 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) { const Decl& CD = *InitLoc->getDecl(); if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CD)) { if (MD->getSelfDecl() == PD) { - // FIXME: Just use a symbolic region, and remove ObjCObjectRegion - // entirely. - const ObjCObjectRegion *SelfRegion = - MRMgr.getObjCObjectRegion(MD->getClassInterface(), - MRMgr.getHeapRegion()); - - St = BindInternal(St, ValMgr.makeLoc(MRMgr.getVarRegion(PD, InitLoc)), - ValMgr.makeLoc(SelfRegion)); - + // FIXME: Add type constraints (when they become available) to + // SelfRegion? (i.e., it implements MD->getClassInterface()). + const MemRegion *VR = MRMgr.getVarRegion(PD, InitLoc); + const MemRegion *SelfRegion = + ValMgr.getRegionValueSymbolVal(VR).getAsRegion(); + assert(SelfRegion); + St = BindInternal(St, ValMgr.makeLoc(VR), + loc::MemRegionVal(SelfRegion)); // Scan the method for ivar references. While this requires an // entire AST scan, the cost should not be high in practice. St = scanForIvars(MD->getBody(), PD, SelfRegion, St); diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index e1a1e72..eab7da7 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -34,6 +34,17 @@ static SourceLocation GetEndLoc(Decl* D) { return D->getLocation(); } + +class AddStmtChoice { +public: + enum Kind { NotAlwaysAdd = 0, AlwaysAdd, AlwaysAddAsLValue }; +public: + AddStmtChoice(Kind kind) : k(kind) {} + bool alwaysAdd() const { return k != NotAlwaysAdd; } + bool asLValue() const { return k == AlwaysAddAsLValue; } +private: + Kind k; +}; /// CFGBuilder - This class implements CFG construction from an AST. /// The builder is stateful: an instance of the builder should be used to only @@ -84,15 +95,16 @@ public: private: // Visitors to walk an AST and construct the CFG. - CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd); - CFGBlock *VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd); - CFGBlock *VisitBlockExpr(BlockExpr* E, bool alwaysAdd); + CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc); + CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc); + CFGBlock *VisitBlockExpr(BlockExpr* E, AddStmtChoice asc); CFGBlock *VisitBreakStmt(BreakStmt *B); - CFGBlock *VisitCallExpr(CallExpr *C, bool alwaysAdd); + CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc); CFGBlock *VisitCaseStmt(CaseStmt *C); - CFGBlock *VisitChooseExpr(ChooseExpr *C); + CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc); CFGBlock *VisitCompoundStmt(CompoundStmt *C); - CFGBlock *VisitConditionalOperator(ConditionalOperator *C); + CFGBlock *VisitConditionalOperator(ConditionalOperator *C, + AddStmtChoice asc); CFGBlock *VisitContinueStmt(ContinueStmt *C); CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S) { return NYS(); } CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); @@ -112,13 +124,13 @@ private: CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S); CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); CFGBlock *VisitReturnStmt(ReturnStmt* R); - CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, bool alwaysAdd); - CFGBlock *VisitStmtExpr(StmtExpr *S, bool alwaysAdd); + CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, AddStmtChoice asc); + CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc); CFGBlock *VisitSwitchStmt(SwitchStmt *S); CFGBlock *VisitWhileStmt(WhileStmt *W); - CFGBlock *Visit(Stmt *S, bool alwaysAdd = false); - CFGBlock *VisitStmt(Stmt *S, bool alwaysAdd); + CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd); + CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc); CFGBlock *VisitChildren(Stmt* S); // NYS == Not Yet Supported @@ -130,10 +142,13 @@ private: void autoCreateBlock() { if (!Block) Block = createBlock(); } CFGBlock *createBlock(bool add_successor = true); bool FinishBlock(CFGBlock* B); - CFGBlock *addStmt(Stmt *S) { return Visit(S, true); } + CFGBlock *addStmt(Stmt *S, AddStmtChoice asc = AddStmtChoice::AlwaysAdd) { + return Visit(S, asc); + } - void AppendStmt(CFGBlock *B, Stmt *S) { - B->appendStmt(S, cfg->getBumpVectorContext()); + void AppendStmt(CFGBlock *B, Stmt *S, + AddStmtChoice asc = AddStmtChoice::AlwaysAdd) { + B->appendStmt(S, cfg->getBumpVectorContext(), asc.asLValue()); } void AddSuccessor(CFGBlock *B, CFGBlock *S) { @@ -278,38 +293,38 @@ bool CFGBuilder::FinishBlock(CFGBlock* B) { /// Visit - Walk the subtree of a statement and add extra /// blocks for ternary operators, &&, and ||. We also process "," and /// DeclStmts (which may contain nested control-flow). -CFGBlock* CFGBuilder::Visit(Stmt * S, bool alwaysAdd) { +CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { tryAgain: switch (S->getStmtClass()) { default: - return VisitStmt(S, alwaysAdd); + return VisitStmt(S, asc); case Stmt::AddrLabelExprClass: - return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), alwaysAdd); + return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc); case Stmt::BinaryOperatorClass: - return VisitBinaryOperator(cast<BinaryOperator>(S), alwaysAdd); + return VisitBinaryOperator(cast<BinaryOperator>(S), asc); case Stmt::BlockExprClass: - return VisitBlockExpr(cast<BlockExpr>(S), alwaysAdd); + return VisitBlockExpr(cast<BlockExpr>(S), asc); case Stmt::BreakStmtClass: return VisitBreakStmt(cast<BreakStmt>(S)); case Stmt::CallExprClass: - return VisitCallExpr(cast<CallExpr>(S), alwaysAdd); + return VisitCallExpr(cast<CallExpr>(S), asc); case Stmt::CaseStmtClass: return VisitCaseStmt(cast<CaseStmt>(S)); case Stmt::ChooseExprClass: - return VisitChooseExpr(cast<ChooseExpr>(S)); + return VisitChooseExpr(cast<ChooseExpr>(S), asc); case Stmt::CompoundStmtClass: return VisitCompoundStmt(cast<CompoundStmt>(S)); case Stmt::ConditionalOperatorClass: - return VisitConditionalOperator(cast<ConditionalOperator>(S)); + return VisitConditionalOperator(cast<ConditionalOperator>(S), asc); case Stmt::ContinueStmtClass: return VisitContinueStmt(cast<ContinueStmt>(S)); @@ -367,10 +382,10 @@ tryAgain: return VisitReturnStmt(cast<ReturnStmt>(S)); case Stmt::SizeOfAlignOfExprClass: - return VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), alwaysAdd); + return VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), asc); case Stmt::StmtExprClass: - return VisitStmtExpr(cast<StmtExpr>(S), alwaysAdd); + return VisitStmtExpr(cast<StmtExpr>(S), asc); case Stmt::SwitchStmtClass: return VisitSwitchStmt(cast<SwitchStmt>(S)); @@ -380,10 +395,10 @@ tryAgain: } } -CFGBlock *CFGBuilder::VisitStmt(Stmt *S, bool alwaysAdd) { - if (alwaysAdd) { +CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) { + if (asc.alwaysAdd()) { autoCreateBlock(); - AppendStmt(Block, S); + AppendStmt(Block, S, asc); } return VisitChildren(S); @@ -399,21 +414,23 @@ CFGBlock *CFGBuilder::VisitChildren(Stmt* Terminator) { return B; } -CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd) { +CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, + AddStmtChoice asc) { AddressTakenLabels.insert(A->getLabel()); - if (alwaysAdd) { + if (asc.alwaysAdd()) { autoCreateBlock(); - AppendStmt(Block, A); + AppendStmt(Block, A, asc); } return Block; } -CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) { +CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, + AddStmtChoice asc) { if (B->isLogicalOp()) { // && or || CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); - AppendStmt(ConfluenceBlock, B); + AppendStmt(ConfluenceBlock, B, asc); if (!FinishBlock(ConfluenceBlock)) return 0; @@ -450,18 +467,18 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) { } else if (B->getOpcode() == BinaryOperator::Comma) { // , autoCreateBlock(); - AppendStmt(Block, B); + AppendStmt(Block, B, asc); addStmt(B->getRHS()); return addStmt(B->getLHS()); } - return VisitStmt(B, alwaysAdd); + return VisitStmt(B, asc); } -CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, bool alwaysAdd) { - if (alwaysAdd) { +CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) { + if (asc.alwaysAdd()) { autoCreateBlock(); - AppendStmt(Block, E); + AppendStmt(Block, E, asc); } return Block; } @@ -487,7 +504,7 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) { return Block; } -CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) { +CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { // If this is a call to a no-return function, this stops the block here. bool NoReturn = false; if (C->getCallee()->getType().getNoReturnAttr()) { @@ -499,14 +516,14 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) { NoReturn = true; if (!NoReturn) - return VisitStmt(C, alwaysAdd); + return VisitStmt(C, asc); if (Block && !FinishBlock(Block)) return 0; // Create new block with no successor for the remaining pieces. Block = createBlock(false); - AppendStmt(Block, C); + AppendStmt(Block, C, asc); // Wire this to the exit block directly. AddSuccessor(Block, &cfg->getExit()); @@ -514,9 +531,10 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) { return VisitChildren(C); } -CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C) { +CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, + AddStmtChoice asc) { CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); - AppendStmt(ConfluenceBlock, C); + AppendStmt(ConfluenceBlock, C, asc); if (!FinishBlock(ConfluenceBlock)) return 0; @@ -555,11 +573,12 @@ CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { return LastBlock; } -CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C) { +CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, + AddStmtChoice asc) { // Create the confluence block that will "merge" the results of the ternary // expression. CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); - AppendStmt(ConfluenceBlock, C); + AppendStmt(ConfluenceBlock, C, asc); if (!FinishBlock(ConfluenceBlock)) return 0; @@ -670,7 +689,10 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(Decl* D) { case Stmt::StringLiteralClass: break; default: - Block = addStmt(Init); + Block = addStmt(Init, + VD->getType()->isReferenceType() + ? AddStmtChoice::AlwaysAddAsLValue + : AddStmtChoice::AlwaysAdd); } } @@ -754,7 +776,19 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { // Add the condition as the last statement in the new block. This may create // new blocks as the condition may contain control-flow. Any newly created // blocks will be pointed to be "Block". - return addStmt(I->getCond()); + Block = addStmt(I->getCond()); + + // Finally, if the IfStmt contains a condition variable, add both the IfStmt + // and the condition variable initialization to the CFG. + if (VarDecl *VD = I->getConditionVariable()) { + if (Expr *Init = VD->getInit()) { + autoCreateBlock(); + AppendStmt(Block, I, AddStmtChoice::AlwaysAdd); + addStmt(Init); + } + } + + return Block; } @@ -776,7 +810,7 @@ CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) { // Add the return statement to the block. This may create new blocks if R // contains control-flow (short-circuit operations). - return VisitStmt(R, true); + return VisitStmt(R, AddStmtChoice::AlwaysAdd); } CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) { @@ -854,6 +888,19 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { if (Stmt* C = F->getCond()) { Block = ExitConditionBlock; EntryConditionBlock = addStmt(C); + assert(Block == EntryConditionBlock); + + // If this block contains a condition variable, add both the condition + // variable and initializer to the CFG. + if (VarDecl *VD = F->getConditionVariable()) { + if (Expr *Init = VD->getInit()) { + autoCreateBlock(); + AppendStmt(Block, F, AddStmtChoice::AlwaysAdd); + EntryConditionBlock = addStmt(Init); + assert(Block == EntryConditionBlock); + } + } + if (Block) { if (!FinishBlock(EntryConditionBlock)) return 0; @@ -1000,7 +1047,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { // Walk the 'element' expression to see if there are any side-effects. We // generate new blocks as necesary. We DON'T add the statement by default to // the CFG unless it contains control-flow. - EntryConditionBlock = Visit(S->getElement(), false); + EntryConditionBlock = Visit(S->getElement(), AddStmtChoice::NotAlwaysAdd); if (Block) { if (!FinishBlock(EntryConditionBlock)) return 0; @@ -1096,6 +1143,18 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { Block = ExitConditionBlock; EntryConditionBlock = addStmt(C); assert(Block == EntryConditionBlock); + + // If this block contains a condition variable, add both the condition + // variable and initializer to the CFG. + if (VarDecl *VD = W->getConditionVariable()) { + if (Expr *Init = VD->getInit()) { + autoCreateBlock(); + AppendStmt(Block, W, AddStmtChoice::AlwaysAdd); + EntryConditionBlock = addStmt(Init); + assert(Block == EntryConditionBlock); + } + } + if (Block) { if (!FinishBlock(EntryConditionBlock)) return 0; @@ -1182,7 +1241,7 @@ CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) { // Add the statement to the block. This may create new blocks if S contains // control-flow (short-circuit operations). - return VisitStmt(S, true); + return VisitStmt(S, AddStmtChoice::AlwaysAdd); } CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) { @@ -1198,7 +1257,7 @@ CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) { // Add the statement to the block. This may create new blocks if S contains // control-flow (short-circuit operations). - return VisitStmt(T, true); + return VisitStmt(T, AddStmtChoice::AlwaysAdd); } CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) { @@ -1316,9 +1375,9 @@ CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) { } CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, - bool alwaysAdd) { + AddStmtChoice asc) { - if (alwaysAdd) { + if (asc.alwaysAdd()) { autoCreateBlock(); AppendStmt(Block, E); } @@ -1335,8 +1394,8 @@ CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, /// VisitStmtExpr - Utility method to handle (nested) statement /// expressions (a GCC extension). -CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, bool alwaysAdd) { - if (alwaysAdd) { +CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) { + if (asc.alwaysAdd()) { autoCreateBlock(); AppendStmt(Block, SE); } @@ -1391,8 +1450,19 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { SwitchTerminatedBlock->setTerminator(Terminator); assert (Terminator->getCond() && "switch condition must be non-NULL"); Block = SwitchTerminatedBlock; - - return addStmt(Terminator->getCond()); + Block = addStmt(Terminator->getCond()); + + // Finally, if the SwitchStmt contains a condition variable, add both the + // SwitchStmt and the condition variable initialization to the CFG. + if (VarDecl *VD = Terminator->getConditionVariable()) { + if (Expr *Init = VD->getInit()) { + autoCreateBlock(); + AppendStmt(Block, Terminator, AddStmtChoice::AlwaysAdd); + addStmt(Init); + } + } + + return Block; } CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { @@ -1514,17 +1584,20 @@ namespace { typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy; } -static void FindSubExprAssignments(Stmt* Terminator, llvm::SmallPtrSet<Expr*,50>& Set) { - if (!Terminator) +static void FindSubExprAssignments(Stmt *S, + llvm::SmallPtrSet<Expr*,50>& Set) { + if (!S) return; - for (Stmt::child_iterator I=Terminator->child_begin(), E=Terminator->child_end(); I!=E; ++I) { - if (!*I) continue; - - if (BinaryOperator* B = dyn_cast<BinaryOperator>(*I)) + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) { + Stmt *child = *I; + if (!child) + continue; + + if (BinaryOperator* B = dyn_cast<BinaryOperator>(child)) if (B->isAssignmentOp()) Set.insert(B); - FindSubExprAssignments(*I, Set); + FindSubExprAssignments(child, Set); } } diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 9639ad9..a15a8f1 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -1149,7 +1149,11 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the // function's type. const FunctionType* FT = FD->getType()->getAs<FunctionType>(); - const char* FName = FD->getIdentifier()->getNameStart(); + const IdentifierInfo *II = FD->getIdentifier(); + if (!II) + break; + + const char* FName = II->getNameStart(); // Strip away preceding '_'. Doing this here will effect all the checks // down below. @@ -2938,6 +2942,17 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, QualType T = Ex->getType(); + // For CallExpr, use the result type to know if it returns a reference. + if (const CallExpr *CE = dyn_cast<CallExpr>(Ex)) { + const Expr *Callee = CE->getCallee(); + if (const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl()) + T = FD->getResultType(); + } + else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Ex)) { + if (const ObjCMethodDecl *MD = ME->getMethodDecl()) + T = MD->getResultType(); + } + if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) { unsigned Count = Builder.getCurrentBlockCount(); ValueManager &ValMgr = Eng.getValueManager(); diff --git a/lib/Analysis/CallInliner.cpp b/lib/Analysis/CallInliner.cpp index 43523c2..d18bbcc 100644 --- a/lib/Analysis/CallInliner.cpp +++ b/lib/Analysis/CallInliner.cpp @@ -11,36 +11,46 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/LocalCheckers.h" using namespace clang; namespace { - -class CallInliner : public GRTransferFuncs { - ASTContext &Ctx; +class CallInliner : public Checker { public: - CallInliner(ASTContext &ctx) : Ctx(ctx) {} + static void *getTag() { + static int x; + return &x; + } - void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode* Pred); - + virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); + virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng); }; +} +void clang::RegisterCallInliner(GRExprEngine &Eng) { + Eng.registerCheck(new CallInliner()); } -void CallInliner::EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode* Pred) { - FunctionDecl const *FD = L.getAsFunctionDecl(); +bool CallInliner::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + + const FunctionDecl *FD = L.getAsFunctionDecl(); if (!FD) - return; // GRExprEngine is responsible for the autotransition. + return false; + + if (!FD->isThisDeclarationADefinition()) + return false; + GRStmtNodeBuilder &Builder = C.getNodeBuilder(); // Make a new LocationContext. - StackFrameContext const *LocCtx = - Engine.getAnalysisManager().getStackFrame(FD, Pred->getLocationContext(), CE); + const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD, + C.getPredecessor()->getLocationContext(), CE, + Builder.getBlock(), Builder.getIndex()); CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry()); @@ -54,22 +64,50 @@ void CallInliner::EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine, // Construct an edge representing the starting location in the function. BlockEdge Loc(Entry, SuccB, LocCtx); - GRState const *state = Builder.GetState(Pred); - state = Engine.getStoreManager().EnterStackFrame(state, LocCtx); - + state = C.getStoreManager().EnterStackFrame(state, LocCtx); + // This is a hack. We really should not use the GRStmtNodeBuilder. bool isNew; - ExplodedNode *SuccN = Engine.getGraph().getNode(Loc, state, &isNew); - SuccN->addPredecessor(Pred, Engine.getGraph()); - - Builder.Deferred.erase(Pred); + GRExprEngine &Eng = C.getEngine(); + ExplodedNode *Pred = C.getPredecessor(); + - // This is a hack. We really should not use the GRStmtNodeBuilder. + ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew); + SuccN->addPredecessor(Pred, Eng.getGraph()); + C.getNodeBuilder().Deferred.erase(Pred); + if (isNew) Builder.getWorkList()->Enqueue(SuccN); Builder.HasGeneratedNode = true; + + return true; } - -GRTransferFuncs *clang::CreateCallInliner(ASTContext &ctx) { - return new CallInliner(ctx); + +void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag, + GRExprEngine &Eng) { + const GRState *state = B.getState(); + ExplodedNode *Pred = B.getPredecessor(); + const StackFrameContext *LocCtx = + cast<StackFrameContext>(Pred->getLocationContext()); + + const Stmt *CE = LocCtx->getCallSite(); + + // Check if this is the top level stack frame. + if (!LocCtx->getParent()) + return; + + PostStmt NodeLoc(CE, LocCtx->getParent()); + + bool isNew; + ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew); + Succ->addPredecessor(Pred, Eng.getGraph()); + + // When creating the new work list unit, increment the statement index to + // point to the statement after the CallExpr. + if (isNew) + B.getWorkList().Enqueue(Succ, + *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()), + LocCtx->getIndex() + 1); + + B.HasGeneratedNode = true; } diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp index db9016f..6e4d899 100644 --- a/lib/Analysis/CheckDeadStores.cpp +++ b/lib/Analysis/CheckDeadStores.cpp @@ -84,7 +84,14 @@ public: const LiveVariables::AnalysisDataTy& AD, const LiveVariables::ValTy& Live) { - if (VD->hasLocalStorage() && !Live(VD, AD) && + if (!VD->hasLocalStorage()) + return; + // Reference types confuse the dead stores checker. Skip them + // for now. + if (VD->getType()->getAs<ReferenceType>()) + return; + + if (!Live(VD, AD) && !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) Report(VD, dsk, Ex->getSourceRange().getBegin(), Val->getSourceRange()); @@ -93,7 +100,6 @@ public: void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk, const LiveVariables::AnalysisDataTy& AD, const LiveVariables::ValTy& Live) { - if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) CheckVarDecl(VD, DR, Val, dsk, AD, Live); } @@ -183,13 +189,22 @@ public: if (!V) continue; - - if (V->hasLocalStorage()) + + if (V->hasLocalStorage()) { + // Reference types confuse the dead stores checker. Skip them + // for now. + if (V->getType()->getAs<ReferenceType>()) + return; + if (Expr* E = V->getInit()) { // Don't warn on C++ objects (yet) until we can show that their // constructors/destructors don't have side effects. if (isa<CXXConstructExpr>(E)) return; + + if (isa<CXXExprWithTemporaries>(E)) + return; + // A dead initialization is a variable that is dead after it // is initialized. We don't flag warnings for those variables // marked 'unused'. @@ -218,6 +233,7 @@ public: Report(V, DeadInit, V->getLocation(), E->getSourceRange()); } } + } } } }; diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp index 644dd19..209452a 100644 --- a/lib/Analysis/GRCoreEngine.cpp +++ b/lib/Analysis/GRCoreEngine.cpp @@ -122,8 +122,8 @@ void GRCoreEngine::ProcessEndPath(GREndPathNodeBuilder& Builder) { SubEngine.ProcessEndPath(Builder); } -void GRCoreEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& Builder) { - SubEngine.ProcessStmt(S, Builder); +void GRCoreEngine::ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder) { + SubEngine.ProcessStmt(E, Builder); } bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const GRState* State, @@ -213,9 +213,9 @@ void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { CFGBlock* Blk = L.getDst(); // Check if we are entering the EXIT block. - if (Blk == &(Pred->getLocationContext()->getCFG()->getExit())) { + if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { - assert (Pred->getLocationContext()->getCFG()->getExit().size() == 0 + assert (L.getLocationContext()->getCFG()->getExit().size() == 0 && "EXIT block cannot contain Stmts."); // Process the final state transition. @@ -241,10 +241,10 @@ void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L, WList->setBlockCounter(Counter); // Process the entrance of the block. - if (Stmt* S = L.getFirstStmt()) { + if (CFGElement E = L.getFirstElement()) { GRStmtNodeBuilder Builder(L.getBlock(), 0, Pred, this, SubEngine.getStateManager()); - ProcessStmt(S, Builder); + ProcessStmt(E, Builder); } else HandleBlockExit(L.getBlock(), Pred); @@ -447,7 +447,7 @@ GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state, ProgramPoint::Kind K, const void *tag) { - const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag); + const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag); return generateNodeInternal(L, state, Pred); } diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 51e6a54..2ce8edd 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -33,6 +33,7 @@ using namespace clang; using llvm::dyn_cast; +using llvm::dyn_cast_or_null; using llvm::cast; using llvm::APSInt; @@ -45,6 +46,29 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { return Ctx.Selectors.getSelector(0, &II); } + +static bool CalleeReturnsReference(const CallExpr *CE) { + const Expr *Callee = CE->getCallee(); + QualType T = Callee->getType(); + + if (const PointerType *PT = T->getAs<PointerType>()) { + const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>(); + T = FT->getResultType(); + } + else { + const BlockPointerType *BT = T->getAs<BlockPointerType>(); + T = BT->getPointeeType()->getAs<FunctionType>()->getResultType(); + } + return T->isReferenceType(); +} + +static bool ReceiverReturnsReference(const ObjCMessageExpr *ME) { + const ObjCMethodDecl *MD = ME->getMethodDecl(); + if (!MD) + return false; + return MD->getResultType()->isReferenceType(); +} + //===----------------------------------------------------------------------===// // Batch auditor. DEPRECATED. //===----------------------------------------------------------------------===// @@ -227,7 +251,7 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; CurrSet->clear(); } - + void *tag = I->first; Checker *checker = I->second; @@ -306,8 +330,9 @@ GRExprEngine::~GRExprEngine() { // Utility methods. //===----------------------------------------------------------------------===// -void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) { +void GRExprEngine::setTransferFunctionsAndCheckers(GRTransferFuncs* tf) { StateMgr.TF = tf; + StateMgr.Checkers = &Checkers; tf->RegisterChecks(*this); tf->RegisterPrinters(getStateManager().Printers); } @@ -333,43 +358,55 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { // FIXME: It would be nice if we had a more general mechanism to add // such preconditions. Some day. - const Decl *D = InitLoc->getDecl(); - - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // Precondition: the first argument of 'main' is an integer guaranteed - // to be > 0. - if (FD->getIdentifier()->getName() == "main" && - FD->getNumParams() > 0) { + do { + const Decl *D = InitLoc->getDecl(); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // Precondition: the first argument of 'main' is an integer guaranteed + // to be > 0. + const IdentifierInfo *II = FD->getIdentifier(); + if (!II || !(II->getName() == "main" && FD->getNumParams() > 0)) + break; + const ParmVarDecl *PD = FD->getParamDecl(0); QualType T = PD->getType(); - if (T->isIntegerType()) - if (const MemRegion *R = state->getRegion(PD, InitLoc)) { - SVal V = state->getSVal(loc::MemRegionVal(R)); - SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V, - ValMgr.makeZeroVal(T), - getContext().IntTy); - - if (DefinedOrUnknownSVal *Constraint = - dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested)) { - if (const GRState *newState = state->Assume(*Constraint, true)) - state = newState; - } - } + if (!T->isIntegerType()) + break; + + const MemRegion *R = state->getRegion(PD, InitLoc); + if (!R) + break; + + SVal V = state->getSVal(loc::MemRegionVal(R)); + SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V, + ValMgr.makeZeroVal(T), + getContext().IntTy); + + DefinedOrUnknownSVal *Constraint = + dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested); + + if (!Constraint) + break; + + if (const GRState *newState = state->Assume(*Constraint, true)) + state = newState; + + break; } - } - else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - // Precondition: 'self' is always non-null upon entry to an Objective-C - // method. - const ImplicitParamDecl *SelfD = MD->getSelfDecl(); - const MemRegion *R = state->getRegion(SelfD, InitLoc); - SVal V = state->getSVal(loc::MemRegionVal(R)); + + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + // Precondition: 'self' is always non-null upon entry to an Objective-C + // method. + const ImplicitParamDecl *SelfD = MD->getSelfDecl(); + const MemRegion *R = state->getRegion(SelfD, InitLoc); + SVal V = state->getSVal(loc::MemRegionVal(R)); - if (const Loc *LV = dyn_cast<Loc>(&V)) { - // Assume that the pointer value in 'self' is non-null. - state = state->Assume(*LV, true); - assert(state && "'self' cannot be null"); + if (const Loc *LV = dyn_cast<Loc>(&V)) { + // Assume that the pointer value in 'self' is non-null. + state = state->Assume(*LV, true); + assert(state && "'self' cannot be null"); + } } - } + } while (0); return state; } @@ -378,17 +415,15 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { // Top-level transfer function logic (Dispatcher). //===----------------------------------------------------------------------===// -void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { - +void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) { + CurrentStmt = CE.getStmt(); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), - S->getLocStart(), + CurrentStmt->getLocStart(), "Error evaluating statement"); Builder = &builder; EntryNode = builder.getLastNode(); - CurrentStmt = S; - // Set up our simple checks. if (BatchAuditor) Builder->setAuditor(BatchAuditor.get()); @@ -415,7 +450,7 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { // FIXME: This should soon be removed. ExplodedNodeSet Tmp2; - getTF().EvalDeadSymbols(Tmp2, *this, *Builder, EntryNode, S, + getTF().EvalDeadSymbols(Tmp2, *this, *Builder, EntryNode, CurrentStmt, CleanedState, SymReaper); if (Checkers.empty()) @@ -437,8 +472,8 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { Checker *checker = I->second; for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end(); NI != NE; ++NI) - checker->GR_EvalDeadSymbols(*DstSet, *Builder, *this, S, *NI, - SymReaper, tag); + checker->GR_EvalDeadSymbols(*DstSet, *Builder, *this, CurrentStmt, + *NI, SymReaper, tag); SrcSet = DstSet; } } @@ -457,7 +492,10 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I)); // Visit the statement. - Visit(S, *I, Dst); + if (CE.asLValue()) + VisitLValue(cast<Expr>(CurrentStmt), *I, Dst); + else + Visit(CurrentStmt, *I, Dst); // Do we need to auto-generate a node? We only need to do this to generate // a node with a "cleaned" state; GRCoreEngine will actually handle @@ -465,7 +503,7 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { if (Dst.size() == 1 && *Dst.begin() == EntryNode && !Builder->HasGeneratedNode && !HasAutoGenerated) { HasAutoGenerated = true; - builder.generateNode(S, GetState(EntryNode), *I); + builder.generateNode(CurrentStmt, GetState(EntryNode), *I); } } @@ -504,7 +542,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::CXXTypeidExprClass: case Stmt::CXXBoolLiteralExprClass: case Stmt::CXXNullPtrLiteralExprClass: - case Stmt::CXXThisExprClass: case Stmt::CXXThrowExprClass: case Stmt::CXXDefaultArgExprClass: case Stmt::CXXZeroInitValueExprClass: @@ -565,7 +602,8 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; } - if (AMgr.shouldEagerlyAssume() && (B->isRelationalOp() || B->isEqualityOp())) { + if (AMgr.shouldEagerlyAssume() && + (B->isRelationalOp() || B->isEqualityOp())) { ExplodedNodeSet Tmp; VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp, false); EvalEagerlyAssume(Dst, Tmp, cast<Expr>(S)); @@ -579,7 +617,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: { CallExpr* C = cast<CallExpr>(S); - VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, false); break; } @@ -606,6 +644,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; } + case Stmt::CXXThisExprClass: + VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst); + break; + case Stmt::DeclRefExprClass: VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst, false); break; @@ -614,12 +656,24 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst); break; + case Stmt::ForStmtClass: + // This case isn't for branch processing, but for handling the + // initialization of a condition variable. + VisitCondInit(cast<ForStmt>(S)->getConditionVariable(), S, Pred, Dst); + break; + case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: { CastExpr* C = cast<CastExpr>(S); - VisitCast(C, C->getSubExpr(), Pred, Dst); + VisitCast(C, C->getSubExpr(), Pred, Dst, false); break; } + + case Stmt::IfStmtClass: + // This case isn't for branch processing, but for handling the + // initialization of a condition variable. + VisitCondInit(cast<IfStmt>(S)->getConditionVariable(), S, Pred, Dst); + break; case Stmt::InitListExprClass: VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst); @@ -637,10 +691,9 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst); break; - case Stmt::ObjCMessageExprClass: { - VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst); + case Stmt::ObjCMessageExprClass: + VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst, false); break; - } case Stmt::ObjCAtThrowStmtClass: { // FIXME: This is not complete. We basically treat @throw as @@ -687,10 +740,16 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::StringLiteralClass: VisitLValue(cast<StringLiteral>(S), Pred, Dst); break; + + case Stmt::SwitchStmtClass: + // This case isn't for branch processing, but for handling the + // initialization of a condition variable. + VisitCondInit(cast<SwitchStmt>(S)->getConditionVariable(), S, Pred, Dst); + break; case Stmt::UnaryOperatorClass: { UnaryOperator *U = cast<UnaryOperator>(S); - if (AMgr.shouldEagerlyAssume() && (U->getOpcode() == UnaryOperator::LNot)) { + if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UnaryOperator::LNot)) { ExplodedNodeSet Tmp; VisitUnaryOperator(U, Pred, Tmp, false); EvalEagerlyAssume(Dst, Tmp, U); @@ -699,48 +758,92 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitUnaryOperator(U, Pred, Dst, false); break; } + + case Stmt::WhileStmtClass: + // This case isn't for branch processing, but for handling the + // initialization of a condition variable. + VisitCondInit(cast<WhileStmt>(S)->getConditionVariable(), S, Pred, Dst); + break; } } void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst) { + + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), + Ex->getLocStart(), + "Error evaluating statement"); + Ex = Ex->IgnoreParens(); - if (Ex != CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)) { + if (Ex != CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)){ Dst.Add(Pred); return; } switch (Ex->getStmtClass()) { + // C++ stuff we don't support yet. + case Stmt::CXXExprWithTemporariesClass: + case Stmt::CXXMemberCallExprClass: + case Stmt::CXXZeroInitValueExprClass: { + SaveAndRestore<bool> OldSink(Builder->BuildSinks); + Builder->BuildSinks = true; + MakeNode(Dst, Ex, Pred, GetState(Pred)); + break; + } case Stmt::ArraySubscriptExprClass: VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(Ex), Pred, Dst, true); return; + case Stmt::BinaryOperatorClass: + case Stmt::CompoundAssignOperatorClass: + VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true); + return; + case Stmt::BlockDeclRefExprClass: VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true); return; + + case Stmt::CallExprClass: + case Stmt::CXXOperatorCallExprClass: { + CallExpr *C = cast<CallExpr>(Ex); + assert(CalleeReturnsReference(C)); + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true); + break; + } + + case Stmt::CompoundLiteralExprClass: + VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true); + return; case Stmt::DeclRefExprClass: VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true); return; - - case Stmt::ObjCIvarRefExprClass: - VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true); - return; - - case Stmt::UnaryOperatorClass: - VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true); - return; - + + case Stmt::ImplicitCastExprClass: + case Stmt::CStyleCastExprClass: { + CastExpr *C = cast<CastExpr>(Ex); + QualType T = Ex->getType(); + VisitCast(C, C->getSubExpr(), Pred, Dst, true); + break; + } + case Stmt::MemberExprClass: VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true); return; - case Stmt::CompoundLiteralExprClass: - VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true); + case Stmt::ObjCIvarRefExprClass: + VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true); + return; + + case Stmt::ObjCMessageExprClass: { + ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex); + assert(ReceiverReturnsReference(ME)); + VisitObjCMessageExpr(ME, Pred, Dst, true); return; + } case Stmt::ObjCPropertyRefExprClass: case Stmt::ObjCImplicitSetterGetterRefExprClass: @@ -765,11 +868,10 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, return; } - case Stmt::BinaryOperatorClass: - case Stmt::CompoundAssignOperatorClass: - VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true); + case Stmt::UnaryOperatorClass: + VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true); return; - + default: // Arbitrary subexpressions can return aggregate temporaries that // can be used in a lvalue context. We need to enhance our support @@ -1023,7 +1125,8 @@ void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) { void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, ExplodedNodeSet& Dst) { - assert (Ex == CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)); + assert(Ex == CurrentStmt && + Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)); const GRState* state = GetState(Pred); SVal X = state->getSVal(Ex); @@ -1147,7 +1250,7 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, assert(B->getOpcode() == BinaryOperator::LAnd || B->getOpcode() == BinaryOperator::LOr); - assert(B == CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B)); + assert(B==CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B)); const GRState* state = GetState(Pred); SVal X = state->getSVal(B); @@ -1232,13 +1335,23 @@ void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D, SVal V = state->getLValue(VD, Pred->getLocationContext()); - if (asLValue) + if (asLValue) { + // For references, the 'lvalue' is the pointer address stored in the + // reference region. + if (VD->getType()->isReferenceType()) { + if (const MemRegion *R = V.getAsRegion()) + V = state->getSVal(R); + else + V = UnknownVal(); + } + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), ProgramPoint::PostLValueKind); + } else EvalLoad(Dst, Ex, Pred, state, V); - return; + return; } else if (const EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) { assert(!asLValue && "EnumConstantDecl does not have lvalue."); @@ -1415,6 +1528,37 @@ void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred, const GRState* state, SVal location, const void *tag, QualType LoadTy) { + // Are we loading from a region? This actually results in two loads; one + // to fetch the address of the referenced value and one to fetch the + // referenced value. + if (const TypedRegion *TR = + dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { + + QualType ValTy = TR->getValueType(getContext()); + if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) { + static int loadReferenceTag = 0; + ExplodedNodeSet Tmp; + EvalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag, + getContext().getPointerType(RT->getPointeeType())); + + // Perform the load from the referenced value. + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) { + state = GetState(*I); + location = state->getSVal(Ex); + EvalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy); + } + return; + } + } + + EvalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy); +} + +void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, Expr *Ex, + ExplodedNode* Pred, + const GRState* state, SVal location, + const void *tag, QualType LoadTy) { + // Evaluate the location (checks for bad dereferences). ExplodedNodeSet Tmp; EvalLocation(Tmp, Ex, Pred, state, location, tag, true); @@ -1489,94 +1633,111 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, // Transfer function: Function calls. //===----------------------------------------------------------------------===// +namespace { +class CallExprWLItem { +public: + CallExpr::arg_iterator I; + ExplodedNode *N; + + CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n) + : I(i), N(n) {} +}; +} // end anonymous namespace + void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - ExplodedNodeSet& Dst) { + ExplodedNodeSet& Dst, bool asLValue) { + // Determine the type of function we're calling (if available). const FunctionProtoType *Proto = NULL; QualType FnType = CE->getCallee()->IgnoreParens()->getType(); if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>(); - VisitCallRec(CE, Pred, AI, AE, Dst, Proto, /*ParamIdx=*/0); -} - -void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred, - CallExpr::arg_iterator AI, - CallExpr::arg_iterator AE, - ExplodedNodeSet& Dst, - const FunctionProtoType *Proto, - unsigned ParamIdx) { + // Create a worklist to process the arguments. + llvm::SmallVector<CallExprWLItem, 20> WorkList; + WorkList.reserve(AE - AI); + WorkList.push_back(CallExprWLItem(AI, Pred)); + + ExplodedNodeSet ArgsEvaluated; - // Process the arguments. - if (AI != AE) { - // If the call argument is being bound to a reference parameter, - // visit it as an lvalue, not an rvalue. + while (!WorkList.empty()) { + CallExprWLItem Item = WorkList.back(); + WorkList.pop_back(); + + if (Item.I == AE) { + ArgsEvaluated.insert(Item.N); + continue; + } + + // Evaluate the argument. + ExplodedNodeSet Tmp; + const unsigned ParamIdx = Item.I - AI; + bool VisitAsLvalue = false; if (Proto && ParamIdx < Proto->getNumArgs()) VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType(); - - ExplodedNodeSet DstTmp; + if (VisitAsLvalue) - VisitLValue(*AI, Pred, DstTmp); + VisitLValue(*Item.I, Item.N, Tmp); else - Visit(*AI, Pred, DstTmp); - ++AI; + Visit(*Item.I, Item.N, Tmp); + + // Enqueue evaluating the next argument on the worklist. + ++(Item.I); - for (ExplodedNodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; - ++DI) - VisitCallRec(CE, *DI, AI, AE, Dst, Proto, ParamIdx + 1); - - return; + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) + WorkList.push_back(CallExprWLItem(Item.I, *NI)); } - // If we reach here we have processed all of the arguments. Evaluate - // the callee expression. + // Now process the call itself. ExplodedNodeSet DstTmp; Expr* Callee = CE->getCallee()->IgnoreParens(); - - { // Enter new scope to make the lifetime of 'DstTmp2' bounded. + + for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(), + NE=ArgsEvaluated.end(); NI != NE; ++NI) { + // Evaluate the callee. ExplodedNodeSet DstTmp2; - Visit(Callee, Pred, DstTmp2); - + Visit(Callee, *NI, DstTmp2); // Perform the previsit of the CallExpr, storing the results in DstTmp. CheckerVisit(CE, DstTmp, DstTmp2, true); } - - // Finally, evaluate the function call. + + // Finally, evaluate the function call. We try each of the checkers + // to see if the can evaluate the function call. ExplodedNodeSet DstTmp3; + for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI != DE; ++DI) { - + const GRState* state = GetState(*DI); SVal L = state->getSVal(Callee); - + // FIXME: Add support for symbolic function calls (calls involving // function pointer values that are symbolic). SaveAndRestore<bool> OldSink(Builder->BuildSinks); ExplodedNodeSet DstChecker; - + // If the callee is processed by a checker, skip the rest logic. if (CheckerEvalCall(CE, DstChecker, *DI)) DstTmp3.insert(DstChecker); else { for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(), - DE_Checker = DstChecker.end(); - DI_Checker != DE_Checker; ++DI_Checker) { - - // Dispatch to the plug-in transfer function. + DE_Checker = DstChecker.end(); + DI_Checker != DE_Checker; ++DI_Checker) { + + // Dispatch to the plug-in transfer function. unsigned OldSize = DstTmp3.size(); SaveOr OldHasGen(Builder->HasGeneratedNode); Pred = *DI_Checker; - + // Dispatch to transfer function logic to handle the call itself. // FIXME: Allow us to chain together transfer functions. - assert(Builder && "GRStmtNodeBuilder must be defined."); - + assert(Builder && "GRStmtNodeBuilder must be defined."); getTF().EvalCall(DstTmp3, *this, *Builder, CE, L, Pred); - + // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. if (!Builder->BuildSinks && DstTmp3.size() == OldSize && @@ -1585,9 +1746,31 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred, } } } - - // Perform the post-condition check of the CallExpr. - CheckerVisit(CE, Dst, DstTmp3, false); + + // Finally, perform the post-condition check of the CallExpr and store + // the created nodes in 'Dst'. + + if (!(!asLValue && CalleeReturnsReference(CE))) { + CheckerVisit(CE, Dst, DstTmp3, false); + return; + } + + // Handle the case where the called function returns a reference but + // we expect an rvalue. For such cases, convert the reference to + // an rvalue. + // FIXME: This conversion doesn't actually happen unless the result + // of CallExpr is consumed by another expression. + ExplodedNodeSet DstTmp4; + CheckerVisit(CE, DstTmp4, DstTmp3, false); + QualType LoadTy = CE->getType(); + + static int *ConvertToRvalueTag = 0; + for (ExplodedNodeSet::iterator NI = DstTmp4.begin(), NE = DstTmp4.end(); + NI!=NE; ++NI) { + const GRState *state = GetState(*NI); + EvalLoad(Dst, CE, *NI, state, state->getSVal(CE), + &ConvertToRvalueTag, LoadTy); + } } //===----------------------------------------------------------------------===// @@ -1764,16 +1947,18 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, //===----------------------------------------------------------------------===// void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, - ExplodedNodeSet& Dst){ + ExplodedNodeSet& Dst, bool asLValue){ VisitObjCMessageExprArgHelper(ME, ME->arg_begin(), ME->arg_end(), - Pred, Dst); + Pred, Dst, asLValue); } void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, - ObjCMessageExpr::arg_iterator AI, - ObjCMessageExpr::arg_iterator AE, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { + ObjCMessageExpr::arg_iterator AI, + ObjCMessageExpr::arg_iterator AE, + ExplodedNode* Pred, + ExplodedNodeSet& Dst, + bool asLValue) { if (AI == AE) { // Process the receiver. @@ -1784,12 +1969,12 @@ void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI) - VisitObjCMessageExprDispatchHelper(ME, *NI, Dst); + VisitObjCMessageExprDispatchHelper(ME, *NI, Dst, asLValue); return; } - VisitObjCMessageExprDispatchHelper(ME, Pred, Dst); + VisitObjCMessageExprDispatchHelper(ME, Pred, Dst, asLValue); return; } @@ -1799,12 +1984,13 @@ void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, ++AI; for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI) - VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst); + VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst, asLValue); } void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { + ExplodedNodeSet& Dst, + bool asLValue) { // Handle previsits checks. ExplodedNodeSet Src, DstTmp; @@ -1812,12 +1998,17 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, CheckerVisit(ME, DstTmp, Src, true); - unsigned size = Dst.size(); + ExplodedNodeSet PostVisitSrc; for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) { + Pred = *DI; bool RaisesException = false; + + unsigned OldSize = PostVisitSrc.size(); + SaveAndRestore<bool> OldSink(Builder->BuildSinks); + SaveOr OldHasGen(Builder->HasGeneratedNode); if (const Expr *Receiver = ME->getReceiver()) { const GRState *state = Pred->getState(); @@ -1832,8 +2023,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, // There are three cases: can be nil or non-nil, must be nil, must be // non-nil. We handle must be nil, and merge the rest two into non-nil. if (nilState && !notNilState) { - CheckerEvalNilReceiver(ME, Dst, nilState, Pred); - return; + CheckerEvalNilReceiver(ME, PostVisitSrc, nilState, Pred); + continue; } assert(notNilState); @@ -1844,39 +2035,29 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, // Check if we raise an exception. For now treat these as sinks. // Eventually we will want to handle exceptions properly. - SaveAndRestore<bool> OldSink(Builder->BuildSinks); if (RaisesException) Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - SaveOr OldHasGen(Builder->HasGeneratedNode); - EvalObjCMessageExpr(Dst, ME, Pred, notNilState); + EvalObjCMessageExpr(PostVisitSrc, ME, Pred, notNilState); } else { - IdentifierInfo* ClsName = ME->getClassName(); Selector S = ME->getSelector(); // Check for special instance methods. - if (!NSExceptionII) { ASTContext& Ctx = getContext(); - NSExceptionII = &Ctx.Idents.get("NSException"); } if (ClsName == NSExceptionII) { - enum { NUM_RAISE_SELECTORS = 2 }; // Lazily create a cache of the selectors. - if (!NSExceptionInstanceRaiseSelectors) { - ASTContext& Ctx = getContext(); - NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS]; - llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II; unsigned idx = 0; @@ -1894,26 +2075,51 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) if (S == NSExceptionInstanceRaiseSelectors[i]) { - RaisesException = true; break; + RaisesException = true; + break; } } // Check if we raise an exception. For now treat these as sinks. // Eventually we will want to handle exceptions properly. - SaveAndRestore<bool> OldSink(Builder->BuildSinks); if (RaisesException) Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - SaveOr OldHasGen(Builder->HasGeneratedNode); - EvalObjCMessageExpr(Dst, ME, Pred, Builder->GetState(Pred)); + EvalObjCMessageExpr(PostVisitSrc, ME, Pred, Builder->GetState(Pred)); } + + // Handle the case where no nodes where generated. Auto-generate that + // contains the updated state if we aren't generating sinks. + if (!Builder->BuildSinks && PostVisitSrc.size() == OldSize && + !Builder->HasGeneratedNode) + MakeNode(PostVisitSrc, ME, Pred, GetState(Pred)); } - // Handle the case where no nodes where generated. Auto-generate that - // contains the updated state if we aren't generating sinks. - if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode) - MakeNode(Dst, ME, Pred, GetState(Pred)); + // Finally, perform the post-condition check of the ObjCMessageExpr and store + // the created nodes in 'Dst'. + if (!(!asLValue && ReceiverReturnsReference(ME))) { + CheckerVisit(ME, Dst, PostVisitSrc, false); + return; + } + + // Handle the case where the message expression returns a reference but + // we expect an rvalue. For such cases, convert the reference to + // an rvalue. + // FIXME: This conversion doesn't actually happen unless the result + // of ObjCMessageExpr is consumed by another expression. + ExplodedNodeSet DstRValueConvert; + CheckerVisit(ME, DstRValueConvert, PostVisitSrc, false); + QualType LoadTy = ME->getType(); + + static int *ConvertToRvalueTag = 0; + for (ExplodedNodeSet::iterator NI = DstRValueConvert.begin(), + NE = DstRValueConvert.end(); + NI!=NE; ++NI) { + const GRState *state = GetState(*NI); + EvalLoad(Dst, ME, *NI, state, state->getSVal(ME), + &ConvertToRvalueTag, LoadTy); + } } //===----------------------------------------------------------------------===// @@ -1921,7 +2127,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, //===----------------------------------------------------------------------===// void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, - ExplodedNodeSet& Dst){ + ExplodedNodeSet& Dst, bool asLValue){ ExplodedNodeSet S1; QualType T = CastE->getType(); QualType ExTy = Ex->getType(); @@ -1929,7 +2135,8 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) T = ExCast->getTypeAsWritten(); - if (ExTy->isArrayType() || ExTy->isFunctionType() || T->isReferenceType()) + if (ExTy->isArrayType() || ExTy->isFunctionType() || T->isReferenceType() || + asLValue) VisitLValue(Ex, Pred, S1); else Visit(Ex, Pred, S1); @@ -1939,10 +2146,19 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, // Check for casting to "void". if (T->isVoidType()) { + assert(!asLValue); for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) Dst.Add(*I); return; } + + // If we are evaluating the cast in an lvalue context, we implicitly want + // the cast to evaluate to a location. + if (asLValue) { + ASTContext &Ctx = getContext(); + T = Ctx.getPointerType(Ctx.getCanonicalType(T)); + ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy)); + } for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { ExplodedNode* N = *I; @@ -1992,8 +2208,12 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, // time a function is called those values may not be current. ExplodedNodeSet Tmp; - if (InitEx) - Visit(InitEx, Pred, Tmp); + if (InitEx) { + if (VD->getType()->isReferenceType()) + VisitLValue(InitEx, Pred, Tmp); + else + Visit(InitEx, Pred, Tmp); + } else Tmp.Add(Pred); @@ -2009,7 +2229,6 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, if (InitEx) { SVal InitVal = state->getSVal(InitEx); - QualType T = VD->getType(); // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. @@ -2020,7 +2239,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, } EvalBind(Dst, DS, DS, *I, state, - loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); + loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); } else { state = state->bindDeclWithNoInit(state->getRegion(VD, LC)); @@ -2029,6 +2248,33 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, } } +void GRExprEngine::VisitCondInit(VarDecl *VD, Stmt *S, + ExplodedNode *Pred, ExplodedNodeSet& Dst) { + + Expr* InitEx = VD->getInit(); + ExplodedNodeSet Tmp; + Visit(InitEx, Pred, Tmp); + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + ExplodedNode *N = *I; + const GRState *state = GetState(N); + + const LocationContext *LC = N->getLocationContext(); + SVal InitVal = state->getSVal(InitEx); + + // Recover some path-sensitivity if a scalar value evaluated to + // UnknownVal. + if (InitVal.isUnknown() || + !getConstraintManager().canReasonAbout(InitVal)) { + InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, + Builder->getCurrentBlockCount()); + } + + EvalBind(Dst, S, S, N, state, + loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); + } +} + namespace { // This class is used by VisitInitListExpr as an item in a worklist // for processing the values contained in an InitListExpr. @@ -2082,7 +2328,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, InitListExpr::reverse_iterator NewItr = X.Itr + 1; - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { + for (ExplodedNodeSet::iterator NI=Tmp.begin(),NE=Tmp.end();NI!=NE;++NI) { // Get the last initializer value. state = GetState(*NI); SVal InitV = state->getSVal(cast<Expr>(*X.Itr)); @@ -2114,7 +2360,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, ExplodedNodeSet Tmp; Expr* Init = E->getInit(0); Visit(Init, Pred, Tmp); - for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I != EI; ++I) { + for (ExplodedNodeSet::iterator I=Tmp.begin(), EI=Tmp.end(); I != EI; ++I) { state = GetState(*I); MakeNode(Dst, E, *I, state->BindExpr(E, state->getSVal(Init))); } @@ -2382,7 +2628,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, ExplodedNodeSet Tmp2; EvalLoad(Tmp2, Ex, *I, state, V1); - for (ExplodedNodeSet::iterator I2 = Tmp2.begin(), E2 = Tmp2.end(); I2!=E2; ++I2) { + for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) { state = GetState(*I2); SVal V2_untested = state->getSVal(Ex); @@ -2445,14 +2691,23 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, } } -void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst) { + +void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, + ExplodedNodeSet & Dst) { + // Get the this object region from StoreManager. + Loc V = getStoreManager().getThisObject(TE->getType()->getPointeeType()); + MakeNode(Dst, TE, Pred, GetState(Pred)->BindExpr(TE, V)); +} + +void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst); } void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A, AsmStmt::outputs_iterator I, AsmStmt::outputs_iterator E, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { + ExplodedNode* Pred, ExplodedNodeSet& Dst) { if (I == E) { VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst); return; @@ -2463,14 +2718,15 @@ void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A, ++I; - for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI) + for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI) VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst); } void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A, AsmStmt::inputs_iterator I, AsmStmt::inputs_iterator E, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { + ExplodedNode* Pred, + ExplodedNodeSet& Dst) { if (I == E) { // We have processed both the inputs and the outputs. All of the outputs @@ -2598,7 +2854,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, // Simulate the effects of a "store": bind the value of the RHS // to the L-Value represented by the LHS. - EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV); + EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV,RightV); continue; } diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index 84e268f..0b2620e 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -112,6 +112,11 @@ public: void VisitUnaryOperator(UnaryOperator* U); void Visit(Stmt *S); void VisitTerminator(CFGBlock* B); + + /// VisitConditionVariableInit - Handle the initialization of condition + /// variables at branches. Valid statements include IfStmt, ForStmt, + /// WhileStmt, and SwitchStmt. + void VisitConditionVariableInit(Stmt *S); void SetTopValue(LiveVariables::ValTy& V) { V = AD.AlwaysLive; @@ -126,7 +131,9 @@ void TransferFuncs::Visit(Stmt *S) { if (AD.Observer) AD.Observer->ObserveStmt(S,AD,LiveState); - if (getCFG().isBlkExpr(S)) LiveState(S,AD) = Dead; + if (getCFG().isBlkExpr(S)) + LiveState(S, AD) = Dead; + StmtVisitor<TransferFuncs,void>::Visit(S); } else if (!getCFG().isBlkExpr(S)) { @@ -142,6 +149,11 @@ void TransferFuncs::Visit(Stmt *S) { LiveState(S,AD) = Alive; } } + +void TransferFuncs::VisitConditionVariableInit(Stmt *S) { + assert(!getCFG().isBlkExpr(S)); + CFGRecStmtVisitor<TransferFuncs>::VisitConditionVariableInit(S); +} void TransferFuncs::VisitTerminator(CFGBlock* B) { @@ -289,17 +301,8 @@ void TransferFuncs::VisitDeclStmt(DeclStmt* DS) { //===----------------------------------------------------------------------===// namespace { - -struct Merge { - typedef StmtDeclBitVector_Types::ValTy ValTy; - - void operator()(ValTy& Dst, const ValTy& Src) { - Dst.OrDeclBits(Src); - Dst.OrBlkExprBits(Src); - } -}; - -typedef DataflowSolver<LiveVariables, TransferFuncs, Merge> Solver; + typedef StmtDeclBitVector_Types::Union Merge; + typedef DataflowSolver<LiveVariables, TransferFuncs, Merge> Solver; } // end anonymous namespace //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp index 2ed070a..fab73ee 100644 --- a/lib/Analysis/MallocChecker.cpp +++ b/lib/Analysis/MallocChecker.cpp @@ -23,13 +23,13 @@ using namespace clang; namespace { class RefState { - enum Kind { Allocated, Released, Escaped } K; + enum Kind { AllocateUnchecked, AllocateFailed, Released, Escaped } K; const Stmt *S; public: RefState(Kind k, const Stmt *s) : K(k), S(s) {} - bool isAllocated() const { return K == Allocated; } + bool isAllocated() const { return K == AllocateUnchecked; } bool isReleased() const { return K == Released; } bool isEscaped() const { return K == Escaped; } @@ -37,7 +37,12 @@ public: return K == X.K && S == X.S; } - static RefState getAllocated(const Stmt *s) { return RefState(Allocated, s); } + static RefState getAllocateUnchecked(const Stmt *s) { + return RefState(AllocateUnchecked, s); + } + static RefState getAllocateFailed() { + return RefState(AllocateFailed, 0); + } static RefState getReleased(const Stmt *s) { return RefState(Released, s); } static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); } @@ -62,6 +67,8 @@ public: void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper); void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng); void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); + const GRState *EvalAssume(const GRState *state, SVal Cond, bool Assumption); + private: void MallocMem(CheckerContext &C, const CallExpr *CE); const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, @@ -74,6 +81,8 @@ private: }; } // end anonymous namespace +typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy; + namespace clang { template <> struct GRStateTrait<RegionState> @@ -144,7 +153,7 @@ const GRState *MallocChecker::MallocMemAux(CheckerContext &C, SymbolRef Sym = RetVal.getAsLocSymbol(); assert(Sym); // Set the symbol's state to Allocated. - return state->set<RegionState>(Sym, RefState::getAllocated(CE)); + return state->set<RegionState>(Sym, RefState::getAllocateUnchecked(CE)); } void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { @@ -298,3 +307,18 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) { C.addTransition(state); } + +const GRState *MallocChecker::EvalAssume(const GRState *state, SVal Cond, + bool Assumption) { + // If a symblic region is assumed to NULL, set its state to AllocateFailed. + // FIXME: should also check symbols assumed to non-null. + + RegionStateTy RS = state->get<RegionState>(); + + for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { + if (state->getSymVal(I.getKey())) + state = state->set<RegionState>(I.getKey(),RefState::getAllocateFailed()); + } + + return state; +} diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index bc3a5b7..74fe3bf 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -291,6 +291,17 @@ void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const { BlockDataRegion::ProfileRegion(ID, BC, LC, getSuperRegion()); } +void CXXObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, + QualType T, + const MemRegion *sReg) { + ID.AddPointer(T.getTypePtr()); + ID.AddPointer(sReg); +} + +void CXXObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const { + ProfileRegion(ID, T, getSuperRegion()); +} + //===----------------------------------------------------------------------===// // Region pretty-printing. //===----------------------------------------------------------------------===// @@ -552,10 +563,9 @@ MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, return getSubRegion<ObjCIvarRegion>(d, superRegion); } -const ObjCObjectRegion* -MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d, - const MemRegion* superRegion) { - return getSubRegion<ObjCObjectRegion>(d, superRegion); +const CXXObjectRegion * +MemRegionManager::getCXXObjectRegion(QualType T) { + return getSubRegion<CXXObjectRegion>(T, getUnknownRegion()); } const AllocaRegion* diff --git a/lib/Analysis/NoReturnFunctionChecker.cpp b/lib/Analysis/NoReturnFunctionChecker.cpp index 6806273..5cfd9ac 100644 --- a/lib/Analysis/NoReturnFunctionChecker.cpp +++ b/lib/Analysis/NoReturnFunctionChecker.cpp @@ -45,13 +45,12 @@ bool NoReturnFunctionChecker::EvalCallExpr(CheckerContext &C, if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>()) BuildSinks = true; - else { + else if (const IdentifierInfo *II = FD->getIdentifier()) { // HACK: Some functions are not marked noreturn, and don't return. // Here are a few hardwired ones. If this takes too long, we can // potentially cache these results. - using llvm::StringRef; BuildSinks - = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName())) + = llvm::StringSwitch<bool>(llvm::StringRef(II->getName())) .Case("exit", true) .Case("panic", true) .Case("error", true) diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Analysis/OSAtomicChecker.cpp index 5a89345..cf16796 100644 --- a/lib/Analysis/OSAtomicChecker.cpp +++ b/lib/Analysis/OSAtomicChecker.cpp @@ -44,11 +44,15 @@ bool OSAtomicChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE) { if (!FD) return false; - const char *FName = FD->getNameAsCString(); + const IdentifierInfo *II = FD->getIdentifier(); + if (!II) + return false; + + llvm::StringRef FName(II->getName()); // Check for compare and swap. - if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 || - strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0) + if (FName.startswith("OSAtomicCompareAndSwap") || + FName.startswith("objc_atomicCompareAndSwap")) return EvalOSAtomicCompareAndSwap(C, CE); // FIXME: Other atomics. diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index b5eeb1e..3bc9dcc 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -349,6 +349,7 @@ public: SVal RetrieveArray(const GRState *St, const TypedRegion* R); + /// Get the state and region whose binding this region R corresponds to. std::pair<const GRState*, const MemRegion*> GetLazyBinding(RegionBindings B, const MemRegion *R); @@ -539,8 +540,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, } // Handle the region itself. - if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) || - isa<ObjCObjectRegion>(R)) { + if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R)) { // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelavant. DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy, @@ -744,8 +744,8 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, case MemRegion::ElementRegionKind: case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: - case MemRegion::ObjCObjectRegionKind: case MemRegion::SymbolicRegionKind: + case MemRegion::CXXObjectRegionKind: return UnknownVal(); case MemRegion::StringRegionKind: { @@ -867,8 +867,8 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, // Fall-through. case MemRegion::CompoundLiteralRegionKind: case MemRegion::FieldRegionKind: - case MemRegion::ObjCObjectRegionKind: case MemRegion::ObjCIvarRegionKind: + case MemRegion::CXXObjectRegionKind: return UnknownVal(); case MemRegion::FunctionTextRegionKind: @@ -987,12 +987,12 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { assert(!isa<UnknownVal>(L) && "location unknown"); assert(!isa<UndefinedVal>(L) && "location undefined"); - + // FIXME: Is this even possible? Shouldn't this be treated as a null // dereference at a higher level? if (isa<loc::ConcreteInt>(L)) return SValuator::CastResult(state, UndefinedVal()); - + const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion(); // FIXME: return symbolic value for these cases. @@ -1090,8 +1090,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { } // All other values are symbolic. - return SValuator::CastResult(state, - ValMgr.getRegionValueSymbolValOrUnknown(R, RTy)); + return SValuator::CastResult(state, ValMgr.getRegionValueSymbolVal(R, RTy)); } std::pair<const GRState*, const MemRegion*> @@ -1256,7 +1255,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state, } // All other values are symbolic. - return ValMgr.getRegionValueSymbolValOrUnknown(R, Ty); + return ValMgr.getRegionValueSymbolVal(R, Ty); } SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state, @@ -1296,7 +1295,7 @@ SVal RegionStoreManager::RetrieveVar(const GRState *state, if (R->hasGlobalsOrParametersStorage() || isa<UnknownSpaceRegion>(R->getMemorySpace())) - return ValMgr.getRegionValueSymbolValOrUnknown(R, VD->getType()); + return ValMgr.getRegionValueSymbolVal(R, VD->getType()); return UndefinedVal(); } @@ -1307,7 +1306,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const GRState *state, QualType valTy = R->getValueType(getContext()); // All other values are symbolic. - return ValMgr.getRegionValueSymbolValOrUnknown(R, valTy); + return ValMgr.getRegionValueSymbolVal(R, valTy); } SVal RegionStoreManager::RetrieveStruct(const GRState *state, @@ -1425,7 +1424,13 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { // Binding directly to a symbolic region should be treated as binding // to element 0. QualType T = SR->getSymbol()->getType(getContext()); - T = T->getAs<PointerType>()->getPointeeType(); + + // FIXME: Is this the right way to handle symbols that are references? + if (const PointerType *PT = T->getAs<PointerType>()) + T = PT->getPointeeType(); + else + T = T->getAs<ReferenceType>()->getPointeeType(); + R = GetElementZeroRegion(SR, T); } diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp index ac727b0..49bc0c4 100644 --- a/lib/Analysis/SValuator.cpp +++ b/lib/Analysis/SValuator.cpp @@ -72,10 +72,14 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, // Check for casts from integers to pointers. if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) { if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) { - // Just unpackage the lval and return it. + if (const MemRegion *R = LV->getLoc().getAsRegion()) { + StoreManager &storeMgr = ValMgr.getStateManager().getStoreManager(); + R = storeMgr.CastRegion(R, castTy); + return R ? CastResult(state, loc::MemRegionVal(R)) + : CastResult(state, UnknownVal()); + } return CastResult(state, LV->getLoc()); } - goto DispatchCast; } @@ -136,15 +140,12 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, // different type. If the MemRegion* returned is NULL, this expression // evaluates to UnknownVal. R = storeMgr.CastRegion(R, castTy); - - if (R) - return CastResult(state, loc::MemRegionVal(R)); - - return CastResult(state, UnknownVal()); + return R ? CastResult(state, loc::MemRegionVal(R)) + : CastResult(state, UnknownVal()); } - // All other cases. DispatchCast: + // All other cases. return CastResult(state, isa<Loc>(val) ? EvalCastL(cast<Loc>(val), castTy) : EvalCastNL(cast<NonLoc>(val), castTy)); diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Analysis/SimpleConstraintManager.cpp index 015db76..23c3b41 100644 --- a/lib/Analysis/SimpleConstraintManager.cpp +++ b/lib/Analysis/SimpleConstraintManager.cpp @@ -15,6 +15,7 @@ #include "SimpleConstraintManager.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/PathSensitive/Checker.h" namespace clang { @@ -72,8 +73,17 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc Cond, // EvalAssume is used to call into the GRTransferFunction object to perform // any checker-specific update of the state based on this assumption being // true or false. - return state ? state->getTransferFuncs().EvalAssume(state, Cond, Assumption) - : NULL; + + if (!state) + return 0; + + std::vector<std::pair<void *, Checker*> >::iterator + I = state->checker_begin(), E = state->checker_end(); + + for (; I != E; ++I) { + state = I->second->EvalAssume(state, Cond, Assumption); + } + return state->getTransferFuncs().EvalAssume(state, Cond, Assumption); } const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, @@ -128,8 +138,18 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state, // EvalAssume is used to call into the GRTransferFunction object to perform // any checker-specific update of the state based on this assumption being // true or false. - return state ? state->getTransferFuncs().EvalAssume(state, Cond, Assumption) - : NULL; + + if (!state) + return 0; + + std::vector<std::pair<void *, Checker*> >::iterator + I = state->checker_begin(), E = state->checker_end(); + + for (; I != E; ++I) { + state = I->second->EvalAssume(state, Cond, Assumption); + } + + return state->getTransferFuncs().EvalAssume(state, Cond, Assumption); } const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp index e6ff6e5..8d911b8 100644 --- a/lib/Analysis/Store.cpp +++ b/lib/Analysis/Store.cpp @@ -98,7 +98,6 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) } case MemRegion::StringRegionKind: - case MemRegion::ObjCObjectRegionKind: // FIXME: Need to handle arbitrary downcasts. case MemRegion::SymbolicRegionKind: case MemRegion::AllocaRegionKind: @@ -106,6 +105,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: case MemRegion::VarRegionKind: + case MemRegion::CXXObjectRegionKind: return MakeElementRegion(R, PointeeTy); case MemRegion::ElementRegionKind: { @@ -198,11 +198,21 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) /// as another region. SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, QualType castTy) { + +#ifndef NDEBUG if (castTy.isNull()) return V; + + ASTContext &Ctx = ValMgr.getContext(); + QualType T = R->getValueType(Ctx); + + // Automatically translate references to pointers. + if (const ReferenceType *RT = T->getAs<ReferenceType>()) + T = Ctx.getPointerType(RT->getPointeeType()); + + assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T)); +#endif - assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, - R->getValueType(ValMgr.getContext()))); return V; } @@ -230,3 +240,8 @@ SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL, const LocationContext *LC) { return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)); } + +Loc StoreManager::getThisObject(QualType T) { + const CXXObjectRegion *R = MRMgr.getCXXObjectRegion(T); + return loc::MemRegionVal(R); +} diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 8d0d813..4351f66 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -203,6 +203,7 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { AllExtensionsSilenced = 0; IgnoreAllWarnings = false; WarningsAsErrors = false; + ErrorsAsFatal = false; SuppressSystemWarnings = false; SuppressAllDiagnostics = false; ExtBehavior = Ext_Ignore; @@ -326,9 +327,13 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const { return Diagnostic::Ignored; Result = Diagnostic::Warning; if (ExtBehavior == Ext_Error) Result = Diagnostic::Error; + if (Result == Diagnostic::Error && ErrorsAsFatal) + Result = Diagnostic::Fatal; break; case diag::MAP_ERROR: Result = Diagnostic::Error; + if (ErrorsAsFatal) + Result = Diagnostic::Fatal; break; case diag::MAP_FATAL: Result = Diagnostic::Fatal; @@ -349,6 +354,8 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const { if (WarningsAsErrors) Result = Diagnostic::Error; + if (Result == Diagnostic::Error && ErrorsAsFatal) + Result = Diagnostic::Fatal; break; case diag::MAP_WARNING_NO_WERROR: @@ -361,6 +368,12 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const { return Diagnostic::Ignored; break; + + case diag::MAP_ERROR_NO_WFATAL: + // Diagnostics specified as -Wno-fatal-error=foo should be errors, but + // unaffected by -Wfatal-errors. + Result = Diagnostic::Error; + break; } // Okay, we're about to return this as a "diagnostic to emit" one last check: diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index 434ff39..c4296c3 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -219,6 +219,11 @@ static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr, /// const DirectoryEntry *FileManager::getDirectory(const char *NameStart, const char *NameEnd) { + // stat doesn't like trailing separators (at least on Windows). + if (((NameEnd - NameStart) > 1) && + ((*(NameEnd - 1) == '/') || (*(NameEnd - 1) == '\\'))) + NameEnd--; + ++NumDirLookups; llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt = DirEntries.GetOrCreateValue(NameStart, NameEnd); diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index a1f97f4..493beee 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -360,6 +360,8 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, Info.setAllowsRegister(); break; case 'm': // memory operand. + case 'o': // offsettable memory operand + case 'V': // non-offsettable memory operand Info.setAllowsMemory(); break; case 'g': // general register, memory operand or immediate integer. diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index e5a4c43..b6b5c6c 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -323,11 +323,14 @@ protected: Define(Defs, "__PPU__", "1"); Define(Defs, "__CELLOS_LV2__", "1"); Define(Defs, "__ELF__", "1"); + Define(Defs, "__LP32__", "1"); } public: PS3PPUTargetInfo(const std::string& triple) : OSTargetInfo<Target>(triple) { this->UserLabelPrefix = ""; + this->LongWidth = this->LongAlign = this->PointerWidth = this->PointerAlign = 32; + this->SizeType = TargetInfo::UnsignedInt; } }; @@ -625,7 +628,7 @@ const Builtin::Info BuiltinInfo[] = { #include "clang/Basic/BuiltinsX86.def" }; -const char *GCCRegNames[] = { +static const char* const GCCRegNames[] = { "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", "argp", "flags", "fspr", "dirflag", "frame", @@ -685,7 +688,7 @@ public: bool Enabled) const; virtual void getDefaultFeatures(const std::string &CPU, llvm::StringMap<bool> &Features) const; - virtual void HandleTargetFeatures(const std::vector<std::string> &Features); + virtual void HandleTargetFeatures(std::vector<std::string> &Features); }; void X86TargetInfo::getDefaultFeatures(const std::string &CPU, @@ -802,8 +805,7 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, /// HandleTargetOptions - Perform initialization based on the user /// configured set of features. -void -X86TargetInfo::HandleTargetFeatures(const std::vector<std::string> &Features) { +void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) { // Remember the maximum enabled sselevel. for (unsigned i = 0, e = Features.size(); i !=e; ++i) { // Ignore disabled features. @@ -993,8 +995,8 @@ public: WCharType = UnsignedShort; DoubleAlign = LongLongAlign = 64; DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" - "a0:0:64-f80:32:32-n8:16:32"; + "i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-" + "v128:128:128-a0:0:64-f80:32:32-n8:16:32"; } virtual void getTargetDefines(const LangOptions &Opts, std::vector<char> &Defines) const { @@ -1181,52 +1183,40 @@ public: namespace { class ARMTargetInfo : public TargetInfo { - enum { - Armv4t, - Armv5, - Armv6, - Armv7a, - XScale - } ArmArch; + // Possible FPU choices. + enum FPUMode { + NoFPU, + VFP2FPU, + VFP3FPU, + NeonFPU + }; - static const TargetInfo::GCCRegAlias GCCRegAliases[]; - static const char * const GCCRegNames[]; + static bool FPUModeIsVFP(FPUMode Mode) { + return Mode >= VFP2FPU && Mode <= NeonFPU; + } + + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char * const GCCRegNames[]; - std::string ABI; - bool IsThumb; + std::string ABI, CPU; + + unsigned FPU : 3; + + unsigned IsThumb : 1; + + // Initialized via features. + unsigned SoftFloat : 1; + unsigned SoftFloatABI : 1; public: ARMTargetInfo(const std::string &TripleStr) - : TargetInfo(TripleStr), ABI("aapcs-linux"), IsThumb(false) + : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s") { - llvm::Triple Triple(TripleStr); - SizeType = UnsignedInt; PtrDiffType = SignedInt; - // FIXME: This shouldn't be done this way, we should use features to - // indicate the arch. See lib/Driver/Tools.cpp. - llvm::StringRef Version(""), Arch = Triple.getArchName(); - if (Arch.startswith("arm")) - Version = Arch.substr(3); - else if (Arch.startswith("thumb")) - Version = Arch.substr(5); - if (Version == "v7") - ArmArch = Armv7a; - else if (Version.empty() || Version == "v6" || Version == "v6t2") - ArmArch = Armv6; - else if (Version == "v5") - ArmArch = Armv5; - else if (Version == "v4t") - ArmArch = Armv4t; - else if (Arch == "xscale" || Arch == "thumbv5e") - ArmArch = XScale; - else - ArmArch = Armv6; - - if (Arch.startswith("thumb")) - IsThumb = true; - + // FIXME: Should we just treat this as a feature? + IsThumb = getTriple().getArchName().startswith("thumb"); if (IsThumb) { DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-" @@ -1269,6 +1259,88 @@ public: return true; } + + void getDefaultFeatures(const std::string &CPU, + llvm::StringMap<bool> &Features) const { + // FIXME: This should not be here. + Features["vfp2"] = false; + Features["vfp3"] = false; + Features["neon"] = false; + + if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore") + Features["vfp2"] = true; + else if (CPU == "cortex-a8" || CPU == "cortex-a9") + Features["neon"] = true; + } + + virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features, + const std::string &Name, + bool Enabled) const { + if (Name == "soft-float" || Name == "soft-float-abi") { + Features[Name] = Enabled; + } else if (Name == "vfp2" || Name == "vfp3" || Name == "neon") { + // These effectively are a single option, reset them when any is enabled. + if (Enabled) + Features["vfp2"] = Features["vfp3"] = Features["neon"] = false; + Features[Name] = Enabled; + } else + return false; + + return true; + } + + virtual void HandleTargetFeatures(std::vector<std::string> &Features) { + FPU = NoFPU; + SoftFloat = SoftFloatABI = false; + for (unsigned i = 0, e = Features.size(); i != e; ++i) { + if (Features[i] == "+soft-float") + SoftFloat = true; + else if (Features[i] == "+soft-float-abi") + SoftFloatABI = true; + else if (Features[i] == "+vfp2") + FPU = VFP2FPU; + else if (Features[i] == "+vfp3") + FPU = VFP3FPU; + else if (Features[i] == "+neon") + FPU = NeonFPU; + } + + // Remove front-end specific options which the backend handles differently. + std::vector<std::string>::iterator it; + it = std::find(Features.begin(), Features.end(), "+soft-float"); + if (it != Features.end()) + Features.erase(it); + it = std::find(Features.begin(), Features.end(), "+soft-float-abi"); + if (it != Features.end()) + Features.erase(it); + } + + static const char *getCPUDefineSuffix(llvm::StringRef Name) { + return llvm::StringSwitch<const char*>(Name) + .Cases("arm8", "arm810", "4") + .Cases("strongarm", "strongarm110", "strongarm1100", "strongarm1110", "4") + .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "arm720t", "arm9", "4T") + .Cases("arm9tdmi", "arm920", "arm920t", "arm922t", "arm940t", "4T") + .Case("ep9312", "4T") + .Cases("arm10tdmi", "arm1020t", "5T") + .Cases("arm9e", "arm946e-s", "arm966e-s", "arm968e-s", "5TE") + .Case("arm926ej-s", "5TEJ") + .Cases("arm10e", "arm1020e", "arm1022e", "5TE") + .Cases("xscale", "iwmmxt", "5TE") + .Case("arm1136j-s", "6J") + .Cases("arm1176jz-s", "arm1176jzf-s", "6ZK") + .Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K") + .Cases("arm1156t2-s", "arm1156t2f-s", "6T2") + .Cases("cortex-a8", "cortex-a9", "7A") + .Default(0); + } + virtual bool setCPU(const std::string &Name) { + if (!getCPUDefineSuffix(Name)) + return false; + + CPU = Name; + return true; + } virtual void getTargetDefines(const LangOptions &Opts, std::vector<char> &Defs) const { // Target identification. @@ -1276,46 +1348,55 @@ public: Define(Defs, "__arm__"); // Target properties. + Define(Defs, "__ARMEL__"); Define(Defs, "__LITTLE_ENDIAN__"); + Define(Defs, "__REGISTER_PREFIX__", ""); + + llvm::StringRef CPUArch = getCPUDefineSuffix(CPU); + std::string ArchName = "__ARM_ARCH_"; + ArchName += CPUArch; + ArchName += "__"; + Define(Defs, ArchName); // Subtarget options. - // - // FIXME: Neither THUMB_INTERWORK nor SOFTFP is not being set correctly - // here. - if (ArmArch == Armv7a) { - Define(Defs, "__ARM_ARCH_7A__"); - Define(Defs, "__THUMB_INTERWORK__"); - } else if (ArmArch == Armv6) { - Define(Defs, "__ARM_ARCH_6K__"); - Define(Defs, "__THUMB_INTERWORK__"); - } else if (ArmArch == Armv5) { - Define(Defs, "__ARM_ARCH_5TEJ__"); + + // FIXME: It's more complicated than this and we don't really support + // interworking. + if ('5' <= CPUArch[0] && CPUArch[0] <= '7') Define(Defs, "__THUMB_INTERWORK__"); + + if (ABI == "aapcs" || ABI == "aapcs-linux") + Define(Defs, "__ARM_EABI__"); + + if (SoftFloat) Define(Defs, "__SOFTFP__"); - } else if (ArmArch == Armv4t) { - Define(Defs, "__ARM_ARCH_4T__"); - Define(Defs, "__SOFTFP__"); - } else if (ArmArch == XScale) { - Define(Defs, "__ARM_ARCH_5TE__"); - Define(Defs, "__XSCALE__"); - Define(Defs, "__SOFTFP__"); - } - Define(Defs, "__ARMEL__"); + if (CPU == "xscale") + Define(Defs, "__XSCALE__"); + bool IsThumb2 = IsThumb && (CPUArch == "6T2" || CPUArch.startswith("7")); if (IsThumb) { Define(Defs, "__THUMBEL__"); Define(Defs, "__thumb__"); - if (ArmArch == Armv7a) + if (IsThumb2) Define(Defs, "__thumb2__"); } // Note, this is always on in gcc, even though it doesn't make sense. Define(Defs, "__APCS_32__"); - // FIXME: This should be conditional on VFP instruction support. - Define(Defs, "__VFP_FP__"); - Define(Defs, "__USING_SJLJ_EXCEPTIONS__"); + if (FPUModeIsVFP((FPUMode) FPU)) + Define(Defs, "__VFP_FP__"); + + // This only gets set when Neon instructions are actually available, unlike + // the VFP define, hence the soft float and arch check. This is subtly + // different from gcc, we follow the intent which was that it should be set + // when Neon instructions are actually available. + if (FPU == NeonFPU && !SoftFloat && IsThumb2) + Define(Defs, "__ARM_NEON__"); + + if (getTriple().getOS() == llvm::Triple::Darwin) + Define(Defs, "__USING_SJLJ_EXCEPTIONS__"); } virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const { @@ -1602,7 +1683,7 @@ namespace { IntPtrType = SignedShort; PtrDiffType = SignedInt; SigAtomicType = SignedLong; - DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-n8:16"; + DescriptionString = "e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32-n8:16"; } virtual void getTargetDefines(const LangOptions &Opts, std::vector<char> &Defines) const { @@ -2111,7 +2192,7 @@ static TargetInfo *AllocateTarget(const std::string &T) { /// CreateTargetInfo - Return the target info object for the specified target /// triple. TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags, - const TargetOptions &Opts) { + TargetOptions &Opts) { llvm::Triple Triple(Opts.Triple); // Construct the target @@ -2121,6 +2202,12 @@ TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags, return 0; } + // Set the target CPU if specified. + if (!Opts.CPU.empty() && !Target->setCPU(Opts.CPU)) { + Diags.Report(diag::err_target_unknown_cpu) << Opts.CPU; + return 0; + } + // Set the target ABI if specified. if (!Opts.ABI.empty() && !Target->setABI(Opts.ABI)) { Diags.Report(diag::err_target_unknown_abi) << Opts.ABI; @@ -2149,11 +2236,11 @@ TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags, // // FIXME: If we are completely confident that we have the right set, we only // need to pass the minuses. - std::vector<std::string> StrFeatures; + Opts.Features.clear(); for (llvm::StringMap<bool>::const_iterator it = Features.begin(), ie = Features.end(); it != ie; ++it) - StrFeatures.push_back(std::string(it->second ? "+" : "-") + it->first()); - Target->HandleTargetFeatures(StrFeatures); + Opts.Features.push_back(std::string(it->second ? "+" : "-") + it->first()); + Target->HandleTargetFeatures(Opts.Features); return Target.take(); } diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 9e44db0..1bece7f 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -460,7 +460,8 @@ const llvm::Type *BlockModule::getGenericExtendedBlockLiteralType() { return GenericExtendedBlockLiteralType; } -RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) { +RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, + ReturnValueSlot ReturnValue) { const BlockPointerType *BPT = E->getCallee()->getType()->getAs<BlockPointerType>(); @@ -509,7 +510,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) { Func = Builder.CreateBitCast(Func, BlockFTyPtr); // And call the block. - return EmitCall(FnInfo, Func, Args); + return EmitCall(FnInfo, Func, ReturnValue, Args); } uint64_t CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index c704432..866c587 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -209,10 +209,19 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, const llvm::Type *ResType[] = { ConvertType(E->getType()) }; + + // LLVM only supports 0 and 2, make sure that we pass along that + // as a boolean. + Value *Ty = EmitScalarExpr(E->getArg(1)); + ConstantInt *CI = dyn_cast<ConstantInt>(Ty); + assert(CI); + uint64_t val = CI->getZExtValue(); + CI = ConstantInt::get(llvm::Type::getInt1Ty(VMContext), (val & 0x2) >> 1); + Value *F = CGM.getIntrinsic(Intrinsic::objectsize, ResType, 1); return RValue::get(Builder.CreateCall2(F, EmitScalarExpr(E->getArg(0)), - EmitScalarExpr(E->getArg(1)))); + CI)); } case Builtin::BI__builtin_prefetch: { Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0)); @@ -229,6 +238,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall(F)); } case Builtin::BI__builtin_unreachable: { + if (CatchUndefined && HaveInsertPoint()) + EmitBranch(getTrapBB()); Value *V = Builder.CreateUnreachable(); Builder.ClearInsertionPoint(); return RValue::get(V); @@ -300,6 +311,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1)); return RValue::get(Address); } + case Builtin::BImemcpy: case Builtin::BI__builtin_memcpy: { Value *Address = EmitScalarExpr(E->getArg(0)); Builder.CreateCall4(CGM.getMemCpyFn(), Address, @@ -308,6 +320,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1)); return RValue::get(Address); } + case Builtin::BImemmove: case Builtin::BI__builtin_memmove: { Value *Address = EmitScalarExpr(E->getArg(0)); Builder.CreateCall4(CGM.getMemMoveFn(), Address, @@ -316,6 +329,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1)); return RValue::get(Address); } + case Builtin::BImemset: case Builtin::BI__builtin_memset: { Value *Address = EmitScalarExpr(E->getArg(0)); Builder.CreateCall4(CGM.getMemSetFn(), Address, @@ -326,12 +340,20 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Address); } case Builtin::BI__builtin_return_address: { + Value *Depth = EmitScalarExpr(E->getArg(0)); + Depth = Builder.CreateIntCast(Depth, + llvm::Type::getInt32Ty(VMContext), + false, "tmp"); Value *F = CGM.getIntrinsic(Intrinsic::returnaddress, 0, 0); - return RValue::get(Builder.CreateCall(F, EmitScalarExpr(E->getArg(0)))); + return RValue::get(Builder.CreateCall(F, Depth)); } case Builtin::BI__builtin_frame_address: { + Value *Depth = EmitScalarExpr(E->getArg(0)); + Depth = Builder.CreateIntCast(Depth, + llvm::Type::getInt32Ty(VMContext), + false, "tmp"); Value *F = CGM.getIntrinsic(Intrinsic::frameaddress, 0, 0); - return RValue::get(Builder.CreateCall(F, EmitScalarExpr(E->getArg(0)))); + return RValue::get(Builder.CreateCall(F, Depth)); } case Builtin::BI__builtin_extract_return_addr: { // FIXME: There should be a target hook for this @@ -565,9 +587,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // that function. if (getContext().BuiltinInfo.isLibFunction(BuiltinID) || getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID)) - return EmitCall(CGM.getBuiltinLibFunction(FD, BuiltinID), - E->getCallee()->getType(), E->arg_begin(), - E->arg_end()); + return EmitCall(E->getCallee()->getType(), + CGM.getBuiltinLibFunction(FD, BuiltinID), + ReturnValueSlot(), + E->arg_begin(), E->arg_end()); // See if we have a target specific intrinsic. const char *Name = getContext().BuiltinInfo.GetName(BuiltinID); @@ -848,7 +871,5 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { - switch (BuiltinID) { - default: return 0; - } + return 0; } diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 0d11be2..cc006d9 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -28,6 +28,7 @@ using namespace CodeGen; RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, llvm::Value *Callee, + ReturnValueSlot ReturnValue, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { @@ -46,8 +47,8 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, EmitCallArgs(Args, FPT, ArgBeg, ArgEnd); QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); - return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), - Callee, Args, MD); + return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, + ReturnValue, Args, MD); } /// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given @@ -78,9 +79,10 @@ static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) { return false; } -RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { +RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, + ReturnValueSlot ReturnValue) { if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens())) - return EmitCXXMemberPointerCallExpr(CE); + return EmitCXXMemberPointerCallExpr(CE, ReturnValue); const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens()); const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); @@ -88,9 +90,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { if (MD->isStatic()) { // The method is static, emit it as we would a regular call. llvm::Value *Callee = CGM.GetAddrOfFunction(MD); - return EmitCall(Callee, getContext().getPointerType(MD->getType()), - CE->arg_begin(), CE->arg_end(), 0); - + return EmitCall(getContext().getPointerType(MD->getType()), Callee, + ReturnValue, CE->arg_begin(), CE->arg_end()); } const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); @@ -139,12 +140,13 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { Callee = CGM.GetAddrOfFunction(MD, Ty); } - return EmitCXXMemberCall(MD, Callee, This, + return EmitCXXMemberCall(MD, Callee, ReturnValue, This, CE->arg_begin(), CE->arg_end()); } RValue -CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) { +CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, + ReturnValueSlot ReturnValue) { const BinaryOperator *BO = cast<BinaryOperator>(E->getCallee()->IgnoreParens()); const Expr *BaseExpr = BO->getLHS(); @@ -247,13 +249,14 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) { // And the rest of the call args EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end()); QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType(); - return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), - Callee, Args, 0); + return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, + ReturnValue, Args); } RValue CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, - const CXXMethodDecl *MD) { + const CXXMethodDecl *MD, + ReturnValueSlot ReturnValue) { assert(MD->isInstance() && "Trying to emit a member call expr on a static method!"); @@ -283,7 +286,7 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, else Callee = CGM.GetAddrOfFunction(MD, Ty); - return EmitCXXMemberCall(MD, Callee, This, + return EmitCXXMemberCall(MD, Callee, ReturnValue, This, E->arg_begin() + 1, E->arg_end()); } @@ -508,7 +511,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { - if (D->isCopyConstructor(getContext())) { + if (D->isCopyConstructor()) { const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext()); if (ClassDecl->hasTrivialCopyConstructor()) { assert(!ClassDecl->hasUserDeclaredCopyConstructor() && @@ -527,7 +530,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); - EmitCXXMemberCall(D, Callee, This, ArgBeg, ArgEnd); + EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, ArgBeg, ArgEnd); } void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, @@ -552,7 +555,8 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, // FIXME: We should try to share this code with EmitCXXMemberCall. QualType ResultType = DD->getType()->getAs<FunctionType>()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, Args, DD); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, + ReturnValueSlot(), Args, DD); } void @@ -564,22 +568,33 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, getContext().getAsConstantArrayType(E->getType()); // For a copy constructor, even if it is trivial, must fall thru so // its argument is code-gen'ed. - if (!CD->isCopyConstructor(getContext())) { + if (!CD->isCopyConstructor()) { QualType InitType = E->getType(); if (Array) InitType = getContext().getBaseElementType(Array); const CXXRecordDecl *RD = cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl()); if (RD->hasTrivialConstructor()) - return; + return; } // Code gen optimization to eliminate copy constructor and return // its first argument instead. if (getContext().getLangOptions().ElideConstructors && E->isElidable()) { const Expr *Arg = E->getArg(0); - + + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { + assert((ICE->getCastKind() == CastExpr::CK_NoOp || + ICE->getCastKind() == CastExpr::CK_ConstructorConversion || + ICE->getCastKind() == CastExpr::CK_UserDefinedConversion) && + "Unknown implicit cast kind in constructor elision"); + Arg = ICE->getSubExpr(); + } + + if (const CXXFunctionalCastExpr *FCE = dyn_cast<CXXFunctionalCastExpr>(Arg)) + Arg = FCE->getSubExpr(); + if (const CXXBindTemporaryExpr *BindExpr = - dyn_cast<CXXBindTemporaryExpr>(Arg)) + dyn_cast<CXXBindTemporaryExpr>(Arg)) Arg = BindExpr->getSubExpr(); EmitAggExpr(Arg, Dest, false); @@ -591,6 +606,7 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = Builder.CreateBitCast(Dest, BasePtr); + EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr, E->arg_begin(), E->arg_end()); } @@ -793,7 +809,7 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, } RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), - Callee, CallArgs, MD); + Callee, ReturnValueSlot(), CallArgs, MD); if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) { bool CanBeZero = !(ResultType->isReferenceType() // FIXME: attr nonnull can't be zero either @@ -1043,765 +1059,70 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, return ::BuildVirtualCall(*this, VtableIndex, This, Ty); } -/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class -/// array of objects from SrcValue to DestValue. Copying can be either a bitwise -/// copy or via a copy constructor call. -// FIXME. Consolidate this with EmitCXXAggrConstructorCall. -void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, - llvm::Value *Src, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty) { - const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); - assert(CA && "VLA cannot be copied over"); - bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor(); - - // Create a temporary for the loop index and initialize it with 0. - llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), - "loop.index"); - llvm::Value* zeroConstant = - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); - Builder.CreateStore(zeroConstant, IndexPtr); - // Start the loop with a block that tests the condition. - llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); - llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); - - EmitBlock(CondBlock); - - llvm::BasicBlock *ForBody = createBasicBlock("for.body"); - // Generate: if (loop-index < number-of-elements fall to the loop body, - // otherwise, go to the block after the for-loop. - uint64_t NumElements = getContext().getConstantArrayElementCount(CA); - llvm::Value * NumElementsPtr = - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); - llvm::Value *Counter = Builder.CreateLoad(IndexPtr); - llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, - "isless"); - // If the condition is true, execute the body. - Builder.CreateCondBr(IsLess, ForBody, AfterFor); - - EmitBlock(ForBody); - llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); - // Inside the loop body, emit the constructor call on the array element. - Counter = Builder.CreateLoad(IndexPtr); - Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); - Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); - if (BitwiseCopy) - EmitAggregateCopy(Dest, Src, Ty); - else if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(getContext(), 0)) { - llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, - Ctor_Complete); - CallArgList CallArgs; - // Push the this (Dest) ptr. - CallArgs.push_back(std::make_pair(RValue::get(Dest), - BaseCopyCtor->getThisType(getContext()))); - - // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - BaseCopyCtor->getParamDecl(0)->getType())); - QualType ResultType = - BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), - Callee, CallArgs, BaseCopyCtor); - } - EmitBlock(ContinueBlock); - - // Emit the increment of the loop counter. - llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); - Counter = Builder.CreateLoad(IndexPtr); - NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); - Builder.CreateStore(NextVal, IndexPtr); - - // Finally, branch back up to the condition for the next iteration. - EmitBranch(CondBlock); - - // Emit the fall-through block. - EmitBlock(AfterFor, true); -} - -/// EmitClassAggrCopyAssignment - This routine generates code to assign a class -/// array of objects from SrcValue to DestValue. Assignment can be either a -/// bitwise assignment or via a copy assignment operator function call. -/// FIXME. This can be consolidated with EmitClassAggrMemberwiseCopy -void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, - llvm::Value *Src, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty) { - const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); - assert(CA && "VLA cannot be asssigned"); - bool BitwiseAssign = BaseClassDecl->hasTrivialCopyAssignment(); - - // Create a temporary for the loop index and initialize it with 0. - llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), - "loop.index"); - llvm::Value* zeroConstant = - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); - Builder.CreateStore(zeroConstant, IndexPtr); - // Start the loop with a block that tests the condition. - llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); - llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); - - EmitBlock(CondBlock); - - llvm::BasicBlock *ForBody = createBasicBlock("for.body"); - // Generate: if (loop-index < number-of-elements fall to the loop body, - // otherwise, go to the block after the for-loop. - uint64_t NumElements = getContext().getConstantArrayElementCount(CA); - llvm::Value * NumElementsPtr = - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); - llvm::Value *Counter = Builder.CreateLoad(IndexPtr); - llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, - "isless"); - // If the condition is true, execute the body. - Builder.CreateCondBr(IsLess, ForBody, AfterFor); - - EmitBlock(ForBody); - llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); - // Inside the loop body, emit the assignment operator call on array element. - Counter = Builder.CreateLoad(IndexPtr); - Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); - Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); - const CXXMethodDecl *MD = 0; - if (BitwiseAssign) - EmitAggregateCopy(Dest, Src, Ty); - else { - bool hasCopyAssign = BaseClassDecl->hasConstCopyAssignment(getContext(), - MD); - assert(hasCopyAssign && "EmitClassAggrCopyAssignment - No user assign"); - (void)hasCopyAssign; - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *LTy = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); - - CallArgList CallArgs; - // Push the this (Dest) ptr. - CallArgs.push_back(std::make_pair(RValue::get(Dest), - MD->getThisType(getContext()))); - - // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - MD->getParamDecl(0)->getType())); - QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), - Callee, CallArgs, MD); - } - EmitBlock(ContinueBlock); - - // Emit the increment of the loop counter. - llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); - Counter = Builder.CreateLoad(IndexPtr); - NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); - Builder.CreateStore(NextVal, IndexPtr); - - // Finally, branch back up to the condition for the next iteration. - EmitBranch(CondBlock); - - // Emit the fall-through block. - EmitBlock(AfterFor, true); -} - -/// EmitClassMemberwiseCopy - This routine generates code to copy a class -/// object from SrcValue to DestValue. Copying can be either a bitwise copy -/// or via a copy constructor call. -void CodeGenFunction::EmitClassMemberwiseCopy( - llvm::Value *Dest, llvm::Value *Src, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, QualType Ty) { - if (ClassDecl) { - Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - } - if (BaseClassDecl->hasTrivialCopyConstructor()) { - EmitAggregateCopy(Dest, Src, Ty); - return; - } - - if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(getContext(), 0)) { - llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, - Ctor_Complete); - CallArgList CallArgs; - // Push the this (Dest) ptr. - CallArgs.push_back(std::make_pair(RValue::get(Dest), - BaseCopyCtor->getThisType(getContext()))); - - // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - BaseCopyCtor->getParamDecl(0)->getType())); - QualType ResultType = - BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), - Callee, CallArgs, BaseCopyCtor); - } -} - -/// EmitClassCopyAssignment - This routine generates code to copy assign a class -/// object from SrcValue to DestValue. Assignment can be either a bitwise -/// assignment of via an assignment operator call. -// FIXME. Consolidate this with EmitClassMemberwiseCopy as they share a lot. -void CodeGenFunction::EmitClassCopyAssignment( - llvm::Value *Dest, llvm::Value *Src, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, - QualType Ty) { - if (ClassDecl) { - Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - } - if (BaseClassDecl->hasTrivialCopyAssignment()) { - EmitAggregateCopy(Dest, Src, Ty); +void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) { + if (!ClassDecl->isDynamicClass()) return; - } - - const CXXMethodDecl *MD = 0; - bool ConstCopyAssignOp = BaseClassDecl->hasConstCopyAssignment(getContext(), - MD); - assert(ConstCopyAssignOp && "EmitClassCopyAssignment - missing copy assign"); - (void)ConstCopyAssignOp; - - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *LTy = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); - - CallArgList CallArgs; - // Push the this (Dest) ptr. - CallArgs.push_back(std::make_pair(RValue::get(Dest), - MD->getThisType(getContext()))); - - // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - MD->getParamDecl(0)->getType())); - QualType ResultType = - MD->getType()->getAs<FunctionType>()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), - Callee, CallArgs, MD); -} - -/// SynthesizeDefaultConstructor - synthesize a default constructor -void -CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor, - CXXCtorType Type, - llvm::Function *Fn, - const FunctionArgList &Args) { - assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor"); - StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, - SourceLocation()); - EmitCtorPrologue(Ctor, Type); - FinishFunction(); -} - -/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a -/// copy constructor, in accordance with section 12.8 (p7 and p8) of C++03 -/// The implicitly-defined copy constructor for class X performs a memberwise -/// copy of its subobjects. The order of copying is the same as the order of -/// initialization of bases and members in a user-defined constructor -/// Each subobject is copied in the manner appropriate to its type: -/// if the subobject is of class type, the copy constructor for the class is -/// used; -/// if the subobject is an array, each element is copied, in the manner -/// appropriate to the element type; -/// if the subobject is of scalar type, the built-in assignment operator is -/// used. -/// Virtual base class subobjects shall be copied only once by the -/// implicitly-defined copy constructor - -void -CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, - CXXCtorType Type, - llvm::Function *Fn, - const FunctionArgList &Args) { - const CXXRecordDecl *ClassDecl = Ctor->getParent(); - assert(!ClassDecl->hasUserDeclaredCopyConstructor() && - "SynthesizeCXXCopyConstructor - copy constructor has definition already"); - assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor"); - StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, - SourceLocation()); - - FunctionArgList::const_iterator i = Args.begin(); - const VarDecl *ThisArg = i->first; - llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); - llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); - const VarDecl *SrcArg = (i+1)->first; - llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); - llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); - - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - // FIXME. copy constrution of virtual base NYI - if (Base->isVirtual()) - continue; - - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - EmitClassMemberwiseCopy(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, - Base->getType()); - } - for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), - E = ClassDecl->field_end(); I != E; ++I) { - const FieldDecl *Field = *I; - - QualType FieldType = getContext().getCanonicalType(Field->getType()); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); - - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0); - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *DestBaseAddrPtr = - Builder.CreateBitCast(LHS.getAddress(), BasePtr); - llvm::Value *SrcBaseAddrPtr = - Builder.CreateBitCast(RHS.getAddress(), BasePtr); - EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array, - FieldClassDecl, FieldType); - } - else - EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(), - 0 /*ClassDecl*/, FieldClassDecl, FieldType); - continue; - } - - if (Field->getType()->isReferenceType()) { - unsigned FieldIndex = CGM.getTypes().getLLVMFieldNo(Field); - - llvm::Value *LHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex, - "lhs.ref"); - - llvm::Value *RHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex, - "rhs.ref"); - - // Load the value in RHS. - RHS = Builder.CreateLoad(RHS); - - // And store it in the LHS - Builder.CreateStore(RHS, LHS); - - continue; - } - // Do a built-in assignment of scalar data members. - LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0); - - if (!hasAggregateLLVMType(Field->getType())) { - RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); - EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); - } else if (Field->getType()->isAnyComplexType()) { - ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(), - RHS.isVolatileQualified()); - StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified()); - } else { - EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); - } - } - - InitializeVtablePtrs(ClassDecl); - FinishFunction(); -} - -/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator. -/// Before the implicitly-declared copy assignment operator for a class is -/// implicitly defined, all implicitly- declared copy assignment operators for -/// its direct base classes and its nonstatic data members shall have been -/// implicitly defined. [12.8-p12] -/// The implicitly-defined copy assignment operator for class X performs -/// memberwise assignment of its subob- jects. The direct base classes of X are -/// assigned first, in the order of their declaration in -/// the base-specifier-list, and then the immediate nonstatic data members of X -/// are assigned, in the order in which they were declared in the class -/// definition.Each subobject is assigned in the manner appropriate to its type: -/// if the subobject is of class type, the copy assignment operator for the -/// class is used (as if by explicit qualification; that is, ignoring any -/// possible virtual overriding functions in more derived classes); -/// -/// if the subobject is an array, each element is assigned, in the manner -/// appropriate to the element type; -/// -/// if the subobject is of scalar type, the built-in assignment operator is -/// used. -void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, - llvm::Function *Fn, - const FunctionArgList &Args) { - - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext()); - assert(!ClassDecl->hasUserDeclaredCopyAssignment() && - "SynthesizeCXXCopyAssignment - copy assignment has user declaration"); - StartFunction(CD, CD->getResultType(), Fn, Args, SourceLocation()); - - FunctionArgList::const_iterator i = Args.begin(); - const VarDecl *ThisArg = i->first; - llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); - llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); - const VarDecl *SrcArg = (i+1)->first; - llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); - llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); - - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - // FIXME. copy assignment of virtual base NYI - if (Base->isVirtual()) - continue; + llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl); + CodeGenModule::AddrSubMap_t& AddressPoints = + *(*CGM.AddressPoints[ClassDecl])[ClassDecl]; + llvm::Value *ThisPtr = LoadCXXThis(); + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl); + // Store address points for virtual bases + for (CXXRecordDecl::base_class_const_iterator I = + ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); I != E; ++I) { + const CXXBaseSpecifier &Base = *I; CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, - Base->getType()); - } - - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = getContext().getCanonicalType((*Field)->getType()); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); - - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *DestBaseAddrPtr = - Builder.CreateBitCast(LHS.getAddress(), BasePtr); - llvm::Value *SrcBaseAddrPtr = - Builder.CreateBitCast(RHS.getAddress(), BasePtr); - EmitClassAggrCopyAssignment(DestBaseAddrPtr, SrcBaseAddrPtr, Array, - FieldClassDecl, FieldType); - } - else - EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(), - 0 /*ClassDecl*/, FieldClassDecl, FieldType); - continue; - } - // Do a built-in assignment of scalar data members. - LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); - if (!hasAggregateLLVMType(Field->getType())) { - RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); - EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); - } else if (Field->getType()->isAnyComplexType()) { - ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(), - RHS.isVolatileQualified()); - StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified()); - } else { - EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); - } - } - - // return *this; - Builder.CreateStore(LoadOfThis, ReturnValue); - - FinishFunction(); -} - -static void EmitBaseInitializer(CodeGenFunction &CGF, - const CXXRecordDecl *ClassDecl, - CXXBaseOrMemberInitializer *BaseInit, - CXXCtorType CtorType) { - assert(BaseInit->isBaseInitializer() && - "Must have base initializer!"); - - llvm::Value *ThisPtr = CGF.LoadCXXThis(); - - const Type *BaseType = BaseInit->getBaseClass(); - CXXRecordDecl *BaseClassDecl = - cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); - llvm::Value *V = CGF.GetAddressOfBaseClass(ThisPtr, ClassDecl, - BaseClassDecl, - /*NullCheckValue=*/false); - CGF.EmitCXXConstructorCall(BaseInit->getConstructor(), - CtorType, V, - BaseInit->const_arg_begin(), - BaseInit->const_arg_end()); -} - -static void EmitMemberInitializer(CodeGenFunction &CGF, - const CXXRecordDecl *ClassDecl, - CXXBaseOrMemberInitializer *MemberInit) { - assert(MemberInit->isMemberInitializer() && - "Must have member initializer!"); - - // non-static data member initializers. - FieldDecl *Field = MemberInit->getMember(); - QualType FieldType = CGF.getContext().getCanonicalType(Field->getType()); - - llvm::Value *ThisPtr = CGF.LoadCXXThis(); - LValue LHS; - if (FieldType->isReferenceType()) { - // FIXME: This is really ugly; should be refactored somehow - unsigned idx = CGF.CGM.getTypes().getLLVMFieldNo(Field); - llvm::Value *V = CGF.Builder.CreateStructGEP(ThisPtr, idx, "tmp"); - assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); - LHS = LValue::MakeAddr(V, CGF.MakeQualifiers(FieldType)); - } else { - LHS = CGF.EmitLValueForField(ThisPtr, Field, ClassDecl->isUnion(), 0); - } - - // If we are initializing an anonymous union field, drill down to the field. - if (MemberInit->getAnonUnionMember()) { - Field = MemberInit->getAnonUnionMember(); - LHS = CGF.EmitLValueForField(LHS.getAddress(), Field, - /*IsUnion=*/true, 0); - FieldType = Field->getType(); - } - - // If the field is an array, branch based on the element type. - const ConstantArrayType *Array = - CGF.getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = CGF.getContext().getBaseElementType(FieldType); - - // We lose the constructor for anonymous union members, so handle them - // explicitly. - // FIXME: This is somwhat ugly. - if (MemberInit->getAnonUnionMember() && FieldType->getAs<RecordType>()) { - if (MemberInit->getNumArgs()) - CGF.EmitAggExpr(*MemberInit->arg_begin(), LHS.getAddress(), - LHS.isVolatileQualified()); - else - CGF.EmitAggregateClear(LHS.getAddress(), Field->getType()); - return; - } - - if (FieldType->getAs<RecordType>()) { - assert(MemberInit->getConstructor() && - "EmitCtorPrologue - no constructor to initialize member"); - if (Array) { - const llvm::Type *BasePtr = CGF.ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr); - CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(), - Array, BaseAddrPtr, - MemberInit->const_arg_begin(), - MemberInit->const_arg_end()); - } - else - CGF.EmitCXXConstructorCall(MemberInit->getConstructor(), - Ctor_Complete, LHS.getAddress(), - MemberInit->const_arg_begin(), - MemberInit->const_arg_end()); - return; - } - - assert(MemberInit->getNumArgs() == 1 && "Initializer count must be 1 only"); - Expr *RhsExpr = *MemberInit->arg_begin(); - RValue RHS; - if (FieldType->isReferenceType()) { - RHS = CGF.EmitReferenceBindingToExpr(RhsExpr, FieldType, - /*IsInitializer=*/true); - CGF.EmitStoreThroughLValue(RHS, LHS, FieldType); - } else if (Array) { - CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType()); - } else if (!CGF.hasAggregateLLVMType(RhsExpr->getType())) { - RHS = RValue::get(CGF.EmitScalarExpr(RhsExpr, true)); - CGF.EmitStoreThroughLValue(RHS, LHS, FieldType); - } else if (RhsExpr->getType()->isAnyComplexType()) { - CGF.EmitComplexExprIntoAddr(RhsExpr, LHS.getAddress(), - LHS.isVolatileQualified()); - } else { - // Handle member function pointers; other aggregates shouldn't get this far. - CGF.EmitAggExpr(RhsExpr, LHS.getAddress(), LHS.isVolatileQualified()); - } -} - -/// EmitCtorPrologue - This routine generates necessary code to initialize -/// base classes and non-static data members belonging to this constructor. -/// FIXME: This needs to take a CXXCtorType. -void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, - CXXCtorType CtorType) { - const CXXRecordDecl *ClassDecl = CD->getParent(); - - // FIXME: Add vbase initialization - - for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(), - E = CD->init_end(); - B != E; ++B) { - CXXBaseOrMemberInitializer *Member = (*B); - - assert(LiveTemporaries.empty() && - "Should not have any live temporaries at initializer start!"); - - if (Member->isBaseInitializer()) - EmitBaseInitializer(*this, ClassDecl, Member, CtorType); - else - EmitMemberInitializer(*this, ClassDecl, Member); - - // Pop any live temporaries that the initializers might have pushed. - while (!LiveTemporaries.empty()) - PopCXXTemporary(); + = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); + uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl); + InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints, + ThisPtr, Offset); } - InitializeVtablePtrs(ClassDecl); + // Store address points for non-virtual bases and current class + InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0); } -void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) { +void CodeGenFunction::InitializeVtablePtrsRecursive( + const CXXRecordDecl *ClassDecl, + llvm::Constant *Vtable, + CodeGenModule::AddrSubMap_t& AddressPoints, + llvm::Value *ThisPtr, + uint64_t Offset) { if (!ClassDecl->isDynamicClass()) return; - - // Initialize the vtable pointer. - // FIXME: This needs to initialize secondary vtable pointers too. - llvm::Value *ThisPtr = LoadCXXThis(); - llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl); - uint64_t AddressPoint = CGM.getVtableInfo().getVtableAddressPoint(ClassDecl); - - llvm::Value *VtableAddressPoint = - Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint); - - llvm::Value *VtableField = - Builder.CreateBitCast(ThisPtr, - VtableAddressPoint->getType()->getPointerTo()); - - Builder.CreateStore(VtableAddressPoint, VtableField); -} - -/// EmitDtorEpilogue - Emit all code that comes at the end of class's -/// destructor. This is to call destructors on members and base classes -/// in reverse order of their construction. -/// FIXME: This needs to take a CXXDtorType. -void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, - CXXDtorType DtorType) { - assert(!DD->isTrivial() && - "Should not emit dtor epilogue for trivial dtor!"); - - const CXXRecordDecl *ClassDecl = DD->getParent(); - - // Collect the fields. - llvm::SmallVector<const FieldDecl *, 16> FieldDecls; - for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), - E = ClassDecl->field_end(); I != E; ++I) { - const FieldDecl *Field = *I; - - QualType FieldType = getContext().getCanonicalType(Field->getType()); - FieldType = getContext().getBaseElementType(FieldType); - - const RecordType *RT = FieldType->getAs<RecordType>(); - if (!RT) - continue; - - CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (FieldClassDecl->hasTrivialDestructor()) - continue; - - FieldDecls.push_back(Field); - } - - // Now destroy the fields. - for (size_t i = FieldDecls.size(); i > 0; --i) { - const FieldDecl *Field = FieldDecls[i - 1]; - - QualType FieldType = Field->getType(); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); - - const RecordType *RT = FieldType->getAs<RecordType>(); - CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - - llvm::Value *ThisPtr = LoadCXXThis(); - - LValue LHS = EmitLValueForField(ThisPtr, Field, - /*isUnion=*/false, - // FIXME: Qualifiers? - /*CVRQualifiers=*/0); - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(LHS.getAddress(), BasePtr); - EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()), - Array, BaseAddrPtr); - } else - EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()), - Dtor_Complete, LHS.getAddress()); - } - - // Destroy non-virtual bases. - for (CXXRecordDecl::reverse_base_class_const_iterator I = - ClassDecl->bases_rbegin(), E = ClassDecl->bases_rend(); I != E; ++I) { + // Store address points for non-virtual bases + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl); + for (CXXRecordDecl::base_class_const_iterator I = + ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) { const CXXBaseSpecifier &Base = *I; - - // Ignore virtual bases. if (Base.isVirtual()) continue; - CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - - // Ignore trivial destructors. - if (BaseClassDecl->hasTrivialDestructor()) - continue; - const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); - - llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(), - ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - EmitCXXDestructorCall(D, Dtor_Base, V); + uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl); + InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints, + ThisPtr, NewOffset); } - // If we're emitting a base destructor, we don't want to emit calls to the - // virtual bases. - if (DtorType == Dtor_Base) - return; - - // Handle virtual bases. - for (CXXRecordDecl::reverse_base_class_const_iterator I = - ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) { - const CXXBaseSpecifier &Base = *I; - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - - // Ignore trivial destructors. - if (BaseClassDecl->hasTrivialDestructor()) - continue; - const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); - llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(), - ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - EmitCXXDestructorCall(D, Dtor_Base, V); - } - - // If we have a deleting destructor, emit a call to the delete operator. - if (DtorType == Dtor_Deleting) { - assert(DD->getOperatorDelete() && - "operator delete missing - EmitDtorEpilogue"); - EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(), - getContext().getTagDeclType(ClassDecl)); - } -} - -void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, - CXXDtorType DtorType, - llvm::Function *Fn, - const FunctionArgList &Args) { - assert(!Dtor->getParent()->hasUserDeclaredDestructor() && - "SynthesizeDefaultDestructor - destructor has user declaration"); + // Compute the address point + assert(AddressPoints.count(std::make_pair(ClassDecl, Offset)) && + "Missing address point for class"); + uint64_t AddressPoint = AddressPoints[std::make_pair(ClassDecl, Offset)]; + llvm::Value *VtableAddressPoint = + Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint); - StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args, - SourceLocation()); + // Compute the address to store the address point + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + llvm::Value *VtableField = Builder.CreateBitCast(ThisPtr, Int8PtrTy); + VtableField = Builder.CreateConstInBoundsGEP1_64(VtableField, Offset/8); + const llvm::Type *AddressPointPtrTy = + VtableAddressPoint->getType()->getPointerTo(); + VtableField = Builder.CreateBitCast(VtableField, AddressPointPtrTy); - EmitDtorEpilogue(Dtor, DtorType); - FinishFunction(); + // Store address point + Builder.CreateStore(VtableAddressPoint, VtableField); } + diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 4856f54..2dda0b8 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -346,6 +346,7 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, /// destination type; the upper bits of the src will be lost. static void CreateCoercedStore(llvm::Value *Src, llvm::Value *DstPtr, + bool DstIsVolatile, CodeGenFunction &CGF) { const llvm::Type *SrcTy = Src->getType(); const llvm::Type *DstTy = @@ -359,7 +360,7 @@ static void CreateCoercedStore(llvm::Value *Src, llvm::Value *Casted = CGF.Builder.CreateBitCast(DstPtr, llvm::PointerType::getUnqual(SrcTy)); // FIXME: Use better alignment / avoid requiring aligned store. - CGF.Builder.CreateStore(Src, Casted)->setAlignment(1); + CGF.Builder.CreateStore(Src, Casted, DstIsVolatile)->setAlignment(1); } else { // Otherwise do coercion through memory. This is stupid, but // simple. @@ -377,7 +378,7 @@ static void CreateCoercedStore(llvm::Value *Src, llvm::LoadInst *Load = CGF.Builder.CreateLoad(Casted); // FIXME: Use better alignment / avoid requiring aligned load. Load->setAlignment(1); - CGF.Builder.CreateStore(Load, DstPtr); + CGF.Builder.CreateStore(Load, DstPtr, DstIsVolatile); } } @@ -732,7 +733,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // result in a new alloca anyway, so we could just store into that // directly if we broke the abstraction down more. llvm::Value *V = CreateTempAlloca(ConvertTypeForMem(Ty), "coerce"); - CreateCoercedStore(AI, V, *this); + CreateCoercedStore(AI, V, /*DestIsVolatile=*/false, *this); // Match to what EmitParmDecl is expecting for this type. if (!CodeGenFunction::hasAggregateLLVMType(Ty)) { V = EmitLoadOfScalar(V, false, Ty); @@ -809,6 +810,7 @@ RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) { RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::Value *Callee, + ReturnValueSlot ReturnValue, const CallArgList &CallArgs, const Decl *TargetDecl) { // FIXME: We no longer need the types from CallArgs; lift up and simplify. @@ -821,9 +823,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // If the call returns a temporary with struct return, create a temporary - // alloca to hold the result. - if (CGM.ReturnTypeUsesSret(CallInfo)) - Args.push_back(CreateTempAlloca(ConvertTypeForMem(RetTy))); + // alloca to hold the result, unless one is given to us. + if (CGM.ReturnTypeUsesSret(CallInfo)) { + llvm::Value *Value = ReturnValue.getValue(); + if (!Value) + Value = CreateTempAlloca(ConvertTypeForMem(RetTy)); + Args.push_back(Value); + } assert(CallInfo.arg_size() == CallArgs.size() && "Mismatch between function signature & arguments."); @@ -972,9 +978,15 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, return RValue::getComplex(std::make_pair(Real, Imag)); } if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - llvm::Value *V = CreateTempAlloca(ConvertTypeForMem(RetTy), "agg.tmp"); - Builder.CreateStore(CI, V); - return RValue::getAggregate(V); + llvm::Value *DestPtr = ReturnValue.getValue(); + bool DestIsVolatile = ReturnValue.isVolatile(); + + if (!DestPtr) { + DestPtr = CreateTempAlloca(ConvertTypeForMem(RetTy), "agg.tmp"); + DestIsVolatile = false; + } + Builder.CreateStore(CI, DestPtr, DestIsVolatile); + return RValue::getAggregate(DestPtr); } return RValue::get(CI); @@ -984,14 +996,20 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, return GetUndefRValue(RetTy); case ABIArgInfo::Coerce: { - // FIXME: Avoid the conversion through memory if possible. - llvm::Value *V = CreateTempAlloca(ConvertTypeForMem(RetTy), "coerce"); - CreateCoercedStore(CI, V, *this); + llvm::Value *DestPtr = ReturnValue.getValue(); + bool DestIsVolatile = ReturnValue.isVolatile(); + + if (!DestPtr) { + DestPtr = CreateTempAlloca(ConvertTypeForMem(RetTy), "coerce"); + DestIsVolatile = false; + } + + CreateCoercedStore(CI, DestPtr, DestIsVolatile, *this); if (RetTy->isAnyComplexType()) - return RValue::getComplex(LoadComplexFromAddr(V, false)); + return RValue::getComplex(LoadComplexFromAddr(DestPtr, false)); if (CodeGenFunction::hasAggregateLLVMType(RetTy)) - return RValue::getAggregate(V); - return RValue::get(EmitLoadOfScalar(V, false, RetTy)); + return RValue::getAggregate(DestPtr); + return RValue::get(EmitLoadOfScalar(DestPtr, false, RetTy)); } case ABIArgInfo::Expand: diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h index ebf801d..427ab5f 100644 --- a/lib/CodeGen/CGCall.h +++ b/lib/CodeGen/CGCall.h @@ -15,7 +15,8 @@ #ifndef CLANG_CODEGEN_CGCALL_H #define CLANG_CODEGEN_CGCALL_H -#include <llvm/ADT/FoldingSet.h> +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Value.h" #include "clang/AST/Type.h" #include "CGValue.h" @@ -123,6 +124,23 @@ namespace CodeGen { begin->Profile(ID); } }; + + /// ReturnValueSlot - Contains the address where the return value of a + /// function can be stored, and whether the address is volatile or not. + class ReturnValueSlot { + llvm::PointerIntPair<llvm::Value *, 1, bool> Value; + + public: + ReturnValueSlot() {} + ReturnValueSlot(llvm::Value *Value, bool IsVolatile) + : Value(Value, IsVolatile) {} + + bool isNull() const { return !getValue(); } + + bool isVolatile() const { return Value.getInt(); } + llvm::Value *getValue() const { return Value.getPointer(); } + }; + } // end namespace CodeGen } // end namespace clang diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index fd2afe7..953b8c8 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -269,3 +269,778 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, return Value; } + +/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class +/// array of objects from SrcValue to DestValue. Copying can be either a bitwise +/// copy or via a copy constructor call. +// FIXME. Consolidate this with EmitCXXAggrConstructorCall. +void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, + llvm::Value *Src, + const ArrayType *Array, + const CXXRecordDecl *BaseClassDecl, + QualType Ty) { + const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); + assert(CA && "VLA cannot be copied over"); + bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor(); + + // Create a temporary for the loop index and initialize it with 0. + llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), + "loop.index"); + llvm::Value* zeroConstant = + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); + Builder.CreateStore(zeroConstant, IndexPtr); + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + // Generate: if (loop-index < number-of-elements fall to the loop body, + // otherwise, go to the block after the for-loop. + uint64_t NumElements = getContext().getConstantArrayElementCount(CA); + llvm::Value * NumElementsPtr = + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, + "isless"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsLess, ForBody, AfterFor); + + EmitBlock(ForBody); + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the constructor call on the array element. + Counter = Builder.CreateLoad(IndexPtr); + Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); + Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); + if (BitwiseCopy) + EmitAggregateCopy(Dest, Src, Ty); + else if (CXXConstructorDecl *BaseCopyCtor = + BaseClassDecl->getCopyConstructor(getContext(), 0)) { + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, + Ctor_Complete); + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + BaseCopyCtor->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + BaseCopyCtor->getParamDecl(0)->getType())); + QualType ResultType = + BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor); + } + EmitBlock(ContinueBlock); + + // Emit the increment of the loop counter. + llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); + Counter = Builder.CreateLoad(IndexPtr); + NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); + Builder.CreateStore(NextVal, IndexPtr); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + +/// EmitClassAggrCopyAssignment - This routine generates code to assign a class +/// array of objects from SrcValue to DestValue. Assignment can be either a +/// bitwise assignment or via a copy assignment operator function call. +/// FIXME. This can be consolidated with EmitClassAggrMemberwiseCopy +void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, + llvm::Value *Src, + const ArrayType *Array, + const CXXRecordDecl *BaseClassDecl, + QualType Ty) { + const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); + assert(CA && "VLA cannot be asssigned"); + bool BitwiseAssign = BaseClassDecl->hasTrivialCopyAssignment(); + + // Create a temporary for the loop index and initialize it with 0. + llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), + "loop.index"); + llvm::Value* zeroConstant = + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); + Builder.CreateStore(zeroConstant, IndexPtr); + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + // Generate: if (loop-index < number-of-elements fall to the loop body, + // otherwise, go to the block after the for-loop. + uint64_t NumElements = getContext().getConstantArrayElementCount(CA); + llvm::Value * NumElementsPtr = + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, + "isless"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsLess, ForBody, AfterFor); + + EmitBlock(ForBody); + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the assignment operator call on array element. + Counter = Builder.CreateLoad(IndexPtr); + Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); + Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); + const CXXMethodDecl *MD = 0; + if (BitwiseAssign) + EmitAggregateCopy(Dest, Src, Ty); + else { + bool hasCopyAssign = BaseClassDecl->hasConstCopyAssignment(getContext(), + MD); + assert(hasCopyAssign && "EmitClassAggrCopyAssignment - No user assign"); + (void)hasCopyAssign; + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *LTy = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); + + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + MD->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + MD->getParamDecl(0)->getType())); + QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, ReturnValueSlot(), CallArgs, MD); + } + EmitBlock(ContinueBlock); + + // Emit the increment of the loop counter. + llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); + Counter = Builder.CreateLoad(IndexPtr); + NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); + Builder.CreateStore(NextVal, IndexPtr); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + +/// EmitClassMemberwiseCopy - This routine generates code to copy a class +/// object from SrcValue to DestValue. Copying can be either a bitwise copy +/// or via a copy constructor call. +void CodeGenFunction::EmitClassMemberwiseCopy( + llvm::Value *Dest, llvm::Value *Src, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, QualType Ty) { + if (ClassDecl) { + Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + } + if (BaseClassDecl->hasTrivialCopyConstructor()) { + EmitAggregateCopy(Dest, Src, Ty); + return; + } + + if (CXXConstructorDecl *BaseCopyCtor = + BaseClassDecl->getCopyConstructor(getContext(), 0)) { + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, + Ctor_Complete); + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + BaseCopyCtor->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + BaseCopyCtor->getParamDecl(0)->getType())); + QualType ResultType = + BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor); + } +} + +/// EmitClassCopyAssignment - This routine generates code to copy assign a class +/// object from SrcValue to DestValue. Assignment can be either a bitwise +/// assignment of via an assignment operator call. +// FIXME. Consolidate this with EmitClassMemberwiseCopy as they share a lot. +void CodeGenFunction::EmitClassCopyAssignment( + llvm::Value *Dest, llvm::Value *Src, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, + QualType Ty) { + if (ClassDecl) { + Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + } + if (BaseClassDecl->hasTrivialCopyAssignment()) { + EmitAggregateCopy(Dest, Src, Ty); + return; + } + + const CXXMethodDecl *MD = 0; + bool ConstCopyAssignOp = BaseClassDecl->hasConstCopyAssignment(getContext(), + MD); + assert(ConstCopyAssignOp && "EmitClassCopyAssignment - missing copy assign"); + (void)ConstCopyAssignOp; + + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *LTy = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); + + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + MD->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + MD->getParamDecl(0)->getType())); + QualType ResultType = + MD->getType()->getAs<FunctionType>()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, ReturnValueSlot(), CallArgs, MD); +} + +/// SynthesizeDefaultConstructor - synthesize a default constructor +void +CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + llvm::Function *Fn, + const FunctionArgList &Args) { + assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor"); + StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, + SourceLocation()); + EmitCtorPrologue(Ctor, Type); + FinishFunction(); +} + +/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a +/// copy constructor, in accordance with section 12.8 (p7 and p8) of C++03 +/// The implicitly-defined copy constructor for class X performs a memberwise +/// copy of its subobjects. The order of copying is the same as the order of +/// initialization of bases and members in a user-defined constructor +/// Each subobject is copied in the manner appropriate to its type: +/// if the subobject is of class type, the copy constructor for the class is +/// used; +/// if the subobject is an array, each element is copied, in the manner +/// appropriate to the element type; +/// if the subobject is of scalar type, the built-in assignment operator is +/// used. +/// Virtual base class subobjects shall be copied only once by the +/// implicitly-defined copy constructor + +void +CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + llvm::Function *Fn, + const FunctionArgList &Args) { + const CXXRecordDecl *ClassDecl = Ctor->getParent(); + assert(!ClassDecl->hasUserDeclaredCopyConstructor() && + "SynthesizeCXXCopyConstructor - copy constructor has definition already"); + assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor"); + StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, + SourceLocation()); + + FunctionArgList::const_iterator i = Args.begin(); + const VarDecl *ThisArg = i->first; + llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); + llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); + const VarDecl *SrcArg = (i+1)->first; + llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); + llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); + + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + // FIXME. copy constrution of virtual base NYI + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + EmitClassMemberwiseCopy(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, + Base->getType()); + } + + for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), + E = ClassDecl->field_end(); I != E; ++I) { + const FieldDecl *Field = *I; + + QualType FieldType = getContext().getCanonicalType(Field->getType()); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { + CXXRecordDecl *FieldClassDecl + = cast<CXXRecordDecl>(FieldClassType->getDecl()); + LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *DestBaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + llvm::Value *SrcBaseAddrPtr = + Builder.CreateBitCast(RHS.getAddress(), BasePtr); + EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array, + FieldClassDecl, FieldType); + } + else + EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(), + 0 /*ClassDecl*/, FieldClassDecl, FieldType); + continue; + } + + if (Field->getType()->isReferenceType()) { + unsigned FieldIndex = CGM.getTypes().getLLVMFieldNo(Field); + + llvm::Value *LHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex, + "lhs.ref"); + + llvm::Value *RHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex, + "rhs.ref"); + + // Load the value in RHS. + RHS = Builder.CreateLoad(RHS); + + // And store it in the LHS + Builder.CreateStore(RHS, LHS); + + continue; + } + // Do a built-in assignment of scalar data members. + LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0); + + if (!hasAggregateLLVMType(Field->getType())) { + RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); + EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); + } else if (Field->getType()->isAnyComplexType()) { + ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(), + RHS.isVolatileQualified()); + StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified()); + } else { + EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); + } + } + + InitializeVtablePtrs(ClassDecl); + FinishFunction(); +} + +/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator. +/// Before the implicitly-declared copy assignment operator for a class is +/// implicitly defined, all implicitly- declared copy assignment operators for +/// its direct base classes and its nonstatic data members shall have been +/// implicitly defined. [12.8-p12] +/// The implicitly-defined copy assignment operator for class X performs +/// memberwise assignment of its subob- jects. The direct base classes of X are +/// assigned first, in the order of their declaration in +/// the base-specifier-list, and then the immediate nonstatic data members of X +/// are assigned, in the order in which they were declared in the class +/// definition.Each subobject is assigned in the manner appropriate to its type: +/// if the subobject is of class type, the copy assignment operator for the +/// class is used (as if by explicit qualification; that is, ignoring any +/// possible virtual overriding functions in more derived classes); +/// +/// if the subobject is an array, each element is assigned, in the manner +/// appropriate to the element type; +/// +/// if the subobject is of scalar type, the built-in assignment operator is +/// used. +void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, + llvm::Function *Fn, + const FunctionArgList &Args) { + + const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext()); + assert(!ClassDecl->hasUserDeclaredCopyAssignment() && + "SynthesizeCXXCopyAssignment - copy assignment has user declaration"); + StartFunction(CD, CD->getResultType(), Fn, Args, SourceLocation()); + + FunctionArgList::const_iterator i = Args.begin(); + const VarDecl *ThisArg = i->first; + llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); + llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); + const VarDecl *SrcArg = (i+1)->first; + llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); + llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); + + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + // FIXME. copy assignment of virtual base NYI + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, + Base->getType()); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = getContext().getCanonicalType((*Field)->getType()); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { + CXXRecordDecl *FieldClassDecl + = cast<CXXRecordDecl>(FieldClassType->getDecl()); + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *DestBaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + llvm::Value *SrcBaseAddrPtr = + Builder.CreateBitCast(RHS.getAddress(), BasePtr); + EmitClassAggrCopyAssignment(DestBaseAddrPtr, SrcBaseAddrPtr, Array, + FieldClassDecl, FieldType); + } + else + EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(), + 0 /*ClassDecl*/, FieldClassDecl, FieldType); + continue; + } + // Do a built-in assignment of scalar data members. + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + if (!hasAggregateLLVMType(Field->getType())) { + RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); + EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); + } else if (Field->getType()->isAnyComplexType()) { + ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(), + RHS.isVolatileQualified()); + StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified()); + } else { + EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); + } + } + + // return *this; + Builder.CreateStore(LoadOfThis, ReturnValue); + + FinishFunction(); +} + +static void EmitBaseInitializer(CodeGenFunction &CGF, + const CXXRecordDecl *ClassDecl, + CXXBaseOrMemberInitializer *BaseInit, + CXXCtorType CtorType) { + assert(BaseInit->isBaseInitializer() && + "Must have base initializer!"); + + llvm::Value *ThisPtr = CGF.LoadCXXThis(); + + const Type *BaseType = BaseInit->getBaseClass(); + CXXRecordDecl *BaseClassDecl = + cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); + + // FIXME: This method of determining whether a base is virtual is ridiculous; + // it should be part of BaseInit. + bool isBaseVirtual = false; + for (CXXRecordDecl::base_class_const_iterator I = ClassDecl->vbases_begin(), + E = ClassDecl->vbases_end(); I != E; ++I) + if (I->getType()->getAs<RecordType>()->getDecl() == BaseClassDecl) { + isBaseVirtual = true; + break; + } + + // The base constructor doesn't construct virtual bases. + if (CtorType == Ctor_Base && isBaseVirtual) + return; + + // Compute the offset to the base; we do this directly instead of using + // GetAddressOfBaseClass because the class doesn't have a vtable pointer + // at this point. + // FIXME: This could be refactored back into GetAddressOfBaseClass if it took + // an extra parameter for whether the derived class is the complete object + // class. + const ASTRecordLayout &Layout = + CGF.getContext().getASTRecordLayout(ClassDecl); + uint64_t Offset; + if (isBaseVirtual) + Offset = Layout.getVBaseClassOffset(BaseClassDecl); + else + Offset = Layout.getBaseClassOffset(BaseClassDecl); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + const llvm::Type *BaseClassType = CGF.ConvertType(QualType(BaseType, 0)); + llvm::Value *V = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy); + V = CGF.Builder.CreateConstInBoundsGEP1_64(V, Offset/8); + V = CGF.Builder.CreateBitCast(V, BaseClassType->getPointerTo()); + + // FIXME: This should always use Ctor_Base as the ctor type! (But that + // causes crashes in tests.) + CGF.EmitCXXConstructorCall(BaseInit->getConstructor(), + CtorType, V, + BaseInit->const_arg_begin(), + BaseInit->const_arg_end()); +} + +static void EmitMemberInitializer(CodeGenFunction &CGF, + const CXXRecordDecl *ClassDecl, + CXXBaseOrMemberInitializer *MemberInit) { + assert(MemberInit->isMemberInitializer() && + "Must have member initializer!"); + + // non-static data member initializers. + FieldDecl *Field = MemberInit->getMember(); + QualType FieldType = CGF.getContext().getCanonicalType(Field->getType()); + + llvm::Value *ThisPtr = CGF.LoadCXXThis(); + LValue LHS; + if (FieldType->isReferenceType()) { + // FIXME: This is really ugly; should be refactored somehow + unsigned idx = CGF.CGM.getTypes().getLLVMFieldNo(Field); + llvm::Value *V = CGF.Builder.CreateStructGEP(ThisPtr, idx, "tmp"); + assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); + LHS = LValue::MakeAddr(V, CGF.MakeQualifiers(FieldType)); + } else { + LHS = CGF.EmitLValueForField(ThisPtr, Field, ClassDecl->isUnion(), 0); + } + + // If we are initializing an anonymous union field, drill down to the field. + if (MemberInit->getAnonUnionMember()) { + Field = MemberInit->getAnonUnionMember(); + LHS = CGF.EmitLValueForField(LHS.getAddress(), Field, + /*IsUnion=*/true, 0); + FieldType = Field->getType(); + } + + // If the field is an array, branch based on the element type. + const ConstantArrayType *Array = + CGF.getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = CGF.getContext().getBaseElementType(FieldType); + + // We lose the constructor for anonymous union members, so handle them + // explicitly. + // FIXME: This is somwhat ugly. + if (MemberInit->getAnonUnionMember() && FieldType->getAs<RecordType>()) { + if (MemberInit->getNumArgs()) + CGF.EmitAggExpr(*MemberInit->arg_begin(), LHS.getAddress(), + LHS.isVolatileQualified()); + else + CGF.EmitAggregateClear(LHS.getAddress(), Field->getType()); + return; + } + + if (FieldType->getAs<RecordType>()) { + assert(MemberInit->getConstructor() && + "EmitCtorPrologue - no constructor to initialize member"); + if (Array) { + const llvm::Type *BasePtr = CGF.ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr); + CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(), + Array, BaseAddrPtr, + MemberInit->const_arg_begin(), + MemberInit->const_arg_end()); + } + else + CGF.EmitCXXConstructorCall(MemberInit->getConstructor(), + Ctor_Complete, LHS.getAddress(), + MemberInit->const_arg_begin(), + MemberInit->const_arg_end()); + return; + } + + assert(MemberInit->getNumArgs() == 1 && "Initializer count must be 1 only"); + Expr *RhsExpr = *MemberInit->arg_begin(); + RValue RHS; + if (FieldType->isReferenceType()) { + RHS = CGF.EmitReferenceBindingToExpr(RhsExpr, FieldType, + /*IsInitializer=*/true); + CGF.EmitStoreThroughLValue(RHS, LHS, FieldType); + } else if (Array) { + CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType()); + } else if (!CGF.hasAggregateLLVMType(RhsExpr->getType())) { + RHS = RValue::get(CGF.EmitScalarExpr(RhsExpr, true)); + CGF.EmitStoreThroughLValue(RHS, LHS, FieldType); + } else if (RhsExpr->getType()->isAnyComplexType()) { + CGF.EmitComplexExprIntoAddr(RhsExpr, LHS.getAddress(), + LHS.isVolatileQualified()); + } else { + // Handle member function pointers; other aggregates shouldn't get this far. + CGF.EmitAggExpr(RhsExpr, LHS.getAddress(), LHS.isVolatileQualified()); + } +} + +/// EmitCtorPrologue - This routine generates necessary code to initialize +/// base classes and non-static data members belonging to this constructor. +/// FIXME: This needs to take a CXXCtorType. +void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, + CXXCtorType CtorType) { + const CXXRecordDecl *ClassDecl = CD->getParent(); + + // FIXME: Add vbase initialization + + for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(), + E = CD->init_end(); + B != E; ++B) { + CXXBaseOrMemberInitializer *Member = (*B); + + assert(LiveTemporaries.empty() && + "Should not have any live temporaries at initializer start!"); + + if (Member->isBaseInitializer()) + EmitBaseInitializer(*this, ClassDecl, Member, CtorType); + else + EmitMemberInitializer(*this, ClassDecl, Member); + + // Pop any live temporaries that the initializers might have pushed. + while (!LiveTemporaries.empty()) + PopCXXTemporary(); + } + + InitializeVtablePtrs(ClassDecl); +} + +/// EmitDtorEpilogue - Emit all code that comes at the end of class's +/// destructor. This is to call destructors on members and base classes +/// in reverse order of their construction. +/// FIXME: This needs to take a CXXDtorType. +void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, + CXXDtorType DtorType) { + assert(!DD->isTrivial() && + "Should not emit dtor epilogue for trivial dtor!"); + + const CXXRecordDecl *ClassDecl = DD->getParent(); + + // Collect the fields. + llvm::SmallVector<const FieldDecl *, 16> FieldDecls; + for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), + E = ClassDecl->field_end(); I != E; ++I) { + const FieldDecl *Field = *I; + + QualType FieldType = getContext().getCanonicalType(Field->getType()); + FieldType = getContext().getBaseElementType(FieldType); + + const RecordType *RT = FieldType->getAs<RecordType>(); + if (!RT) + continue; + + CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (FieldClassDecl->hasTrivialDestructor()) + continue; + + FieldDecls.push_back(Field); + } + + // Now destroy the fields. + for (size_t i = FieldDecls.size(); i > 0; --i) { + const FieldDecl *Field = FieldDecls[i - 1]; + + QualType FieldType = Field->getType(); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + const RecordType *RT = FieldType->getAs<RecordType>(); + CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + + llvm::Value *ThisPtr = LoadCXXThis(); + + LValue LHS = EmitLValueForField(ThisPtr, Field, + /*isUnion=*/false, + // FIXME: Qualifiers? + /*CVRQualifiers=*/0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()), + Array, BaseAddrPtr); + } else + EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()), + Dtor_Complete, LHS.getAddress()); + } + + // Destroy non-virtual bases. + for (CXXRecordDecl::reverse_base_class_const_iterator I = + ClassDecl->bases_rbegin(), E = ClassDecl->bases_rend(); I != E; ++I) { + const CXXBaseSpecifier &Base = *I; + + // Ignore virtual bases. + if (Base.isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); + + // Ignore trivial destructors. + if (BaseClassDecl->hasTrivialDestructor()) + continue; + const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); + + llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(), + ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + EmitCXXDestructorCall(D, Dtor_Base, V); + } + + // If we're emitting a base destructor, we don't want to emit calls to the + // virtual bases. + if (DtorType == Dtor_Base) + return; + + // Handle virtual bases. + for (CXXRecordDecl::reverse_base_class_const_iterator I = + ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) { + const CXXBaseSpecifier &Base = *I; + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); + + // Ignore trivial destructors. + if (BaseClassDecl->hasTrivialDestructor()) + continue; + const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); + llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(), + ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + EmitCXXDestructorCall(D, Dtor_Base, V); + } + + // If we have a deleting destructor, emit a call to the delete operator. + if (DtorType == Dtor_Deleting) { + assert(DD->getOperatorDelete() && + "operator delete missing - EmitDtorEpilogue"); + EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(), + getContext().getTagDeclType(ClassDecl)); + } +} + +void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, + CXXDtorType DtorType, + llvm::Function *Fn, + const FunctionArgList &Args) { + assert(!Dtor->getParent()->hasUserDeclaredDestructor() && + "SynthesizeDefaultDestructor - destructor has user declaration"); + + StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args, + SourceLocation()); + + EmitDtorEpilogue(Dtor, DtorType); + FinishFunction(); +} diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 2238c89..19695c8 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -123,8 +123,6 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { CLANG_VENDOR #endif "clang " CLANG_VERSION_STRING; - bool isOptimized = LO.Optimize; - const char *Flags = ""; // FIXME: Encode command line options. // Figure out which version of the ObjC runtime we have. unsigned RuntimeVers = 0; @@ -132,11 +130,9 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1; // Create new compile unit. - return Unit = DebugFactory.CreateCompileUnit(LangTag, - AbsFileName.getLast(), - AbsFileName.getDirname(), - Producer, isMain, - isOptimized, Flags, RuntimeVers); + return Unit = DebugFactory.CreateCompileUnit( + LangTag, AbsFileName.getLast(), AbsFileName.getDirname(), Producer, isMain, + LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers); } /// CreateType - Get the Basic type from the cache or create a new @@ -834,27 +830,43 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty, 0, 0, 0, llvm::DIType(), Elements); } -static QualType CanonicalizeTypeForDebugInfo(QualType T) { - switch (T->getTypeClass()) { - default: - return T; - case Type::TemplateSpecialization: - return cast<TemplateSpecializationType>(T)->desugar(); - case Type::TypeOfExpr: { - TypeOfExprType *Ty = cast<TypeOfExprType>(T); - return CanonicalizeTypeForDebugInfo(Ty->getUnderlyingExpr()->getType()); - } - case Type::TypeOf: - return cast<TypeOfType>(T)->getUnderlyingType(); - case Type::Decltype: - return cast<DecltypeType>(T)->getUnderlyingType(); - case Type::QualifiedName: - return cast<QualifiedNameType>(T)->getNamedType(); - case Type::SubstTemplateTypeParm: - return cast<SubstTemplateTypeParmType>(T)->getReplacementType(); - case Type::Elaborated: - return cast<ElaboratedType>(T)->getUnderlyingType(); - } +static QualType UnwrapTypeForDebugInfo(QualType T) { + do { + QualType LastT = T; + switch (T->getTypeClass()) { + default: + return T; + case Type::TemplateSpecialization: + T = cast<TemplateSpecializationType>(T)->desugar(); + break; + case Type::TypeOfExpr: { + TypeOfExprType *Ty = cast<TypeOfExprType>(T); + T = Ty->getUnderlyingExpr()->getType(); + break; + } + case Type::TypeOf: + T = cast<TypeOfType>(T)->getUnderlyingType(); + break; + case Type::Decltype: + T = cast<DecltypeType>(T)->getUnderlyingType(); + break; + case Type::QualifiedName: + T = cast<QualifiedNameType>(T)->getNamedType(); + break; + case Type::SubstTemplateTypeParm: + T = cast<SubstTemplateTypeParmType>(T)->getReplacementType(); + break; + case Type::Elaborated: + T = cast<ElaboratedType>(T)->getUnderlyingType(); + break; + } + + assert(T != LastT && "Type unwrapping failed to unwrap!"); + if (T == LastT) + return T; + } while (true); + + return T; } /// getOrCreateType - Get the type from the cache or create a new @@ -864,8 +876,8 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, if (Ty.isNull()) return llvm::DIType(); - // Canonicalize the type. - Ty = CanonicalizeTypeForDebugInfo(Ty); + // Unwrap the type as needed for debug information. + Ty = UnwrapTypeForDebugInfo(Ty); // Check for existing entry. std::map<void *, llvm::WeakVH>::iterator it = @@ -891,6 +903,8 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, if (Ty.hasLocalQualifiers()) return CreateQualifiedType(Ty, Unit); + const char *Diag = 0; + // Work out details of type. switch (Ty->getTypeClass()) { #define TYPE(Class, Base) @@ -903,11 +917,8 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, // FIXME: Handle these. case Type::ExtVector: case Type::Vector: - case Type::FixedWidthInt: - return llvm::DIType(); - default: - assert(false && "Unhandled type class!"); return llvm::DIType(); + case Type::ObjCObjectPointer: return CreateType(cast<ObjCObjectPointerType>(Ty), Unit); case Type::ObjCInterface: @@ -934,7 +945,29 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::MemberPointer: return CreateType(cast<MemberPointerType>(Ty), Unit); + + case Type::TemplateSpecialization: + case Type::Elaborated: + case Type::QualifiedName: + case Type::SubstTemplateTypeParm: + case Type::TypeOfExpr: + case Type::TypeOf: + case Type::Decltype: + llvm_unreachable("type should have been unwrapped!"); + return llvm::DIType(); + + case Type::RValueReference: + // FIXME: Implement! + Diag = "rvalue references"; + break; } + + assert(Diag && "Fall through without a diagnostic?"); + unsigned DiagID = CGM.getDiags().getCustomDiagID(Diagnostic::Error, + "debug information for %0 is not yet supported"); + CGM.getDiags().Report(FullSourceLoc(), DiagID) + << Diag; + return llvm::DIType(); } /// EmitFunctionStart - Constructs the debug code for entering a function - @@ -1067,7 +1100,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().IntTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = CGM.getContext().getTypeAlign(FType); @@ -1078,7 +1111,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().IntTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = CGM.getContext().getTypeAlign(FType); @@ -1182,9 +1215,9 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, llvm::DIScope DS(RegionStack.back()); llvm::DILocation DO(NULL); - llvm::DILocation DL = - DebugFactory.CreateLocation(Line, Column, DS, DO); - Builder.SetDebugLocation(Call, DL.getNode()); + llvm::DILocation DL = DebugFactory.CreateLocation(Line, Column, DS, DO); + + Call->setMetadata("dbg", DL.getNode()); } /// EmitDeclare - Emit local variable declaration debug info. @@ -1244,7 +1277,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().IntTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = CGM.getContext().getTypeAlign(FType); @@ -1255,7 +1288,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().IntTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = CGM.getContext().getTypeAlign(FType); @@ -1385,7 +1418,8 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, llvm::DILocation DO(NULL); llvm::DILocation DL = DebugFactory.CreateLocation(Line, PLoc.getColumn(), DS, DO); - Builder.SetDebugLocation(Call, DL.getNode()); + + Call->setMetadata("dbg", DL.getNode()); } void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *Decl, diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 14ee90d..602cc9e 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -15,6 +15,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/SourceManager.h" @@ -471,7 +472,8 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { const llvm::Type *IntPtr = llvm::IntegerType::get(VMContext, LLVMPointerWidth); llvm::Value *SizeVal = - llvm::ConstantInt::get(IntPtr, getContext().getTypeSizeInBytes(Ty)); + llvm::ConstantInt::get(IntPtr, + getContext().getTypeSizeInChars(Ty).getRaw()); const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); if (Loc->getType() != BP) @@ -641,7 +643,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr, ConvertType(ArgTy))), getContext().getPointerType(D.getType()))); - EmitCall(Info, F, Args); + EmitCall(Info, F, ReturnValueSlot(), Args); } if (Exceptions) { EHCleanupBlock Cleanup(*this); @@ -650,7 +652,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr, ConvertType(ArgTy))), getContext().getPointerType(D.getType()))); - EmitCall(Info, F, Args); + EmitCall(Info, F, ReturnValueSlot(), Args); } } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index b15b2e9..bd0461f 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -149,21 +149,39 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E, CGF.EmitAggExpr(E, This, false); } else if (CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(CGF.getContext(), 0)) { - llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest(); + llvm::Value *CondPtr = 0; if (CGF.Exceptions) { CodeGenFunction::EHCleanupBlock Cleanup(CGF); llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF); + llvm::BasicBlock *CondBlock = CGF.createBasicBlock("cond.free"); + llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); + CondPtr = CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()), + "doEHfree"); + + CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CondPtr), + CondBlock, Cont); + CGF.EmitBlock(CondBlock); + // Load the exception pointer. llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr); CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr); + + CGF.EmitBlock(Cont); } + if (CondPtr) + CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()), + CondPtr); + llvm::Value *Src = CGF.EmitLValue(E).getAddress(); - CGF.setInvokeDest(PrevLandingPad); + + if (CondPtr) + CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()), + CondPtr); llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); - PrevLandingPad = CGF.getInvokeDest(); + llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest(); CGF.setInvokeDest(TerminateHandler); // Stolen from EmitClassAggrMemberwiseCopy @@ -179,7 +197,7 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E, QualType ResultType = CopyCtor->getType()->getAs<FunctionType>()->getResultType(); CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), - Callee, CallArgs, CopyCtor); + Callee, ReturnValueSlot(), CallArgs, CopyCtor); CGF.setInvokeDest(PrevLandingPad); } else llvm_unreachable("uncopyable object"); @@ -189,14 +207,22 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E, // CopyObject - Utility to copy an object. Calls copy constructor as necessary. // N is casted to the right type. static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, - bool WasPointer, llvm::Value *E, llvm::Value *N) { + bool WasPointer, bool WasPointerReference, + llvm::Value *E, llvm::Value *N) { // Store the throw exception in the exception object. if (WasPointer || !CGF.hasAggregateLLVMType(ObjectType)) { llvm::Value *Value = E; if (!WasPointer) Value = CGF.Builder.CreateLoad(Value); const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); - CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); + if (WasPointerReference) { + llvm::Value *Tmp = CGF.CreateTempAlloca(Value->getType(), "catch.param"); + CGF.Builder.CreateStore(Value, Tmp); + Value = Tmp; + ValuePtrTy = Value->getType()->getPointerTo(0); + } + N = CGF.Builder.CreateBitCast(N, ValuePtrTy); + CGF.Builder.CreateStore(Value, N); } else { const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); const CXXRecordDecl *RD; @@ -221,7 +247,7 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, QualType ResultType = CopyCtor->getType()->getAs<FunctionType>()->getResultType(); CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), - Callee, CallArgs, CopyCtor); + Callee, ReturnValueSlot(), CallArgs, CopyCtor); } else llvm_unreachable("uncopyable object"); } @@ -264,7 +290,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { // Now throw the exception. const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - llvm::Constant *TypeInfo = CGM.GenerateRTTI(ThrowType); + llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType); llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); if (getInvokeDest()) { @@ -347,8 +373,9 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { for (unsigned i = 0; i < Proto->getNumExceptions(); ++i) { QualType Ty = Proto->getExceptionType(i); - llvm::Value *EHType - = CGM.GenerateRTTI(Ty.getNonReferenceType()); + QualType ExceptType + = Ty.getNonReferenceType().getUnqualifiedType(); + llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType); SelectorArgs.push_back(EHType); } if (Proto->getNumExceptions()) @@ -487,9 +514,12 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { const CXXCatchStmt *C = S.getHandler(i); VarDecl *CatchParam = C->getExceptionDecl(); if (CatchParam) { - llvm::Value *EHType - = CGM.GenerateRTTI(C->getCaughtType().getNonReferenceType()); - SelectorArgs.push_back(EHType); + // C++ [except.handle]p3 indicates that top-level cv-qualifiers + // are ignored. + QualType CaughtType = C->getCaughtType().getNonReferenceType(); + llvm::Value *EHTypeInfo + = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType()); + SelectorArgs.push_back(EHTypeInfo); } else { // null indicates catch all SelectorArgs.push_back(Null); @@ -541,7 +571,12 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { QualType CatchType = CatchParam->getType().getNonReferenceType(); setInvokeDest(TerminateHandler); bool WasPointer = true; - if (!CatchType.getTypePtr()->isPointerType()) { + bool WasPointerReference = false; + CatchType = CGM.getContext().getCanonicalType(CatchType); + if (CatchType.getTypePtr()->isPointerType()) { + if (isa<ReferenceType>(CatchParam->getType())) + WasPointerReference = true; + } else { if (!isa<ReferenceType>(CatchParam->getType())) WasPointer = false; CatchType = getContext().getPointerType(CatchType); @@ -552,7 +587,8 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { // cleanup doesn't start until after the ctor completes, use a decl // init? CopyObject(*this, CatchParam->getType().getNonReferenceType(), - WasPointer, ExcObject, GetAddrOfLocalVar(CatchParam)); + WasPointer, WasPointerReference, ExcObject, + GetAddrOfLocalVar(CatchParam)); setInvokeDest(MatchHandler); } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index e6bbfa8..ab451cf 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -97,13 +97,15 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, bool IsInitializer) { bool ShouldDestroyTemporaries = false; unsigned OldNumLiveTemporaries = 0; - - if (const CXXExprWithTemporaries *TE = dyn_cast<CXXExprWithTemporaries>(E)) { - ShouldDestroyTemporaries = TE->shouldDestroyTemporaries(); + if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E)) + E = DAE->getExpr(); + + if (const CXXExprWithTemporaries *TE = dyn_cast<CXXExprWithTemporaries>(E)) { + ShouldDestroyTemporaries = true; + // Keep track of the current cleanup stack depth. - if (ShouldDestroyTemporaries) - OldNumLiveTemporaries = LiveTemporaries.size(); + OldNumLiveTemporaries = LiveTemporaries.size(); E = TE->getSubExpr(); } @@ -209,6 +211,34 @@ unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx, return cast<llvm::ConstantInt>(Elts->getOperand(Idx))->getZExtValue(); } +void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) { + if (!CatchUndefined) + return; + + const llvm::IntegerType *Size_tTy + = llvm::IntegerType::get(VMContext, LLVMPointerWidth); + Address = Builder.CreateBitCast(Address, PtrToInt8Ty); + + const llvm::Type *ResType[] = { + Size_tTy + }; + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, ResType, 1); + const llvm::IntegerType *IntTy = cast<llvm::IntegerType>( + CGM.getTypes().ConvertType(CGM.getContext().IntTy)); + // In time, people may want to control this and use a 1 here. + llvm::Value *Arg = llvm::ConstantInt::get(IntTy, 0); + llvm::Value *C = Builder.CreateCall2(F, Address, Arg); + llvm::BasicBlock *Cont = createBasicBlock(); + llvm::BasicBlock *Check = createBasicBlock(); + llvm::Value *NegativeOne = llvm::ConstantInt::get(Size_tTy, -1ULL); + Builder.CreateCondBr(Builder.CreateICmpEQ(C, NegativeOne), Cont, Check); + + EmitBlock(Check); + Builder.CreateCondBr(Builder.CreateICmpUGE(C, + llvm::ConstantInt::get(Size_tTy, Size)), + Cont, getTrapBB()); + EmitBlock(Cont); +} //===----------------------------------------------------------------------===// // LValue Expression Emission @@ -246,6 +276,13 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E, MakeQualifiers(E->getType())); } +LValue CodeGenFunction::EmitCheckedLValue(const Expr *E) { + LValue LV = EmitLValue(E); + if (!isa<DeclRefExpr>(E) && !LV.isBitfield() && LV.isSimple()) + EmitCheck(LV.getAddress(), getContext().getTypeSize(E->getType()) / 8); + return LV; +} + /// EmitLValue - Emit code to compute a designator that specifies the location /// of the expression. /// @@ -1072,8 +1109,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { llvm::IntegerType::get(VMContext, LLVMPointerWidth), IdxSigned, "idxprom"); + // FIXME: As llvm implements the object size checking, this can come out. if (CatchUndefined) { - if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E->getBase())) { + if (const ImplicitCastExpr *ICE=dyn_cast<ImplicitCastExpr>(E->getBase())) { if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) { if (ICE->getCastKind() == CastExpr::CK_ArrayToPointerDecay) { if (const ConstantArrayType *CAT @@ -1141,7 +1179,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { static llvm::Constant *GenerateConstantVector(llvm::LLVMContext &VMContext, llvm::SmallVector<unsigned, 4> &Elts) { - llvm::SmallVector<llvm::Constant *, 4> CElts; + llvm::SmallVector<llvm::Constant*, 4> CElts; for (unsigned i = 0, e = Elts.size(); i != e; ++i) CElts.push_back(llvm::ConstantInt::get( @@ -1152,21 +1190,37 @@ llvm::Constant *GenerateConstantVector(llvm::LLVMContext &VMContext, LValue CodeGenFunction:: EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { + const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext); + // Emit the base vector as an l-value. LValue Base; // ExtVectorElementExpr's base can either be a vector or pointer to vector. - if (!E->isArrow()) { - assert(E->getBase()->getType()->isVectorType()); - Base = EmitLValue(E->getBase()); - } else { - const PointerType *PT = E->getBase()->getType()->getAs<PointerType>(); + if (E->isArrow()) { + // If it is a pointer to a vector, emit the address and form an lvalue with + // it. llvm::Value *Ptr = EmitScalarExpr(E->getBase()); + const PointerType *PT = E->getBase()->getType()->getAs<PointerType>(); Qualifiers Quals = MakeQualifiers(PT->getPointeeType()); Quals.removeObjCGCAttr(); Base = LValue::MakeAddr(Ptr, Quals); + } else if (E->getBase()->isLvalue(getContext()) == Expr::LV_Valid) { + // Otherwise, if the base is an lvalue ( as in the case of foo.x.x), + // emit the base as an lvalue. + assert(E->getBase()->getType()->isVectorType()); + Base = EmitLValue(E->getBase()); + } else { + // Otherwise, the base is a normal rvalue (as in (V+V).x), emit it as such. + const VectorType *VT = E->getBase()->getType()->getAs<VectorType>(); + assert(VT && "Result must be a vector"); + llvm::Value *Vec = EmitScalarExpr(E->getBase()); + + // Store the vector to memory (because LValue wants an address). + llvm::Value *VecMem =CreateTempAlloca(ConvertType(E->getBase()->getType())); + Builder.CreateStore(Vec, VecMem); + Base = LValue::MakeAddr(VecMem, Qualifiers()); } - + // Encode the element access list into a vector of unsigned indices. llvm::SmallVector<unsigned, 4> Indices; E->getEncodedElementAccess(Indices); @@ -1181,7 +1235,6 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { llvm::Constant *BaseElts = Base.getExtVectorElts(); llvm::SmallVector<llvm::Constant *, 4> CElts; - const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext); for (unsigned i = 0, e = Indices.size(); i != e; ++i) { if (isa<llvm::ConstantAggregateZero>(BaseElts)) CElts.push_back(llvm::ConstantInt::get(Int32Ty, 0)); @@ -1325,12 +1378,20 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ LValue CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) { if (E->isLvalue(getContext()) == Expr::LV_Valid) { + if (int Cond = ConstantFoldsToSimpleInteger(E->getCond())) { + Expr *Live = Cond == 1 ? E->getLHS() : E->getRHS(); + if (Live) + return EmitLValue(Live); + } + + if (!E->getLHS()) + return EmitUnsupportedLValue(E, "conditional operator with missing LHS"); + llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true"); llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false"); llvm::BasicBlock *ContBlock = createBasicBlock("cond.end"); - llvm::Value *Cond = EvaluateExprAsBool(E->getCond()); - Builder.CreateCondBr(Cond, LHSBlock, RHSBlock); + EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); EmitBlock(LHSBlock); @@ -1390,6 +1451,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CastExpr::CK_NoOp: case CastExpr::CK_ConstructorConversion: case CastExpr::CK_UserDefinedConversion: + case CastExpr::CK_AnyPointerToObjCPointerCast: return EmitLValue(E->getSubExpr()); case CastExpr::CK_DerivedToBase: { @@ -1464,13 +1526,14 @@ LValue CodeGenFunction::EmitNullInitializationLValue( //===--------------------------------------------------------------------===// -RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { +RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, + ReturnValueSlot ReturnValue) { // Builtins never have block type. if (E->getCallee()->getType()->isBlockPointerType()) - return EmitBlockCallExpr(E); + return EmitBlockCallExpr(E, ReturnValue); if (const CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(E)) - return EmitCXXMemberCallExpr(CE); + return EmitCXXMemberCallExpr(CE, ReturnValue); const Decl *TargetDecl = 0; if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E->getCallee())) { @@ -1484,7 +1547,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { if (const CXXOperatorCallExpr *CE = dyn_cast<CXXOperatorCallExpr>(E)) if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl)) - return EmitCXXOperatorMemberCallExpr(CE, MD); + return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue); if (isa<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) { // C++ [expr.pseudo]p1: @@ -1497,7 +1560,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { } llvm::Value *Callee = EmitScalarExpr(E->getCallee()); - return EmitCall(Callee, E->getCallee()->getType(), + return EmitCall(E->getCallee()->getType(), Callee, ReturnValue, E->arg_begin(), E->arg_end(), TargetDecl); } @@ -1658,7 +1721,8 @@ LValue CodeGenFunction::EmitPointerToDataMemberLValue(const FieldDecl *Field) { return LValue::MakeAddr(V, MakeQualifiers(Field->getType())); } -RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, +RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, + ReturnValueSlot ReturnValue, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd, const Decl *TargetDecl) { @@ -1683,7 +1747,7 @@ RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, CallingConvention = F->getCallingConv(); return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args, CallingConvention), - Callee, Args, TargetDecl); + Callee, ReturnValue, Args, TargetDecl); } LValue CodeGenFunction:: diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 2c122eb..b95fd79 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -106,6 +106,7 @@ public: void VisitConditionalOperator(const ConditionalOperator *CO); void VisitChooseExpr(const ChooseExpr *CE); void VisitInitListExpr(InitListExpr *E); + void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E); void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { Visit(DAE->getExpr()); } @@ -271,6 +272,13 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) { return; } + // If the struct doesn't require GC, we can just pass the destination + // directly to EmitCall. + if (!RequiresGCollection) { + CGF.EmitCallExpr(E, ReturnValueSlot(DestPtr, VolatileDest)); + return; + } + RValue RV = CGF.EmitCallExpr(E); EmitFinalDestCopy(E, RV); } @@ -388,12 +396,16 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { } void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) { + if (!E->getLHS()) { + CGF.ErrorUnsupported(E, "conditional operator with missing LHS"); + return; + } + llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end"); - llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond()); - Builder.CreateCondBr(Cond, LHSBlock, RHSBlock); + CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); CGF.StartConditionalBranch(); CGF.EmitBlock(LHSBlock); @@ -457,16 +469,45 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) { Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp"); } + if (E->requiresZeroInitialization()) + EmitNullInitializationToLValue(LValue::MakeAddr(Val, + // FIXME: Qualifiers()? + E->getType().getQualifiers()), + E->getType()); + CGF.EmitCXXConstructExpr(Val, E); } void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { - CGF.EmitCXXExprWithTemporaries(E, DestPtr, VolatileDest, IsInitializer); + llvm::Value *Val = DestPtr; + + if (!Val) { + // Create a temporary variable. + Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp"); + } + CGF.EmitCXXExprWithTemporaries(E, Val, VolatileDest, IsInitializer); } void AggExprEmitter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { - LValue lvalue = LValue::MakeAddr(DestPtr, Qualifiers()); - EmitNullInitializationToLValue(lvalue, E->getType()); + llvm::Value *Val = DestPtr; + + if (!Val) { + // Create a temporary variable. + Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp"); + } + LValue LV = LValue::MakeAddr(Val, Qualifiers()); + EmitNullInitializationToLValue(LV, E->getType()); +} + +void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { + llvm::Value *Val = DestPtr; + + if (!Val) { + // Create a temporary variable. + Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp"); + } + LValue LV = LValue::MakeAddr(Val, Qualifiers()); + EmitNullInitializationToLValue(LV, E->getType()); } void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) { diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 150f11e..7992322 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -78,7 +78,6 @@ static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { } return CalculateCookiePadding(Ctx, E->getAllocatedType()); - QualType T = E->getAllocatedType(); } static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, @@ -212,7 +211,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // Emit the call to new. RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs), - CGM.GetAddrOfFunction(NewFD), NewArgs, NewFD); + CGM.GetAddrOfFunction(NewFD), ReturnValueSlot(), NewArgs, NewFD); // If an allocation function is declared with an empty exception specification // it returns null to indicate failure to allocate storage. [expr.new]p13. @@ -354,7 +353,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, // Emit the call to delete. EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), DeleteArgs), - CGM.GetAddrOfFunction(DeleteFD), + CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(), DeleteArgs, DeleteFD); } @@ -406,7 +405,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { /*isVariadic=*/false); llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty); - EmitCXXMemberCall(Dtor, Callee, Ptr, 0, 0); + EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, 0, 0); // The dtor took care of deleting the object. ShouldCallDelete = false; @@ -426,9 +425,12 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { QualType Ty = E->getType(); const llvm::Type *LTy = ConvertType(Ty)->getPointerTo(); - if (E->isTypeOperand()) - return Builder.CreateBitCast(CGM.GetAddrOfRTTI(E->getTypeOperand()), LTy); - + if (E->isTypeOperand()) { + llvm::Constant *TypeInfo = + CGM.GetAddrOfRTTIDescriptor(E->getTypeOperand()); + return Builder.CreateBitCast(TypeInfo, LTy); + } + Expr *subE = E->getExprOperand(); Ty = subE->getType(); CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); @@ -468,24 +470,23 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { V = Builder.CreateConstInBoundsGEP1_64(V, -1ULL); V = Builder.CreateLoad(V); return V; - } - return Builder.CreateBitCast(CGM.GenerateRTTI(RD), LTy); + } } - return Builder.CreateBitCast(CGM.GenerateRTTI(Ty), LTy); + return Builder.CreateBitCast(CGM.GetAddrOfRTTIDescriptor(Ty), LTy); } llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE) { - QualType CastTy = DCE->getTypeAsWritten(); - QualType InnerType = CastTy->getPointeeType(); - QualType ArgTy = DCE->getSubExpr()->getType(); - const llvm::Type *LArgTy = ConvertType(ArgTy); + QualType SrcTy = DCE->getSubExpr()->getType(); + QualType DestTy = DCE->getTypeAsWritten(); + QualType InnerType = DestTy->getPointeeType(); + const llvm::Type *LTy = ConvertType(DCE->getType()); bool CanBeZero = false; bool ToVoid = false; bool ThrowOnBad = false; - if (CastTy->isPointerType()) { + if (DestTy->isPointerType()) { // FIXME: if PointerType->hasAttr<NonNullAttr>(), we don't set this CanBeZero = true; if (InnerType->isVoidType()) @@ -495,14 +496,13 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, ThrowOnBad = true; } - CXXRecordDecl *SrcTy; - QualType Ty = ArgTy; - if (ArgTy.getTypePtr()->isPointerType() - || ArgTy.getTypePtr()->isReferenceType()) - Ty = Ty.getTypePtr()->getPointeeType(); - CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); - Ty = CanTy.getUnqualifiedType(); - SrcTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl()); + if (SrcTy->isPointerType() || SrcTy->isReferenceType()) + SrcTy = SrcTy->getPointeeType(); + SrcTy = SrcTy.getUnqualifiedType(); + + if (DestTy->isPointerType() || DestTy->isReferenceType()) + DestTy = DestTy->getPointeeType(); + DestTy = DestTy.getUnqualifiedType(); llvm::BasicBlock *ContBlock = createBasicBlock(); llvm::BasicBlock *NullBlock = 0; @@ -510,15 +510,13 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, if (CanBeZero) { NonZeroBlock = createBasicBlock(); NullBlock = createBasicBlock(); - llvm::Value *Zero = llvm::Constant::getNullValue(LArgTy); - Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), - NonZeroBlock, NullBlock); + Builder.CreateCondBr(Builder.CreateIsNotNull(V), NonZeroBlock, NullBlock); EmitBlock(NonZeroBlock); } llvm::BasicBlock *BadCastBlock = 0; - const llvm::Type *PtrDiffTy = ConvertType(getContext().getSizeType()); + const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); // See if this is a dynamic_cast(void*) if (ToVoid) { @@ -542,27 +540,27 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, ArgTys.push_back(PtrToInt8Ty); ArgTys.push_back(PtrDiffTy); FTy = llvm::FunctionType::get(ResultType, ArgTys, false); - CXXRecordDecl *DstTy; - Ty = CastTy.getTypePtr()->getPointeeType(); - CanTy = CGM.getContext().getCanonicalType(Ty); - Ty = CanTy.getUnqualifiedType(); - DstTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl()); // FIXME: Calculate better hint. llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL); - llvm::Value *SrcArg = CGM.GenerateRTTIRef(SrcTy); - llvm::Value *DstArg = CGM.GenerateRTTIRef(DstTy); + + assert(SrcTy->isRecordType() && "Src type must be record type!"); + assert(DestTy->isRecordType() && "Dest type must be record type!"); + + llvm::Value *SrcArg + = CGM.GetAddrOfRTTIDescriptor(SrcTy.getUnqualifiedType()); + llvm::Value *DestArg + = CGM.GetAddrOfRTTIDescriptor(DestTy.getUnqualifiedType()); + V = Builder.CreateBitCast(V, PtrToInt8Ty); V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"), - V, SrcArg, DstArg, hint); + V, SrcArg, DestArg, hint); V = Builder.CreateBitCast(V, LTy); if (ThrowOnBad) { BadCastBlock = createBasicBlock(); - llvm::Value *Zero = llvm::Constant::getNullValue(LTy); - Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), - ContBlock, BadCastBlock); + Builder.CreateCondBr(Builder.CreateIsNotNull(V), ContBlock, BadCastBlock); EmitBlock(BadCastBlock); /// Call __cxa_bad_cast ResultType = llvm::Type::getVoidTy(VMContext); diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 7fa8ffb..be2239f 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -626,6 +626,14 @@ ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) { ComplexPairTy ComplexExprEmitter:: VisitConditionalOperator(const ConditionalOperator *E) { + if (!E->getLHS()) { + CGF.ErrorUnsupported(E, "conditional operator with missing LHS"); + const llvm::Type *EltTy = + CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType()); + llvm::Value *U = llvm::UndefValue::get(EltTy); + return ComplexPairTy(U, U); + } + TestAndClearIgnoreReal(); TestAndClearIgnoreImag(); TestAndClearIgnoreRealAssign(); @@ -634,8 +642,7 @@ VisitConditionalOperator(const ConditionalOperator *E) { llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end"); - llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond()); - Builder.CreateCondBr(Cond, LHSBlock, RHSBlock); + CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); CGF.EmitBlock(LHSBlock); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 2f31c05..93646d6 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -69,6 +69,7 @@ public: const llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); } LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); } + LValue EmitCheckedLValue(const Expr *E) { return CGF.EmitCheckedLValue(E); } Value *EmitLoadOfLValue(LValue LV, QualType T) { return CGF.EmitLoadOfLValue(LV, T).getScalarVal(); @@ -78,7 +79,7 @@ public: /// value l-value, this method emits the address of the l-value, then loads /// and returns the result. Value *EmitLoadOfLValue(const Expr *E) { - return EmitLoadOfLValue(EmitLValue(E), E->getType()); + return EmitLoadOfLValue(EmitCheckedLValue(E), E->getType()); } /// EmitConversionToBool - Convert the specified expression value to a @@ -327,16 +328,16 @@ public: Value *VisitBin ## OP ## Assign(const CompoundAssignOperator *E) { \ return EmitCompoundAssign(E, &ScalarExprEmitter::Emit ## OP); \ } - HANDLEBINOP(Mul); - HANDLEBINOP(Div); - HANDLEBINOP(Rem); - HANDLEBINOP(Add); - HANDLEBINOP(Sub); - HANDLEBINOP(Shl); - HANDLEBINOP(Shr); - HANDLEBINOP(And); - HANDLEBINOP(Xor); - HANDLEBINOP(Or); + HANDLEBINOP(Mul) + HANDLEBINOP(Div) + HANDLEBINOP(Rem) + HANDLEBINOP(Add) + HANDLEBINOP(Sub) + HANDLEBINOP(Shl) + HANDLEBINOP(Shr) + HANDLEBINOP(And) + HANDLEBINOP(Xor) + HANDLEBINOP(Or) #undef HANDLEBINOP // Comparisons. @@ -346,12 +347,12 @@ public: Value *VisitBin##CODE(const BinaryOperator *E) { \ return EmitCompare(E, llvm::ICmpInst::UI, llvm::ICmpInst::SI, \ llvm::FCmpInst::FP); } - VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT); - VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT); - VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE); - VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE); - VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ); - VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE); + VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT) + VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT) + VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE) + VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE) + VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ) + VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE) #undef VISITCOMP Value *VisitBinAssign (const BinaryOperator *E); @@ -815,6 +816,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { return Builder.CreateBitCast(Src, ConvertType(DestTy)); } case CastExpr::CK_NoOp: + case CastExpr::CK_UserDefinedConversion: return Visit(const_cast<Expr*>(E)); case CastExpr::CK_BaseToDerived: { @@ -902,7 +904,6 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { return Src; } - case CastExpr::CK_UserDefinedConversion: case CastExpr::CK_ConstructorConversion: assert(0 && "Should be unreachable!"); break; @@ -1198,7 +1199,7 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) { Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) { bool Ignore = TestAndClearIgnoreResultAssign(); - QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType(); + QualType LHSTy = E->getLHS()->getType(); BinOpInfo OpInfo; @@ -1217,7 +1218,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, OpInfo.Ty = E->getComputationResultType(); OpInfo.E = E; // Load/convert the LHS. - LValue LHSLV = EmitLValue(E->getLHS()); + LValue LHSLV = EmitCheckedLValue(E->getLHS()); OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy); OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, E->getComputationLHSType()); @@ -1654,7 +1655,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { // __block variables need to have the rhs evaluated first, plus this should // improve codegen just a little. Value *RHS = Visit(E->getRHS()); - LValue LHS = EmitLValue(E->getLHS()); + LValue LHS = EmitCheckedLValue(E->getLHS()); // Store the value into the LHS. Bit-fields are handled specially // because the result is altered by the store, i.e., [C99 6.5.16p1] diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 2fe3f5b..ac391d9 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -190,7 +190,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, // FIXME: We shouldn't need to get the function info here, the // runtime already should have computed it to build the function. RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args), - GetPropertyFn, Args); + GetPropertyFn, ReturnValueSlot(), Args); // We need to fix the type here. Ivars with copy & retain are // always objects so we don't need to worry about complex or // aggregates. @@ -277,8 +277,8 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, getContext().BoolTy)); // FIXME: We shouldn't need to get the function info here, the runtime // already should have computed it to build the function. - EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args), - SetPropertyFn, Args); + EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args), SetPropertyFn, + ReturnValueSlot(), Args); } else { // FIXME: Find a clean way to avoid AST node creation. SourceLocation Loc = PD->getLocation(); @@ -553,7 +553,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ // FIXME: We shouldn't need to get the function info here, the runtime already // should have computed it to build the function. EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2), - EnumerationMutationFn, Args2); + EnumerationMutationFn, ReturnValueSlot(), Args2); EmitBlock(WasNotMutated); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index be772c7..95f67ae 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -450,7 +450,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, llvm::Value *imp = CGF.Builder.CreateCall(lookupFunction, lookupArgs, lookupArgs+2); - return CGF.EmitCall(FnInfo, imp, ActualArgs); + return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs); } /// Generate code for a message send expression. @@ -536,7 +536,7 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, imp = Builder.CreateCall2(lookupFunction, Receiver, cmd); } - return CGF.EmitCall(FnInfo, imp, ActualArgs); + return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs); } /// Generates a MethodList. Used in construction of a objc_class and @@ -1607,7 +1607,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, Params.push_back(PtrTy); llvm::Value *RethrowFn = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - Params, false), "_Unwind_Resume_or_Rethrow"); + Params, false), "objc_exception_throw"); bool isTry = isa<ObjCAtTryStmt>(S); llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try"); @@ -1618,7 +1618,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::BasicBlock *FinallyRethrow = CGF.createBasicBlock("finally.throw"); llvm::BasicBlock *FinallyEnd = CGF.createBasicBlock("finally.end"); - // GNU runtime does not currently support @synchronized() + // @synchronized() if (!isTry) { std::vector<const llvm::Type*> Args(1, IdTy); llvm::FunctionType *FTy = @@ -1770,7 +1770,13 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, ESelArgs.clear(); ESelArgs.push_back(Exc); ESelArgs.push_back(Personality); - ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0)); + // If there is a @catch or @finally clause in outside of this one then we + // need to make sure that we catch and rethrow it. + if (PrevLandingPad) { + ESelArgs.push_back(NULLPtr); + } else { + ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0)); + } CGF.Builder.CreateCall(llvm_eh_selector, ESelArgs.begin(), ESelArgs.end(), "selector"); CGF.Builder.CreateCall(llvm_eh_typeid_for, @@ -1811,11 +1817,23 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.EmitBranch(FinallyEnd); CGF.EmitBlock(FinallyRethrow); - CGF.Builder.CreateCall(RethrowFn, CGF.Builder.CreateLoad(RethrowPtr)); - CGF.Builder.CreateUnreachable(); - CGF.EmitBlock(FinallyEnd); + llvm::Value *ExceptionObject = CGF.Builder.CreateLoad(RethrowPtr); + llvm::BasicBlock *UnwindBB = CGF.getInvokeDest(); + if (!UnwindBB) { + CGF.Builder.CreateCall(RethrowFn, ExceptionObject); + // Exception always thrown, next instruction is never reached. + CGF.Builder.CreateUnreachable(); + } else { + // If there is a @catch block outside this scope, we invoke instead of + // calling because we may return to this function. This is very slow, but + // some people still do it. It would be nice to add an optimised path for + // this. + CGF.Builder.CreateInvoke(RethrowFn, UnwindBB, UnwindBB, &ExceptionObject, + &ExceptionObject+1); + } + CGF.EmitBlock(FinallyEnd); } void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index fb920f0..727746f 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -1581,7 +1581,7 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, assert(Fn && "EmitLegacyMessageSend - unknown API"); Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy)); - return CGF.EmitCall(FnInfo, Fn, ActualArgs); + return CGF.EmitCall(FnInfo, Fn, ReturnValueSlot(), ActualArgs); } llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder, @@ -3351,7 +3351,6 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( SkipScanIvars.push_back(SkScan); } - bool BytesSkipped = false; if (!SkipIvars.empty()) { unsigned int LastIndex = SkipIvars.size()-1; int LastByteSkipped = @@ -3360,9 +3359,8 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( int LastByteScanned = IvarsInfo[LastIndex].ivar_bytepos + IvarsInfo[LastIndex].ivar_size * WordSize; - BytesSkipped = (LastByteSkipped > LastByteScanned); // Compute number of bytes to skip at the tail end of the last ivar scanned. - if (BytesSkipped) { + if (LastByteSkipped > LastByteScanned) { unsigned int TotalWords = (LastByteSkipped + (WordSize -1)) / WordSize; SKIP_SCAN SkScan; SkScan.skip = TotalWords - (LastByteScanned/WordSize); @@ -3393,8 +3391,6 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( unsigned int skip_big = SkipScanIvars[i].skip / 0xf; unsigned int scan_big = SkipScanIvars[i].scan / 0xf; - if (skip_small > 0 || skip_big > 0) - BytesSkipped = true; // first skip big. for (unsigned int ix = 0; ix < skip_big; ix++) BitMap += (unsigned char)(0xf0); @@ -5169,7 +5165,7 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true); Callee = CGF.Builder.CreateBitCast(Callee, llvm::PointerType::getUnqual(FTy)); - return CGF.EmitCall(FnInfo1, Callee, ActualArgs); + return CGF.EmitCall(FnInfo1, Callee, ReturnValueSlot(), ActualArgs); } /// Generate code for a message send expression in the nonfragile abi. diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 02de00e..db6c507 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -21,76 +21,48 @@ namespace { class RTTIBuilder { CodeGenModule &CGM; // Per-module state. llvm::LLVMContext &VMContext; + const llvm::Type *Int8PtrTy; - llvm::SmallSet<const CXXRecordDecl *, 16> SeenVBase; - llvm::SmallSet<const CXXRecordDecl *, 32> SeenBase; - - // Type info flags. - enum { - /// TI_Const - Type has const qualifier. - TI_Const = 0x1, - - /// TI_Volatile - Type has volatile qualifier. - TI_Volatile = 0x2, - - /// TI_Restrict - Type has restrict qualifier. - TI_Restrict = 0x4, - - /// TI_Incomplete - Type is incomplete. - TI_Incomplete = 0x8, + + /// Fields - The fields of the RTTI descriptor currently being built. + llvm::SmallVector<llvm::Constant *, 16> Fields; - /// TI_ContainingClassIncomplete - Containing class is incomplete. - /// (in pointer to member). - TI_ContainingClassIncomplete = 0x10 - }; + /// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI + /// descriptor of the given type. + llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty); + + /// BuildVtablePointer - Build the vtable pointer for the given type. + void BuildVtablePointer(const Type *Ty); + + /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single + /// inheritance, according to the Itanium C++ ABI, 2.9.5p6b. + void BuildSIClassTypeInfo(const CXXRecordDecl *RD); + + /// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for + /// classes with bases that do not satisfy the abi::__si_class_type_info + /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c. + void BuildVMIClassTypeInfo(const CXXRecordDecl *RD); + + /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used + /// for pointer types. + void BuildPointerTypeInfo(const PointerType *Ty); + + /// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info + /// struct, used for member pointer types. + void BuildPointerToMemberTypeInfo(const MemberPointerType *Ty); public: RTTIBuilder(CodeGenModule &cgm) : CGM(cgm), VMContext(cgm.getModule().getContext()), Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { } - /// BuildVtableRef - Build a reference to a vtable. - llvm::Constant *BuildVtableRef(const char *Name) { - // Build a descriptor for Name - llvm::Constant *GV = CGM.getModule().getGlobalVariable(Name); - if (GV) - GV = llvm::ConstantExpr::getBitCast(GV, - llvm::PointerType::get(Int8PtrTy, 0)); - else { - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::ExternalLinkage; - GV = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy, - true, linktype, 0, Name); - } - llvm::Constant *C; - C = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 2); - C = llvm::ConstantExpr::getInBoundsGetElementPtr(GV, &C, 1); - return llvm::ConstantExpr::getBitCast(C, Int8PtrTy); - } - - // FIXME: This should be removed, and clients should pass in the linkage - // directly instead. - static inline llvm::GlobalVariable::LinkageTypes - GetLinkageFromExternFlag(bool Extern) { - if (Extern) - return llvm::GlobalValue::WeakODRLinkage; - - return llvm::GlobalValue::InternalLinkage; - } - - // FIXME: This should be removed, and clients should pass in the linkage - // directly instead. - llvm::Constant *BuildName(QualType Ty, bool Hidden, bool Extern) { - return BuildName(Ty, Hidden, GetLinkageFromExternFlag(Extern)); - } - llvm::Constant *BuildName(QualType Ty, bool Hidden, llvm::GlobalVariable::LinkageTypes Linkage) { llvm::SmallString<256> OutName; CGM.getMangleContext().mangleCXXRTTIName(Ty, OutName); llvm::StringRef Name = OutName.str(); - llvm::GlobalVariable *OGV = CGM.getModule().getGlobalVariable(Name); + llvm::GlobalVariable *OGV = CGM.getModule().getNamedGlobal(Name); if (OGV && !OGV->isDeclaration()) return llvm::ConstantExpr::getBitCast(OGV, Int8PtrTy); @@ -109,397 +81,789 @@ public: if (Hidden) GV->setVisibility(llvm::GlobalVariable::HiddenVisibility); return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); - }; - - /// - BuildFlags - Build a psABI __flags value for __vmi_class_type_info. - llvm::Constant *BuildFlags(int f) { - return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f); } - /// BuildBaseCount - Build a psABI __base_count value for - /// __vmi_class_type_info. - llvm::Constant *BuildBaseCount(unsigned c) { - return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), c); + // FIXME: unify with DecideExtern + bool DecideHidden(QualType Ty) { + // For this type, see if all components are never hidden. + if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()) + return (DecideHidden(MPT->getPointeeType()) + && DecideHidden(QualType(MPT->getClass(), 0))); + if (const PointerType *PT = Ty->getAs<PointerType>()) + return DecideHidden(PT->getPointeeType()); + if (const FunctionType *FT = Ty->getAs<FunctionType>()) { + if (DecideHidden(FT->getResultType()) == false) + return false; + if (const FunctionProtoType *FPT = Ty->getAs<FunctionProtoType>()) { + for (unsigned i = 0; i <FPT->getNumArgs(); ++i) + if (DecideHidden(FPT->getArgType(i)) == false) + return false; + for (unsigned i = 0; i <FPT->getNumExceptions(); ++i) + if (DecideHidden(FPT->getExceptionType(i)) == false) + return false; + return true; + } + } + if (const RecordType *RT = Ty->getAs<RecordType>()) + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) + return CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden; + return false; } + + // Pointer type info flags. + enum { + /// PTI_Const - Type has const qualifier. + PTI_Const = 0x1, + + /// PTI_Volatile - Type has volatile qualifier. + PTI_Volatile = 0x2, + + /// PTI_Restrict - Type has restrict qualifier. + PTI_Restrict = 0x4, + + /// PTI_Incomplete - Type is incomplete. + PTI_Incomplete = 0x8, + + /// PTI_ContainingClassIncomplete - Containing class is incomplete. + /// (in pointer to member). + PTI_ContainingClassIncomplete = 0x10 + }; + + // VMI type info flags. + enum { + /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance. + VMI_NonDiamondRepeat = 0x1, + + /// VMI_DiamondShaped - Class is diamond shaped. + VMI_DiamondShaped = 0x2 + }; + + // Base class type info flags. + enum { + /// BCTI_Virtual - Base class is virtual. + BCTI_Virtual = 0x1, + + /// BCTI_Public - Base class is public. + BCTI_Public = 0x2 + }; + + /// BuildTypeInfo - Build the RTTI type info struct for the given type. + llvm::Constant *BuildTypeInfo(QualType Ty); +}; +} - llvm::Constant *BuildTypeRef(QualType Ty) { - llvm::Constant *C; - - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); - llvm::StringRef Name = OutName.str(); - - C = CGM.getModule().getGlobalVariable(Name); - if (C) - return llvm::ConstantExpr::getBitCast(C, Int8PtrTy); - - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::ExternalLinkage;; +llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) { + // Mangle the RTTI name. + llvm::SmallString<256> OutName; + CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); + llvm::StringRef Name = OutName.str(); - C = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy, true, linktype, - 0, Name); - return llvm::ConstantExpr::getBitCast(C, Int8PtrTy); + // Look for an existing global. + llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name); + + if (!GV) { + // Create a new global variable. + GV = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy, /*Constant=*/true, + llvm::GlobalValue::ExternalLinkage, 0, Name); } + + return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); +} - llvm::Constant *Buildclass_type_infoRef(const CXXRecordDecl *RD) { - return BuildTypeRef(CGM.getContext().getTagDeclType(RD)); - } +/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type +/// info for that type is defined in the standard library. +static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { + // Itanium C++ ABI 2.9.2: + // Basic type information (e.g. for "int", "bool", etc.) will be kept in + // the run-time support library. Specifically, the run-time support + // library should contain type_info objects for the types X, X* and + // X const*, for every X in: void, bool, wchar_t, char, unsigned char, + // signed char, short, unsigned short, int, unsigned int, long, + // unsigned long, long long, unsigned long long, float, double, long double, + // char16_t, char32_t, and the IEEE 754r decimal and half-precision + // floating point types. + switch (Ty->getKind()) { + case BuiltinType::Void: + case BuiltinType::Bool: + case BuiltinType::WChar: + case BuiltinType::Char_U: + case BuiltinType::Char_S: + case BuiltinType::UChar: + case BuiltinType::SChar: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: + case BuiltinType::Float: + case BuiltinType::Double: + case BuiltinType::LongDouble: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::Int128: + case BuiltinType::UInt128: + return true; + + case BuiltinType::Overload: + case BuiltinType::Dependent: + case BuiltinType::UndeducedAuto: + assert(false && "Should not see this type here!"); + + case BuiltinType::NullPtr: + assert(false && "FIXME: nullptr_t is not handled!"); - /// CalculateFlags - Calculate the flags for the __vmi_class_type_info - /// datastructure. 1 for non-diamond repeated inheritance, 2 for a dimond - /// shaped class. - int CalculateFlags(const CXXRecordDecl*RD) { - int flags = 0; - if (SeenBase.count(RD)) - flags |= 1; - else - SeenBase.insert(RD); - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (i->isVirtual()) { - if (SeenVBase.count(Base)) - flags |= 2; - else - SeenVBase.insert(Base); - } - flags |= CalculateFlags(Base); - } - return flags; + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + assert(false && "FIXME: Objective-C types are unsupported!"); } + + // Silent gcc. + return false; +} - bool SimpleInheritance(const CXXRecordDecl *RD) { - if (RD->getNumBases() != 1) - return false; - CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(); - if (i->isVirtual()) - return false; - if (i->getAccessSpecifier() != AS_public) - return false; +static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) { + QualType PointeeTy = PointerTy->getPointeeType(); + const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(PointeeTy); + if (!BuiltinTy) + return false; + + // Check the qualifiers. + Qualifiers Quals = PointeeTy.getQualifiers(); + Quals.removeConst(); + + if (!Quals.empty()) + return false; + + return TypeInfoIsInStandardLibrary(BuiltinTy); +} - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (Layout.getBaseClassOffset(Base) != 0) +/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for +/// the given type exists somewhere else, and that we should not emit the typ +/// information in this translation unit. +bool ShouldUseExternalRTTIDescriptor(QualType Ty) { + // Type info for builtin types is defined in the standard library. + if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty)) + return TypeInfoIsInStandardLibrary(BuiltinTy); + + // Type info for some pointer types to builtin types is defined in the + // standard library. + if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty)) + return TypeInfoIsInStandardLibrary(PointerTy); + + if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); + if (!RD->isDynamicClass()) return false; - return true; - } - llvm::Constant *finish(llvm::Constant *const *Values, unsigned NumValues, - llvm::GlobalVariable *GV, - llvm::StringRef Name, bool Hidden, - llvm::GlobalVariable::LinkageTypes Linkage) { - llvm::Constant *C = - llvm::ConstantStruct::get(VMContext, Values, NumValues, /*Packed=*/false); - - llvm::GlobalVariable *OGV = GV; - GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, Linkage, - C, Name); - if (OGV) { - GV->takeName(OGV); - llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV, - OGV->getType()); - OGV->replaceAllUsesWith(NewPtr); - OGV->eraseFromParent(); + // Get the key function. + const CXXMethodDecl *KeyFunction = RD->getASTContext().getKeyFunction(RD); + if (KeyFunction && !KeyFunction->getBody()) { + // The class has a key function, but it is not defined in this translation + // unit, so we should use the external descriptor for it. + return true; } - if (Hidden) - GV->setVisibility(llvm::GlobalVariable::HiddenVisibility); - return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); } + + return false; +} +/// IsIncompleteClassType - Returns whether the given record type is incomplete. +static bool IsIncompleteClassType(const RecordType *RecordTy) { + return !RecordTy->getDecl()->isDefinition(); +} + +/// ContainsIncompleteClassType - Returns whether the given type contains an +/// incomplete class type. This is true if +/// +/// * The given type is an incomplete class type. +/// * The given type is a pointer type whose pointee type contains an +/// incomplete class type. +/// * The given type is a member pointer type whose class is an incomplete +/// class type. +/// * The given type is a member pointer type whoise pointee type contains an +/// incomplete class type. +/// is an indirect or direct pointer to an incomplete class type. +static bool ContainsIncompleteClassType(QualType Ty) { + if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) { + if (IsIncompleteClassType(RecordTy)) + return true; + } + + if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty)) + return ContainsIncompleteClassType(PointerTy->getPointeeType()); + + if (const MemberPointerType *MemberPointerTy = + dyn_cast<MemberPointerType>(Ty)) { + // Check if the class type is incomplete. + const RecordType *ClassType = cast<RecordType>(MemberPointerTy->getClass()); + if (IsIncompleteClassType(ClassType)) + return true; + + return ContainsIncompleteClassType(MemberPointerTy->getPointeeType()); + } + + return false; +} - llvm::Constant * - Buildclass_type_info(const CXXRecordDecl *RD, - llvm::GlobalVariable::LinkageTypes Linkage) { - std::vector<llvm::Constant *> info; - assert(info.empty() && "Info vector must be empty!"); +/// getTypeInfoLinkage - Return the linkage that the type info and type info +/// name constants should have for the given type. +static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) { + // Itanium C++ ABI 2.9.5p7: + // In addition, it and all of the intermediate abi::__pointer_type_info + // structs in the chain down to the abi::__class_type_info for the + // incomplete class type must be prevented from resolving to the + // corresponding type_info structs for the complete class type, possibly + // by making them local static objects. Finally, a dummy class RTTI is + // generated for the incomplete type that will not resolve to the final + // complete class RTTI (because the latter need not exist), possibly by + // making it a local static object. + if (ContainsIncompleteClassType(Ty)) + return llvm::GlobalValue::InternalLinkage; + + switch (Ty->getTypeClass()) { + default: + // FIXME: We need to add code to handle all types. + assert(false && "Unhandled type!"); + break; + + case Type::Pointer: { + const PointerType *PointerTy = cast<PointerType>(Ty); + + // If the pointee type has internal linkage, then the pointer type needs to + // have it as well. + if (getTypeInfoLinkage(PointerTy->getPointeeType()) == + llvm::GlobalVariable::InternalLinkage) + return llvm::GlobalVariable::InternalLinkage; - llvm::Constant *C; + return llvm::GlobalVariable::WeakODRLinkage; + } - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRTTI(CGM.getContext().getTagDeclType(RD), - OutName); - llvm::StringRef Name = OutName.str(); + case Type::Enum: { + const EnumType *EnumTy = cast<EnumType>(Ty); + const EnumDecl *ED = EnumTy->getDecl(); + + // If we're in an anonymous namespace, then we always want internal linkage. + if (ED->isInAnonymousNamespace() || !ED->hasLinkage()) + return llvm::GlobalVariable::InternalLinkage; + + return llvm::GlobalValue::WeakODRLinkage; + } - llvm::GlobalVariable *GV; - GV = CGM.getModule().getGlobalVariable(Name); - if (GV && !GV->isDeclaration()) - return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + case Type::Record: { + const RecordType *RecordTy = cast<RecordType>(Ty); + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); // If we're in an anonymous namespace, then we always want internal linkage. if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) - Linkage = llvm::GlobalVariable::InternalLinkage; + return llvm::GlobalVariable::InternalLinkage; - bool Hidden = CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden; - - bool simple = false; - if (RD->getNumBases() == 0) - C = BuildVtableRef("_ZTVN10__cxxabiv117__class_type_infoE"); - else if (SimpleInheritance(RD)) { - simple = true; - C = BuildVtableRef("_ZTVN10__cxxabiv120__si_class_type_infoE"); - } else - C = BuildVtableRef("_ZTVN10__cxxabiv121__vmi_class_type_infoE"); - info.push_back(C); - info.push_back(BuildName(CGM.getContext().getTagDeclType(RD), Hidden, - Linkage)); - - // If we have no bases, there are no more fields. - if (RD->getNumBases()) { - if (!simple) { - info.push_back(BuildFlags(CalculateFlags(RD))); - info.push_back(BuildBaseCount(RD->getNumBases())); - } - - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - info.push_back(CGM.GetAddrOfRTTI(Base)); - if (simple) - break; - int64_t offset; - if (!i->isVirtual()) - offset = Layout.getBaseClassOffset(Base)/8; - else - offset = CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, Base); - offset <<= 8; - // Now set the flags. - offset += i->isVirtual() ? 1 : 0;; - offset += i->getAccessSpecifier() == AS_public ? 2 : 0; - const llvm::Type *LongTy = - CGM.getTypes().ConvertType(CGM.getContext().LongTy); - C = llvm::ConstantInt::get(LongTy, offset); - info.push_back(C); - } + if (!RD->isDynamicClass()) + return llvm::GlobalValue::WeakODRLinkage; + + // Get the key function. + const CXXMethodDecl *KeyFunction = RD->getASTContext().getKeyFunction(RD); + if (!KeyFunction) { + // There is no key function, the RTTI descriptor is emitted with weak_odr + // linkage. + return llvm::GlobalValue::WeakODRLinkage; } - return finish(&info[0], info.size(), GV, Name, Hidden, Linkage); - } + // If the key function is defined, but inlined, then the RTTI descriptor is + // emitted with weak_odr linkage. + const FunctionDecl* KeyFunctionDefinition; + KeyFunction->getBody(KeyFunctionDefinition); - /// - BuildFlags - Build a __flags value for __pbase_type_info. - llvm::Constant *BuildInt(unsigned n) { - return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), n); + if (KeyFunctionDefinition->isInlined()) + return llvm::GlobalValue::WeakODRLinkage; + + // Otherwise, the RTTI descriptor is emitted with external linkage. + return llvm::GlobalValue::ExternalLinkage; } - bool DecideExtern(QualType Ty) { - // For this type, see if all components are never in an anonymous namespace. - if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()) - return (DecideExtern(MPT->getPointeeType()) - && DecideExtern(QualType(MPT->getClass(), 0))); - if (const PointerType *PT = Ty->getAs<PointerType>()) - return DecideExtern(PT->getPointeeType()); - if (const RecordType *RT = Ty->getAs<RecordType>()) - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) - return !RD->isInAnonymousNamespace() && RD->hasLinkage(); - return true; - } + case Type::Vector: + case Type::ExtVector: + case Type::Builtin: + return llvm::GlobalValue::WeakODRLinkage; - bool DecideHidden(QualType Ty) { - // For this type, see if all components are never hidden. - if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()) - return (DecideHidden(MPT->getPointeeType()) - && DecideHidden(QualType(MPT->getClass(), 0))); - if (const PointerType *PT = Ty->getAs<PointerType>()) - return DecideHidden(PT->getPointeeType()); - if (const RecordType *RT = Ty->getAs<RecordType>()) - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) - return CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden; - return false; - } + case Type::FunctionProto: { + const FunctionProtoType *FPT = cast<FunctionProtoType>(Ty); - llvm::Constant *BuildPointerType(QualType Ty) { - std::vector<llvm::Constant *> info; - assert(info.empty() && "Info vector must be empty!"); + // Check the return type. + if (getTypeInfoLinkage(FPT->getResultType()) == + llvm::GlobalValue::InternalLinkage) + return llvm::GlobalValue::InternalLinkage; + + // Check the parameter types. + for (unsigned i = 0; i != FPT->getNumArgs(); ++i) { + if (getTypeInfoLinkage(FPT->getArgType(i)) == + llvm::GlobalValue::InternalLinkage) + return llvm::GlobalValue::InternalLinkage; + } - llvm::Constant *C; + return llvm::GlobalValue::WeakODRLinkage; + } + + case Type::ConstantArray: + case Type::IncompleteArray: { + const ArrayType *AT = cast<ArrayType>(Ty); + + // Check the element type. + if (getTypeInfoLinkage(AT->getElementType()) == + llvm::GlobalValue::InternalLinkage) + return llvm::GlobalValue::InternalLinkage; + } - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); - llvm::StringRef Name = OutName.str(); + } - llvm::GlobalVariable *GV; - GV = CGM.getModule().getGlobalVariable(Name); - if (GV && !GV->isDeclaration()) - return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + return llvm::GlobalValue::WeakODRLinkage; +} - bool Extern = DecideExtern(Ty); - bool Hidden = DecideHidden(Ty); +// CanUseSingleInheritance - Return whether the given record decl has a "single, +// public, non-virtual base at offset zero (i.e. the derived class is dynamic +// iff the base is)", according to Itanium C++ ABI, 2.95p6b. +static bool CanUseSingleInheritance(const CXXRecordDecl *RD) { + // Check the number of bases. + if (RD->getNumBases() != 1) + return false; + + // Get the base. + CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(); + + // Check that the base is not virtual. + if (Base->isVirtual()) + return false; + + // Check that the base is public. + if (Base->getAccessSpecifier() != AS_public) + return false; + + // Check that the class is dynamic iff the base is. + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (!BaseDecl->isEmpty() && + BaseDecl->isDynamicClass() != RD->isDynamicClass()) + return false; + + return true; +} - const MemberPointerType *PtrMemTy = dyn_cast<MemberPointerType>(Ty); - QualType PointeeTy; - - if (PtrMemTy) - PointeeTy = PtrMemTy->getPointeeType(); - else - PointeeTy = Ty->getPointeeType(); - - if (PtrMemTy) - C = BuildVtableRef("_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"); - else - C = BuildVtableRef("_ZTVN10__cxxabiv119__pointer_type_infoE"); - - info.push_back(C); - info.push_back(BuildName(Ty, Hidden, Extern)); - Qualifiers Q = PointeeTy.getQualifiers(); - - PointeeTy = - CGM.getContext().getCanonicalType(PointeeTy).getUnqualifiedType(); - - unsigned Flags = 0; - if (Q.hasConst()) - Flags |= TI_Const; - if (Q.hasVolatile()) - Flags |= TI_Volatile; - if (Q.hasRestrict()) - Flags |= TI_Restrict; +void RTTIBuilder::BuildVtablePointer(const Type *Ty) { + const char *VtableName; + + switch (Ty->getTypeClass()) { + default: assert(0 && "Unhandled type!"); + + // GCC treats vector types as fundamental types. + case Type::Vector: + case Type::ExtVector: + // abi::__fundamental_type_info. + VtableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE"; + break; + + case Type::ConstantArray: + case Type::IncompleteArray: + // abi::__array_type_info. + VtableName = "_ZTVN10__cxxabiv117__array_type_infoE"; + break; + + case Type::FunctionNoProto: + case Type::FunctionProto: + // abi::__function_type_info. + VtableName = "_ZTVN10__cxxabiv120__function_type_infoE"; + break; + + case Type::Enum: + // abi::__enum_type_info. + VtableName = "_ZTVN10__cxxabiv116__enum_type_infoE"; + break; + + case Type::Record: { + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl()); - if (Ty->isIncompleteType()) - Flags |= TI_Incomplete; - - if (PtrMemTy && PtrMemTy->getClass()->isIncompleteType()) - Flags |= TI_ContainingClassIncomplete; + if (!RD->getNumBases()) { + // abi::__class_type_info. + VtableName = "_ZTVN10__cxxabiv117__class_type_infoE"; + } else if (CanUseSingleInheritance(RD)) { + // abi::__si_class_type_info. + VtableName = "_ZTVN10__cxxabiv120__si_class_type_infoE"; + } else { + // abi::__vmi_class_type_info. + VtableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; + } - info.push_back(BuildInt(Flags)); - info.push_back(BuildInt(0)); - info.push_back(BuildType(PointeeTy)); + break; + } - if (PtrMemTy) - info.push_back(BuildType(QualType(PtrMemTy->getClass(), 0))); + case Type::Pointer: + // abi::__pointer_type_info. + VtableName = "_ZTVN10__cxxabiv119__pointer_type_infoE"; + break; - // We always generate these as hidden, only the name isn't hidden. - return finish(&info[0], info.size(), GV, Name, /*Hidden=*/true, - GetLinkageFromExternFlag(Extern)); + case Type::MemberPointer: + // abi::__pointer_to_member_type_info. + VtableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"; + break; } - llvm::Constant *BuildSimpleType(QualType Ty, const char *vtbl) { - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); - llvm::StringRef Name = OutName.str(); + llvm::Constant *Vtable = + CGM.getModule().getOrInsertGlobal(VtableName, Int8PtrTy); + + const llvm::Type *PtrDiffTy = + CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); + + // The vtable address point is 2. + llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2); + Vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, &Two, 1); + Vtable = llvm::ConstantExpr::getBitCast(Vtable, Int8PtrTy); - llvm::GlobalVariable *GV; - GV = CGM.getModule().getGlobalVariable(Name); - if (GV && !GV->isDeclaration()) - return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + Fields.push_back(Vtable); +} - bool Extern = DecideExtern(Ty); - bool Hidden = DecideHidden(Ty); +llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) { + // We want to operate on the canonical type. + Ty = CGM.getContext().getCanonicalType(Ty); - llvm::Constant *Info[] = { - BuildVtableRef(vtbl), BuildName(Ty, Hidden, Extern) - }; + // Check if we've already emitted an RTTI descriptor for this type. + llvm::SmallString<256> OutName; + CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); + llvm::StringRef Name = OutName.str(); + + llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name); + if (OldGV && !OldGV->isDeclaration()) + return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy); + + // Check if there is already an external RTTI descriptor for this type. + if (ShouldUseExternalRTTIDescriptor(Ty)) + return GetAddrOfExternalRTTIDescriptor(Ty); + + llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty); + + // Add the vtable pointer. + BuildVtablePointer(cast<Type>(Ty)); + + // And the name. + Fields.push_back(BuildName(Ty, DecideHidden(Ty), Linkage)); + + switch (Ty->getTypeClass()) { + default: assert(false && "Unhandled type class!"); + case Type::Builtin: + assert(false && "Builtin type info must be in the standard library!"); + break; + + // GCC treats vector types as fundamental types. + case Type::Vector: + case Type::ExtVector: + // Itanium C++ ABI 2.9.5p4: + // abi::__fundamental_type_info adds no data members to std::type_info. + break; + + case Type::ConstantArray: + case Type::IncompleteArray: + // Itanium C++ ABI 2.9.5p5: + // abi::__array_type_info adds no data members to std::type_info. + break; + + case Type::FunctionNoProto: + case Type::FunctionProto: + // Itanium C++ ABI 2.9.5p5: + // abi::__function_type_info adds no data members to std::type_info. + break; + + case Type::Enum: + // Itanium C++ ABI 2.9.5p5: + // abi::__enum_type_info adds no data members to std::type_info. + break; + + case Type::Record: { + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl()); + if (!RD->getNumBases()) { + // We don't need to emit any fields. + break; + } - // We always generate these as hidden, only the name isn't hidden. - return finish(&Info[0], llvm::array_lengthof(Info), GV, Name, - /*Hidden=*/true, GetLinkageFromExternFlag(Extern)); + if (CanUseSingleInheritance(RD)) + BuildSIClassTypeInfo(RD); + else + BuildVMIClassTypeInfo(RD); + + break; + } + + case Type::Pointer: + BuildPointerTypeInfo(cast<PointerType>(Ty)); + break; + + case Type::MemberPointer: + BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty)); + break; } - /// BuildType - Builds the type info for the given type. - llvm::Constant *BuildType(QualType Ty) { - const clang::Type &Type - = *CGM.getContext().getCanonicalType(Ty).getTypePtr(); + llvm::Constant *Init = + llvm::ConstantStruct::get(VMContext, &Fields[0], Fields.size(), + /*Packed=*/false); - if (const RecordType *RT = Ty.getTypePtr()->getAs<RecordType>()) - if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl())) - return BuildClassTypeInfo(RD); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), Init->getType(), + /*Constant=*/true, Linkage, Init, Name); + + // If there's already an old global variable, replace it with the new one. + if (OldGV) { + GV->takeName(OldGV); + llvm::Constant *NewPtr = + llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); + OldGV->replaceAllUsesWith(NewPtr); + OldGV->eraseFromParent(); + } + + return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); +} - switch (Type.getTypeClass()) { - default: { - assert(0 && "typeid expression"); - return llvm::Constant::getNullValue(Int8PtrTy); - } +/// ComputeQualifierFlags - Compute the pointer type info flags from the +/// given qualifier. +static unsigned ComputeQualifierFlags(Qualifiers Quals) { + unsigned Flags = 0; - case Type::Builtin: { - // We expect all type_info objects for builtin types to be in the library. - return BuildTypeRef(Ty); - } + if (Quals.hasConst()) + Flags |= RTTIBuilder::PTI_Const; + if (Quals.hasVolatile()) + Flags |= RTTIBuilder::PTI_Volatile; + if (Quals.hasRestrict()) + Flags |= RTTIBuilder::PTI_Restrict; + + return Flags; +} - case Type::Pointer: { - QualType PTy = Ty->getPointeeType(); - Qualifiers Q = PTy.getQualifiers(); - Q.removeConst(); - // T* and const T* for all builtin types T are expected in the library. - if (isa<BuiltinType>(PTy) && Q.empty()) - return BuildTypeRef(Ty); +/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single +/// inheritance, according to the Itanium C++ ABI, 2.95p6b. +void RTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) { + // Itanium C++ ABI 2.9.5p6b: + // It adds to abi::__class_type_info a single member pointing to the + // type_info structure for the base type, + llvm::Constant *BaseTypeInfo = + RTTIBuilder(CGM).BuildTypeInfo(RD->bases_begin()->getType()); + Fields.push_back(BaseTypeInfo); +} + +/// SeenBases - Contains virtual and non-virtual bases seen when traversing +/// a class hierarchy. +struct SeenBases { + llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases; + llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases; +}; - return BuildPointerType(Ty); +/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in +/// abi::__vmi_class_type_info. +/// +static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base, + SeenBases &Bases) { + + unsigned Flags = 0; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + + if (Base->isVirtual()) { + if (Bases.VirtualBases.count(BaseDecl)) { + // If this virtual base has been seen before, then the class is diamond + // shaped. + Flags |= RTTIBuilder::VMI_DiamondShaped; + } else { + if (Bases.NonVirtualBases.count(BaseDecl)) + Flags |= RTTIBuilder::VMI_NonDiamondRepeat; + + // Mark the virtual base as seen. + Bases.VirtualBases.insert(BaseDecl); } - case Type::MemberPointer: - return BuildPointerType(Ty); - case Type::FunctionProto: - case Type::FunctionNoProto: - return BuildSimpleType(Ty, "_ZTVN10__cxxabiv120__function_type_infoE"); - case Type::ConstantArray: - case Type::IncompleteArray: - case Type::VariableArray: - case Type::Vector: - case Type::ExtVector: - return BuildSimpleType(Ty, "_ZTVN10__cxxabiv117__array_type_infoE"); - case Type::Enum: - return BuildSimpleType(Ty, "_ZTVN10__cxxabiv116__enum_type_infoE"); + } else { + if (Bases.NonVirtualBases.count(BaseDecl)) { + // If this non-virtual base has been seen before, then the class has non- + // diamond shaped repeated inheritance. + Flags |= RTTIBuilder::VMI_NonDiamondRepeat; + } else { + if (Bases.VirtualBases.count(BaseDecl)) + Flags |= RTTIBuilder::VMI_NonDiamondRepeat; + + // Mark the non-virtual base as seen. + Bases.NonVirtualBases.insert(BaseDecl); } } + + // Walk all bases. + for (CXXRecordDecl::base_class_const_iterator I = BaseDecl->bases_begin(), + E = BaseDecl->bases_end(); I != E; ++I) + Flags |= ComputeVMIClassTypeInfoFlags(I, Bases); - /// BuildClassTypeInfo - Builds the class type info (or a reference to it) - /// for the given record decl. - llvm::Constant *BuildClassTypeInfo(const CXXRecordDecl *RD) { - const CXXMethodDecl *KeyFunction = 0; + return Flags; +} - if (RD->isDynamicClass()) - KeyFunction = CGM.getContext().getKeyFunction(RD); +static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) { + unsigned Flags = 0; + SeenBases Bases; + + // Walk all bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) + Flags |= ComputeVMIClassTypeInfoFlags(I, Bases); + + return Flags; +} + +/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for +/// classes with bases that do not satisfy the abi::__si_class_type_info +/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c. +void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { + const llvm::Type *UnsignedIntLTy = + CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); + + // Itanium C++ ABI 2.9.5p6c: + // __flags is a word with flags describing details about the class + // structure, which may be referenced by using the __flags_masks + // enumeration. These flags refer to both direct and indirect bases. + unsigned Flags = ComputeVMIClassTypeInfoFlags(RD); + Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); + + // Itanium C++ ABI 2.9.5p6c: + // __base_count is a word with the number of direct proper base class + // descriptions that follow. + Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, RD->getNumBases())); + + if (!RD->getNumBases()) + return; + + const llvm::Type *LongLTy = + CGM.getTypes().ConvertType(CGM.getContext().LongTy); + + // Now add the base class descriptions. + + // Itanium C++ ABI 2.9.5p6c: + // __base_info[] is an array of base class descriptions -- one for every + // direct proper base. Each description is of the type: + // + // struct abi::__base_class_type_info { + // public: + // const __class_type_info *__base_type; + // long __offset_flags; + // + // enum __offset_flags_masks { + // __virtual_mask = 0x1, + // __public_mask = 0x2, + // __offset_shift = 8 + // }; + // }; + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXBaseSpecifier *Base = I; + + // The __base_type member points to the RTTI for the base type. + Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(Base->getType())); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + + int64_t OffsetFlags = 0; - if (KeyFunction) { - // If the key function is defined in this translation unit, then the RTTI - // related constants should also be emitted here, with external linkage. - if (KeyFunction->getBody()) - return Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage); - - // Otherwise, we just want a reference to the type info. - return Buildclass_type_infoRef(RD); - } + // All but the lower 8 bits of __offset_flags are a signed offset. + // For a non-virtual base, this is the offset in the object of the base + // subobject. For a virtual base, this is the offset in the virtual table of + // the virtual base offset for the virtual base referenced (negative). + if (Base->isVirtual()) + OffsetFlags = CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, BaseDecl); + else { + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + OffsetFlags = Layout.getBaseClassOffset(BaseDecl) / 8; + }; + + OffsetFlags <<= 8; - // If there is no key function (or if the record doesn't have any virtual - // member functions or virtual bases), emit the type info with weak_odr - // linkage. - return Buildclass_type_info(RD, llvm::GlobalValue::WeakODRLinkage); + // The low-order byte of __offset_flags contains flags, as given by the + // masks from the enumeration __offset_flags_masks. + if (Base->isVirtual()) + OffsetFlags |= BCTI_Virtual; + if (Base->getAccessSpecifier() == AS_public) + OffsetFlags |= BCTI_Public; + + Fields.push_back(llvm::ConstantInt::get(LongLTy, OffsetFlags)); } -}; } -llvm::Constant *CodeGenModule::GetAddrOfRTTI(const CXXRecordDecl *RD) { - if (!getContext().getLangOptions().RTTI) { - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); - return llvm::Constant::getNullValue(Int8PtrTy); - } +/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, +/// used for pointer types. +void RTTIBuilder::BuildPointerTypeInfo(const PointerType *Ty) { + QualType PointeeTy = Ty->getPointeeType(); - return RTTIBuilder(*this).BuildClassTypeInfo(RD); -} - -llvm::Constant *CodeGenModule::GetAddrOfRTTI(QualType Ty) { - if (!getContext().getLangOptions().RTTI) { - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); - return llvm::Constant::getNullValue(Int8PtrTy); - } + // Itanium C++ ABI 2.9.5p7: + // __flags is a flag word describing the cv-qualification and other + // attributes of the type pointed to + unsigned Flags = ComputeQualifierFlags(PointeeTy.getQualifiers()); + + // Itanium C++ ABI 2.9.5p7: + // When the abi::__pbase_type_info is for a direct or indirect pointer to an + // incomplete class type, the incomplete target type flag is set. + if (ContainsIncompleteClassType(PointeeTy)) + Flags |= PTI_Incomplete; + + const llvm::Type *UnsignedIntLTy = + CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); + Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); - return RTTIBuilder(*this).BuildType(Ty); + // Itanium C++ ABI 2.9.5p7: + // __pointee is a pointer to the std::type_info derivation for the + // unqualified type being pointed to. + llvm::Constant *PointeeTypeInfo = + RTTIBuilder(CGM).BuildTypeInfo(PointeeTy.getUnqualifiedType()); + Fields.push_back(PointeeTypeInfo); } -llvm::Constant *CodeGenModule::GenerateRTTIRef(const CXXRecordDecl *RD) { - RTTIBuilder b(*this); +/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info +/// struct, used for member pointer types. +void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) { + QualType PointeeTy = Ty->getPointeeType(); + + // Itanium C++ ABI 2.9.5p7: + // __flags is a flag word describing the cv-qualification and other + // attributes of the type pointed to. + unsigned Flags = ComputeQualifierFlags(PointeeTy.getQualifiers()); - return b.Buildclass_type_infoRef(RD); -} + const RecordType *ClassType = cast<RecordType>(Ty->getClass()); -llvm::Constant *CodeGenModule::GenerateRTTI(const CXXRecordDecl *RD) { - RTTIBuilder b(*this); + // Itanium C++ ABI 2.9.5p7: + // When the abi::__pbase_type_info is for a direct or indirect pointer to an + // incomplete class type, the incomplete target type flag is set. + if (ContainsIncompleteClassType(PointeeTy)) + Flags |= PTI_Incomplete; - return b.Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage); + if (IsIncompleteClassType(ClassType)) + Flags |= PTI_ContainingClassIncomplete; + + const llvm::Type *UnsignedIntLTy = + CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); + Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); + + // Itanium C++ ABI 2.9.5p7: + // __pointee is a pointer to the std::type_info derivation for the + // unqualified type being pointed to. + llvm::Constant *PointeeTypeInfo = + RTTIBuilder(CGM).BuildTypeInfo(PointeeTy.getUnqualifiedType()); + Fields.push_back(PointeeTypeInfo); + + // Itanium C++ ABI 2.9.5p9: + // __context is a pointer to an abi::__class_type_info corresponding to the + // class type containing the member pointed to + // (e.g., the "A" in "int A::*"). + Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0))); } -llvm::Constant *CodeGenModule::GenerateRTTI(QualType Ty) { - RTTIBuilder b(*this); - - return b.BuildType(Ty); +llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty) { + if (!getContext().getLangOptions().RTTI) { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + return llvm::Constant::getNullValue(Int8PtrTy); + } + + return RTTIBuilder(*this).BuildTypeInfo(Ty); } diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 31784ed..9f90ec5 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -216,12 +216,28 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { AppendPadding(Layout.getSize() / 8, Align); } +void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD, + const ASTRecordLayout &Layout) { + // Check if we need to add a vtable pointer. + if (RD->isDynamicClass() && !Layout.getPrimaryBase()) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(Types.getLLVMContext()); + + assert(NextFieldOffsetInBytes == 0 && + "Vtable pointer must come first!"); + AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo()); + } +} + bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { assert(!D->isUnion() && "Can't call LayoutFields on a union!"); assert(Alignment && "Did not set alignment!"); const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D); + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) + LayoutBases(RD, Layout); + unsigned FieldNo = 0; for (RecordDecl::field_iterator Field = D->field_begin(), diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h index 4ebf4e8..cf84053 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.h +++ b/lib/CodeGen/CGRecordLayoutBuilder.h @@ -23,6 +23,8 @@ namespace llvm { } namespace clang { + class ASTRecordLayout; + class CXXRecordDecl; class FieldDecl; class RecordDecl; @@ -90,6 +92,9 @@ class CGRecordLayoutBuilder { /// Returns false if the operation failed because the struct is not packed. bool LayoutFields(const RecordDecl *D); + /// LayoutBases - layout the bases and vtable pointer of a record decl. + void LayoutBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout); + /// LayoutField - layout a single field. Returns false if the operation failed /// because the current struct is not packed. bool LayoutField(const FieldDecl *D, uint64_t FieldOffset); diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp index 5cfc7ef..bed8439 100644 --- a/lib/CodeGen/CGTemporaries.cpp +++ b/lib/CodeGen/CGTemporaries.cpp @@ -17,6 +17,10 @@ using namespace CodeGen; void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr) { + assert((LiveTemporaries.empty() || + LiveTemporaries.back().ThisPtr != Ptr || + ConditionalBranchLevel) && + "Pushed the same temporary twice; AST is likely wrong"); llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor"); llvm::Value *CondPtr = 0; @@ -41,6 +45,33 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, CondPtr)); PushCleanupBlock(DtorBlock); + + if (Exceptions) { + const CXXLiveTemporaryInfo& Info = LiveTemporaries.back(); + llvm::BasicBlock *CondEnd = 0; + + EHCleanupBlock Cleanup(*this); + + // If this is a conditional temporary, we need to check the condition + // boolean and only call the destructor if it's true. + if (Info.CondPtr) { + llvm::BasicBlock *CondBlock = createBasicBlock("cond.dtor.call"); + CondEnd = createBasicBlock("cond.dtor.end"); + + llvm::Value *Cond = Builder.CreateLoad(Info.CondPtr); + Builder.CreateCondBr(Cond, CondBlock, CondEnd); + EmitBlock(CondBlock); + } + + EmitCXXDestructorCall(Info.Temporary->getDestructor(), + Dtor_Complete, Info.ThisPtr); + + if (CondEnd) { + // Reset the condition. to false. + Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), Info.CondPtr); + EmitBlock(CondEnd); + } + } } void CodeGenFunction::PopCXXTemporary() { @@ -92,12 +123,6 @@ CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, llvm::Value *AggLoc, bool IsAggLocVolatile, bool IsInitializer) { - // If we shouldn't destroy the temporaries, just emit the - // child expression. - if (!E->shouldDestroyTemporaries()) - return EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, - /*IgnoreResult=*/false, IsInitializer); - // Keep track of the current cleanup stack depth. size_t CleanupStackDepth = CleanupEntries.size(); (void) CleanupStackDepth; @@ -119,11 +144,6 @@ CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue( const CXXExprWithTemporaries *E) { - // If we shouldn't destroy the temporaries, just emit the - // child expression. - if (!E->shouldDestroyTemporaries()) - return EmitLValue(E->getSubExpr()); - // Keep track of the current cleanup stack depth. size_t CleanupStackDepth = CleanupEntries.size(); (void) CleanupStackDepth; diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 5283ed9..7930f71 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -202,8 +202,10 @@ public: Extern(!l->isInAnonymousNamespace()), LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - if (BuildVtable) - rtti = CGM.GetAddrOfRTTI(MostDerivedClass); + if (BuildVtable) { + QualType ClassType = CGM.getContext().getTagDeclType(MostDerivedClass); + rtti = CGM.GetAddrOfRTTIDescriptor(ClassType); + } } // getVtableComponents - Returns a reference to the vtable components. @@ -481,13 +483,13 @@ public: } - Index_t FinishGenerateVtable(const CXXRecordDecl *RD, - const ASTRecordLayout &Layout, - const CXXRecordDecl *PrimaryBase, - bool PrimaryBaseWasVirtual, - bool MorallyVirtual, int64_t Offset, - bool ForVirtualBase, int64_t CurrentVBaseOffset, - Path_t *Path) { + void FinishGenerateVtable(const CXXRecordDecl *RD, + const ASTRecordLayout &Layout, + const CXXRecordDecl *PrimaryBase, + bool PrimaryBaseWasVirtual, + bool MorallyVirtual, int64_t Offset, + bool ForVirtualBase, int64_t CurrentVBaseOffset, + Path_t *Path) { bool alloc = false; if (Path == 0) { alloc = true; @@ -535,7 +537,6 @@ public: if (alloc) { delete Path; } - return AddressPoint; } void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, @@ -600,19 +601,19 @@ public: } } - int64_t GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0, - bool MorallyVirtual = false, - bool ForVirtualBase = false, - int CurrentVBaseOffset = 0, - Path_t *Path = 0) { + void GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0, + bool MorallyVirtual = false, + bool ForVirtualBase = false, + int CurrentVBaseOffset = 0, + Path_t *Path = 0) { if (!RD->isDynamicClass()) - return 0; + return; // Construction vtable don't need parts that have no virtual bases and // aren't morally virtual. if ((LayoutClass != MostDerivedClass) && RD->getNumVBases() == 0 && !MorallyVirtual) - return 0; + return; const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); @@ -631,9 +632,9 @@ public: if (Path) OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset); - return FinishGenerateVtable(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, - MorallyVirtual, Offset, ForVirtualBase, - CurrentVBaseOffset, Path); + FinishGenerateVtable(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, + MorallyVirtual, Offset, ForVirtualBase, + CurrentVBaseOffset, Path); } void GenerateVtableForVBases(const CXXRecordDecl *RD, @@ -751,10 +752,10 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx, } const CXXRecordDecl *DerivedDecl = - cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl()); + cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl()); const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl()); + cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl()); return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl); } @@ -1156,22 +1157,13 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, CGM.getMangleContext().mangleCXXVtable(RD, OutName); llvm::StringRef Name = OutName.str(); - int64_t AddressPoint; - llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); - if (GV && CGM.AddressPoints[LayoutClass] && !GV->isDeclaration()) { - AddressPoint=(*(*(CGM.AddressPoints[LayoutClass]))[RD])[std::make_pair(RD, - Offset)]; - // FIXME: We can never have 0 address point. Do this for now so gepping - // retains the same structure. Later, we'll just assert. - if (AddressPoint == 0) - AddressPoint = 1; - } else { + if (GV == 0 || CGM.AddressPoints[LayoutClass] == 0 || GV->isDeclaration()) { VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition); D1(printf("vtable %s\n", RD->getNameAsCString())); // First comes the vtables for all the non-virtual bases... - AddressPoint = b.GenerateVtableForBase(RD, Offset); + b.GenerateVtableForBase(RD, Offset); // then the vtables for all the virtual bases. b.GenerateVtableForVBases(RD, Offset); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 28df9e4..f904f04 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -331,7 +331,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { // FIXME: For C++0x, we want to look for implicit *definitions* of // these special member functions, rather than implicit *declarations*. - if (CD->isCopyConstructor(getContext())) { + if (CD->isCopyConstructor()) { assert(!ClassDecl->hasUserDeclaredCopyConstructor() && "Cannot synthesize a non-implicit copy constructor"); SynthesizeCXXCopyConstructor(CD, GD.getCtorType(), Fn, Args); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 12e636c..273ddca 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -515,6 +515,12 @@ public: void InitializeVtablePtrs(const CXXRecordDecl *ClassDecl); + void InitializeVtablePtrsRecursive(const CXXRecordDecl *ClassDecl, + llvm::Constant *Vtable, + CodeGenModule::AddrSubMap_t& AddressPoints, + llvm::Value *ThisPtr, + uint64_t Offset); + void SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, CXXCtorType Type, llvm::Function *Fn, @@ -807,6 +813,8 @@ public: llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E); llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE); + void EmitCheck(llvm::Value *, unsigned Size); + //===--------------------------------------------------------------------===// // Declaration Emission //===--------------------------------------------------------------------===// @@ -921,6 +929,12 @@ public: /// LValue EmitLValue(const Expr *E); + /// EmitCheckedLValue - Same as EmitLValue but additionally we generate + /// checking code to guard against undefined behavior. This is only + /// suitable when we know that the address will be used to access the + /// object. + LValue EmitCheckedLValue(const Expr *E); + /// EmitLoadOfScalar - Load a scalar value from an address, taking /// care to appropriately convert from the memory representation to /// the LLVM value representation. @@ -1022,14 +1036,17 @@ public: /// used to set attributes on the call (noreturn, etc.). RValue EmitCall(const CGFunctionInfo &FnInfo, llvm::Value *Callee, + ReturnValueSlot ReturnValue, const CallArgList &Args, const Decl *TargetDecl = 0); - RValue EmitCall(llvm::Value *Callee, QualType FnType, + RValue EmitCall(QualType FnType, llvm::Value *Callee, + ReturnValueSlot ReturnValue, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd, const Decl *TargetDecl = 0); - RValue EmitCallExpr(const CallExpr *E); + RValue EmitCallExpr(const CallExpr *E, + ReturnValueSlot ReturnValue = ReturnValueSlot()); llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, const llvm::Type *Ty); @@ -1038,20 +1055,24 @@ public: RValue EmitCXXMemberCall(const CXXMethodDecl *MD, llvm::Value *Callee, + ReturnValueSlot ReturnValue, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); - RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E); - RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E); + RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E, + ReturnValueSlot ReturnValue); + RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, + ReturnValueSlot ReturnValue); RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, - const CXXMethodDecl *MD); + const CXXMethodDecl *MD, + ReturnValueSlot ReturnValue); RValue EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E); - RValue EmitBlockCallExpr(const CallExpr *E); + RValue EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue); /// EmitTargetBuiltinExpr - Emit the given builtin call. Returns 0 if the call /// is unhandled by the current target. diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 761f343..d497471 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -30,6 +30,7 @@ #include "llvm/CallingConv.h" #include "llvm/Module.h" #include "llvm/Intrinsics.h" +#include "llvm/LLVMContext.h" #include "llvm/Target/TargetData.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -546,7 +547,7 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { // static, static inline, always_inline, and extern inline functions can // always be deferred. Normal inline functions can be deferred in C99/C++. if (Linkage == GVA_Internal || Linkage == GVA_C99Inline || - Linkage == GVA_CXXInline) + Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) return true; return false; } @@ -1089,9 +1090,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, CI->replaceAllUsesWith(NewCall); // Copy any custom metadata attached with CI. - llvm::MetadataContext &TheMetadata = CI->getContext().getMetadata(); - TheMetadata.copyMD(CI, NewCall); - + if (llvm::MDNode *DbgNode = CI->getMetadata("dbg")) + NewCall->setMetadata("dbg", DbgNode); CI->eraseFromParent(); } } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index cc7ec9c..939c66c 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -212,24 +212,10 @@ public: llvm::Constant *GetAddrOfFunction(GlobalDecl GD, const llvm::Type *Ty = 0); - /// GetAddrOfRTTI - Get the address of the RTTI structure for the given type. - llvm::Constant *GetAddrOfRTTI(QualType Ty); + /// GetAddrOfRTTIDescriptor - Get the address of the RTTI descriptor + /// for the given type. + llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty); - /// GetAddrOfRTTI - Get the address of the RTTI structure for the given record - /// decl. - llvm::Constant *GetAddrOfRTTI(const CXXRecordDecl *RD); - - /// GenerateRTTI - Generate the rtti information for the given type. - llvm::Constant *GenerateRTTI(const CXXRecordDecl *RD); - - /// GenerateRTTIRef - Generate a reference to the rtti information for the - /// given type. - llvm::Constant *GenerateRTTIRef(const CXXRecordDecl *RD); - - /// GenerateRTTI - Generate the rtti information for the given - /// non-class type. - llvm::Constant *GenerateRTTI(QualType Ty); - llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkAdjustment &ThisAdjustment); llvm::Constant *GetAddrOfCovariantThunk(GlobalDecl GD, @@ -247,8 +233,8 @@ public: const CovariantThunkAdjustment &Adjustment); typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t; - typedef llvm::DenseMap<const CXXRecordDecl *, - llvm::DenseMap<CtorVtable_t, int64_t>*> AddrMap_t; + typedef llvm::DenseMap<CtorVtable_t, int64_t> AddrSubMap_t; + typedef llvm::DenseMap<const CXXRecordDecl *, AddrSubMap_t *> AddrMap_t; llvm::DenseMap<const CXXRecordDecl *, AddrMap_t*> AddressPoints; /// GetCXXBaseClassOffset - Returns the offset from a derived class to its diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index cd3575c..cd34e0c 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -199,7 +199,6 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { case Type::Builtin: { switch (cast<BuiltinType>(Ty).getKind()) { - default: assert(0 && "Unknown builtin type!"); case BuiltinType::Void: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: @@ -245,12 +244,16 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { case BuiltinType::UInt128: case BuiltinType::Int128: return llvm::IntegerType::get(getLLVMContext(), 128); + + case BuiltinType::Overload: + case BuiltinType::Dependent: + case BuiltinType::UndeducedAuto: + assert(0 && "Unexpected builtin type!"); + break; } + assert(0 && "Unknown builtin type!"); break; } - case Type::FixedWidthInt: - return llvm::IntegerType::get(getLLVMContext(), - cast<FixedWidthIntType>(T)->getWidth()); case Type::Complex: { const llvm::Type *EltTy = ConvertTypeRecursive(cast<ComplexType>(Ty).getElementType()); diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 90cc894..10fd1f5 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -125,8 +125,8 @@ private: void mangleTemplateArgs(const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); - void mangleTemplateArgumentList(const TemplateArgumentList &L); - void mangleTemplateArgument(const TemplateArgument &A); + void mangleTemplateArgs(const TemplateArgumentList &L); + void mangleTemplateArg(const TemplateArgument &A); void mangleTemplateParameter(unsigned Index); }; @@ -321,7 +321,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { mangleUnscopedTemplateName(TD); - mangleTemplateArgumentList(*TemplateArgs); + mangleTemplateArgs(*TemplateArgs); return; } @@ -480,10 +480,17 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { mangleType(Context.getASTContext().getCanonicalType(Name.getCXXNameType())); break; - case DeclarationName::CXXOperatorName: - mangleOperatorName(Name.getCXXOverloadedOperator(), - cast<FunctionDecl>(ND)->getNumParams()); + case DeclarationName::CXXOperatorName: { + unsigned Arity = cast<FunctionDecl>(ND)->getNumParams(); + + // If we have a C++ member function, we need to include the 'this' pointer. + // FIXME: This does not make sense for operators that are static, but their + // names stay the same regardless of the arity (operator new for instance). + if (isa<CXXMethodDecl>(ND)) + Arity++; + mangleOperatorName(Name.getCXXOverloadedOperator(), Arity); break; + } case DeclarationName::CXXLiteralOperatorName: // FIXME: This mangling is not yet official. @@ -517,7 +524,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND, const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { mangleTemplatePrefix(TD); - mangleTemplateArgumentList(*TemplateArgs); + mangleTemplateArgs(*TemplateArgs); } else { manglePrefix(DC); mangleUnqualifiedName(ND); @@ -573,7 +580,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) { const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) { mangleTemplatePrefix(TD); - mangleTemplateArgumentList(*TemplateArgs); + mangleTemplateArgs(*TemplateArgs); } else { manglePrefix(DC->getParent()); mangleUnqualifiedName(cast<NamedDecl>(DC)); @@ -611,16 +618,24 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { case OO_Array_Delete: Out << "da"; break; // ::= ps # + (unary) // ::= pl # + - case OO_Plus: Out << (Arity == 1? "ps" : "pl"); break; + case OO_Plus: + assert((Arity == 1 || Arity == 2) && "Invalid arity!"); + Out << (Arity == 1? "ps" : "pl"); break; // ::= ng # - (unary) // ::= mi # - - case OO_Minus: Out << (Arity == 1? "ng" : "mi"); break; + case OO_Minus: + assert((Arity == 1 || Arity == 2) && "Invalid arity!"); + Out << (Arity == 1? "ng" : "mi"); break; // ::= ad # & (unary) // ::= an # & - case OO_Amp: Out << (Arity == 1? "ad" : "an"); break; + case OO_Amp: + assert((Arity == 1 || Arity == 2) && "Invalid arity!"); + Out << (Arity == 1? "ad" : "an"); break; // ::= de # * (unary) // ::= ml # * - case OO_Star: Out << (Arity == 1? "de" : "ml"); break; + case OO_Star: + assert((Arity == 1 || Arity == 2) && "Invalid arity!"); + Out << (Arity == 1? "de" : "ml"); break; // ::= co # ~ case OO_Tilde: Out << "co"; break; // ::= dv # / @@ -975,11 +990,8 @@ void CXXNameMangler::mangleType(const ObjCInterfaceType *T) { } void CXXNameMangler::mangleType(const BlockPointerType *T) { - assert(false && "can't mangle block pointer types yet"); -} - -void CXXNameMangler::mangleType(const FixedWidthIntType *T) { - assert(false && "can't mangle arbitary-precision integer type yet"); + Out << "U13block_pointer"; + mangleType(T->getPointeeType()); } void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { @@ -1078,6 +1090,16 @@ void CXXNameMangler::mangleExpression(const Expr *E) { break; } + case Expr::CXXOperatorCallExprClass: { + const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E); + unsigned NumArgs = CE->getNumArgs(); + mangleOperatorName(CE->getOperator(), /*Arity=*/NumArgs); + // Mangle the arguments. + for (unsigned i = 0; i != NumArgs; ++i) + mangleExpression(CE->getArg(i)); + break; + } + case Expr::ParenExprClass: mangleExpression(cast<ParenExpr>(E)->getSubExpr()); break; @@ -1161,11 +1183,11 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { } } -void CXXNameMangler::mangleTemplateArgumentList(const TemplateArgumentList &L) { +void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &L) { // <template-args> ::= I <template-arg>+ E Out << "I"; for (unsigned i = 0, e = L.size(); i != e; ++i) - mangleTemplateArgument(L[i]); + mangleTemplateArg(L[i]); Out << "E"; } @@ -1174,11 +1196,11 @@ void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs, // <template-args> ::= I <template-arg>+ E Out << "I"; for (unsigned i = 0; i != NumTemplateArgs; ++i) - mangleTemplateArgument(TemplateArgs[i]); + mangleTemplateArg(TemplateArgs[i]); Out << "E"; } -void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) { +void CXXNameMangler::mangleTemplateArg(const TemplateArgument &A) { // <template-arg> ::= <type> # type or template // ::= X <expression> E # expression // ::= <expr-primary> # simple expressions @@ -1190,6 +1212,9 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) { case TemplateArgument::Type: mangleType(A.getAsType()); break; + case TemplateArgument::Template: + mangleName(A.getAsTemplate().getAsTemplateDecl()); + break; case TemplateArgument::Expression: Out << 'X'; mangleExpression(A.getAsExpr()); @@ -1558,6 +1583,7 @@ void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, void MangleContext::mangleCXXRTTI(QualType Ty, llvm::SmallVectorImpl<char> &Res) { // <special-name> ::= TI <type> # typeinfo structure + assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers"); CXXNameMangler Mangler(*this, Res); Mangler.getStream() << "_ZTI"; Mangler.mangleType(Ty); diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp index 017059d..1e1edc1 100644 --- a/lib/CodeGen/ModuleBuilder.cpp +++ b/lib/CodeGen/ModuleBuilder.cpp @@ -81,7 +81,7 @@ namespace { if (Builder) Builder->Release(); - }; + } virtual void CompleteTentativeDefinition(VarDecl *D) { if (Diags.hasErrorOccurred()) diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp index 7be1ead..863a297 100644 --- a/lib/CodeGen/TargetABIInfo.cpp +++ b/lib/CodeGen/TargetABIInfo.cpp @@ -805,6 +805,10 @@ void X86_64ABIInfo::classify(QualType Ty, if (Lo == Memory || Hi == Memory) break; } + + // If this record has no fields but isn't empty, classify as INTEGER. + if (RD->field_empty() && Size) + Current = Integer; } // Classify the fields one at a time, merging the results. diff --git a/lib/Driver/CC1Options.cpp b/lib/Driver/CC1Options.cpp index 13f84c0..0e98bb9 100644 --- a/lib/Driver/CC1Options.cpp +++ b/lib/Driver/CC1Options.cpp @@ -15,7 +15,7 @@ using namespace clang::driver; using namespace clang::driver::options; using namespace clang::driver::cc1options; -static OptTable::Info CC1InfoTable[] = { +static const OptTable::Info CC1InfoTable[] = { #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ HELPTEXT, METAVAR) \ { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \ diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index dbe7bd9..ab4bd49 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -711,6 +711,11 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { // Add a link action if necessary. if (!LinkerInputs.empty()) Actions.push_back(new LinkJobAction(LinkerInputs, types::TY_Image)); + + // If we are linking, claim any options which are obviously only used for + // compilation. + if (FinalPhase == phases::Link) + Args.ClaimAllArgs(options::OPT_CompileOnly_Group); } Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, @@ -734,6 +739,10 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, case phases::Precompile: return new PrecompileJobAction(Input, types::TY_PCH); case phases::Compile: { + bool HasO4 = false; + if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) + HasO4 = A->getOption().matches(options::OPT_O4); + if (Args.hasArg(options::OPT_fsyntax_only)) { return new CompileJobAction(Input, types::TY_Nothing); } else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) { @@ -741,8 +750,7 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, } else if (Args.hasArg(options::OPT_emit_ast)) { return new CompileJobAction(Input, types::TY_AST); } else if (Args.hasArg(options::OPT_emit_llvm) || - Args.hasArg(options::OPT_flto) || - Args.hasArg(options::OPT_O4)) { + Args.hasArg(options::OPT_flto) || HasO4) { types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LLVMAsm : types::TY_LLVMBC; return new CompileJobAction(Input, Output); @@ -768,10 +776,8 @@ void Driver::BuildJobs(Compilation &C) const { UsePipes = false; // -save-temps inhibits pipes. - if (SaveTemps && UsePipes) { + if (SaveTemps && UsePipes) Diag(clang::diag::warn_drv_pipe_ignored_with_save_temps); - UsePipes = true; - } Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o); @@ -906,14 +912,12 @@ void Driver::BuildJobsForAction(Compilation &C, // See if we should use an integrated preprocessor. We do so when we have // exactly one input, since this is the only use case we care about // (irrelevant since we don't support combine yet). - bool UseIntegratedCPP = false; const ActionList *Inputs = &A->getInputs(); if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin())) { if (!C.getArgs().hasArg(options::OPT_no_integrated_cpp) && !C.getArgs().hasArg(options::OPT_traditional_cpp) && !C.getArgs().hasArg(options::OPT_save_temps) && T.hasIntegratedCPP()) { - UseIntegratedCPP = true; Inputs = &(*Inputs)[0]->getInputs(); } } diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index abe9c81..9b6264a 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -22,6 +22,10 @@ ToolChain::ToolChain(const HostInfo &_Host, const llvm::Triple &_Triple) ToolChain::~ToolChain() { } +const Driver &ToolChain::getDriver() const { + return Host.getDriver(); +} + std::string ToolChain::GetFilePath(const Compilation &C, const char *Name) const { return Host.getDriver().GetFilePath(Name, *this); diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 420573d..cc3febf 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -88,7 +88,7 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, std::string Path; if (getArchName() == "x86_64") { - Path = getHost().getDriver().Dir; + Path = getDriver().Dir; Path += "/../lib/gcc/"; Path += ToolChainDir; Path += "/x86_64"; @@ -100,7 +100,7 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, getFilePaths().push_back(Path); } - Path = getHost().getDriver().Dir; + Path = getDriver().Dir; Path += "/../lib/gcc/"; Path += ToolChainDir; getFilePaths().push_back(Path); @@ -109,7 +109,7 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, Path += ToolChainDir; getFilePaths().push_back(Path); - Path = getHost().getDriver().Dir; + Path = getDriver().Dir; Path += "/../libexec/gcc/"; Path += ToolChainDir; getProgramPaths().push_back(Path); @@ -118,11 +118,11 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, Path += ToolChainDir; getProgramPaths().push_back(Path); - Path = getHost().getDriver().Dir; + Path = getDriver().Dir; Path += "/../libexec"; getProgramPaths().push_back(Path); - getProgramPaths().push_back(getHost().getDriver().Dir); + getProgramPaths().push_back(getDriver().Dir); } Darwin::~Darwin() { @@ -134,7 +134,7 @@ Darwin::~Darwin() { Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; - if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple())) + if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); @@ -238,12 +238,12 @@ DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple, // Add the relative libexec dir (for clang-cc). // // FIXME: We should sink clang-cc into libexec/clang/<version>/. - std::string Path = getHost().getDriver().Dir; + std::string Path = getDriver().Dir; Path += "/../libexec"; getProgramPaths().push_back(Path); // We expect 'as', 'ld', etc. to be adjacent to our install dir. - getProgramPaths().push_back(getHost().getDriver().Dir); + getProgramPaths().push_back(getDriver().Dir); } void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args, @@ -264,7 +264,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, // cares. This is useful in situations where someone wants to statically link // something like libstdc++, and needs its runtime support routines. if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) { - getHost().getDriver().Diag(clang::diag::err_drv_unsupported_opt) + getDriver().Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(Args); return; } @@ -284,7 +284,7 @@ void Darwin::getMacosxVersionMin(const ArgList &Args, if (!Driver::GetReleaseVersion(A->getValue(Args), Res[0], Res[1], Res[2], HadExtra) || HadExtra) { - const Driver &D = getHost().getDriver(); + const Driver &D = getDriver(); D.Diag(clang::diag::err_drv_invalid_version_number) << A->getAsString(Args); } @@ -295,7 +295,7 @@ void Darwin::getMacosxVersionMin(const ArgList &Args, DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, const char *BoundArch) const { DerivedArgList *DAL = new DerivedArgList(Args, false); - const OptTable &Opts = getHost().getDriver().getOpts(); + const OptTable &Opts = getDriver().getOpts(); // FIXME: We really want to get out of the tool chain level argument // translation business, as it makes the driver functionality much @@ -309,7 +309,7 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, Arg *iPhoneVersion = Args.getLastArgNoClaim(options::OPT_miphoneos_version_min_EQ); if (OSXVersion && iPhoneVersion) { - getHost().getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with) + getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with) << OSXVersion->getAsString(Args) << iPhoneVersion->getAsString(Args); } else if (!OSXVersion && !iPhoneVersion) { @@ -355,7 +355,7 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, // like -O4 are going to slip through. if (!XarchArg || Index > Prev + 1 || XarchArg->getOption().isDriverOption()) { - getHost().getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument) + getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument) << A->getAsString(Args); continue; } @@ -526,6 +526,12 @@ bool Darwin::IsUnwindTablesDefault() const { return getArchName() == "x86_64"; } +bool Darwin::UseDwarfDebugFlags() const { + if (const char *S = ::getenv("RC_DEBUG_OPTIONS")) + return S[0] != '\0'; + return false; +} + const char *Darwin::GetDefaultRelocationModel() const { return "pic"; } @@ -542,11 +548,11 @@ const char *Darwin::GetForcedPicModel() const { Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) : ToolChain(Host, Triple) { - std::string Path(getHost().getDriver().Dir); + std::string Path(getDriver().Dir); Path += "/../libexec"; getProgramPaths().push_back(Path); - getProgramPaths().push_back(getHost().getDriver().Dir); + getProgramPaths().push_back(getDriver().Dir); } Generic_GCC::~Generic_GCC() { @@ -559,7 +565,7 @@ Generic_GCC::~Generic_GCC() { Tool &Generic_GCC::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; - if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple())) + if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); @@ -620,13 +626,13 @@ DerivedArgList *Generic_GCC::TranslateArgs(InputArgList &Args, OpenBSD::OpenBSD(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { - getFilePaths().push_back(getHost().getDriver().Dir + "/../lib"); + getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); } Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; - if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple())) + if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); @@ -651,17 +657,17 @@ Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const { FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple, bool Lib32) : Generic_GCC(Host, Triple) { if (Lib32) { - getFilePaths().push_back(getHost().getDriver().Dir + "/../lib32"); + getFilePaths().push_back(getDriver().Dir + "/../lib32"); getFilePaths().push_back("/usr/lib32"); } else { - getFilePaths().push_back(getHost().getDriver().Dir + "/../lib"); + getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); } } Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; - if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple())) + if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); @@ -687,13 +693,13 @@ AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { // Path mangling to find libexec - std::string Path(getHost().getDriver().Dir); + std::string Path(getDriver().Dir); Path += "/../libexec"; getProgramPaths().push_back(Path); - getProgramPaths().push_back(getHost().getDriver().Dir); + getProgramPaths().push_back(getDriver().Dir); - getFilePaths().push_back(getHost().getDriver().Dir + "/../lib"); + getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); getFilePaths().push_back("/usr/sfw/lib"); getFilePaths().push_back("/opt/gcc4/lib"); @@ -703,7 +709,7 @@ AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple) Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; - if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple())) + if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); @@ -728,7 +734,7 @@ Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const { Linux::Linux(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { - getFilePaths().push_back(getHost().getDriver().Dir + "/../lib/clang/1.0/"); + getFilePaths().push_back(getDriver().Dir + "/../lib/clang/1.0/"); getFilePaths().push_back("/lib/"); getFilePaths().push_back("/usr/lib/"); @@ -755,20 +761,20 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { // Path mangling to find libexec - std::string Path(getHost().getDriver().Dir); + std::string Path(getDriver().Dir); Path += "/../libexec"; getProgramPaths().push_back(Path); - getProgramPaths().push_back(getHost().getDriver().Dir); + getProgramPaths().push_back(getDriver().Dir); - getFilePaths().push_back(getHost().getDriver().Dir + "/../lib"); + getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); getFilePaths().push_back("/usr/lib/gcc41"); } Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; - if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple())) + if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index fcd96f1..be36344 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -154,6 +154,8 @@ public: virtual const char *GetDefaultRelocationModel() const; virtual const char *GetForcedPicModel() const; + virtual bool UseDwarfDebugFlags() const; + /// } }; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 70597ab..8f0af21 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -230,7 +230,7 @@ static const char *getARMTargetCPU(const ArgList &Args) { if (MArch == "armv5e" || MArch == "armv5te") return "arm1026ejs"; if (MArch == "armv5tej") - return "arm926ejs"; + return "arm926ej-s"; if (MArch == "armv6" || MArch == "armv6k") return "arm1136jf-s"; if (MArch == "armv6j") @@ -338,7 +338,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - const Driver &D = getToolChain().getHost().getDriver(); + const Driver &D = getToolChain().getDriver(); // Select the ABI to use. // @@ -367,7 +367,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args, CmdArgs.push_back(ABIName); // Set the CPU based on -march= and -mcpu=. - CmdArgs.push_back("-mcpu"); + CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(getARMTargetCPU(Args)); // Select the float ABI as determined by -msoft-float, -mhard-float, and @@ -432,6 +432,53 @@ void Clang::AddARMTargetArgs(const ArgList &Args, CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("hard"); } + + // Set appropriate target features for floating point mode. + // + // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these + // yet (it uses the -mfloat-abi and -msoft-float options above), and it is + // stripped out by the ARM target. + + // Use software floating point operations? + if (FloatABI == "soft") { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("+soft-float"); + } + + // Use software floating point argument passing? + if (FloatABI != "hard") { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("+soft-float-abi"); + } + + // Honor -mfpu=. + // + // FIXME: Centralize feature selection, defaulting shouldn't be also in the + // frontend target. + if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) { + llvm::StringRef FPU = A->getValue(Args); + + // Set the target features based on the FPU. + if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") { + // Disable any default FPU support. + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("-vfp2"); + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("-vfp3"); + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("-neon"); + } else if (FPU == "vfp") { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("+vfp2"); + } else if (FPU == "vfp3") { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("+vfp3"); + } else if (FPU == "neon") { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("+neon"); + } else + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + } } void Clang::AddX86TargetArgs(const ArgList &Args, @@ -480,7 +527,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args, } if (CPUName) { - CmdArgs.push_back("-mcpu"); + CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(CPUName); } @@ -589,7 +636,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getHost().getDriver(); + const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); @@ -945,6 +992,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin)) CmdArgs.push_back("-fno-builtin"); + if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, + options::OPT_fno_assume_sane_operator_new)) + CmdArgs.push_back("-fno-assume-sane-operator-new"); + // -fblocks=0 is default. if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, getToolChain().IsBlocksDefault())) { @@ -1039,9 +1090,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers, options::OPT_fno_dollars_in_identifiers)) { if (A->getOption().matches(options::OPT_fdollars_in_identifiers)) - CmdArgs.push_back("-fdollars-in-identifiers=1"); + CmdArgs.push_back("-fdollars-in-identifiers"); else - CmdArgs.push_back("-fdollars-in-identifiers=0"); + CmdArgs.push_back("-fno-dollars-in-identifiers"); } // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for @@ -1105,6 +1156,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "clang")); + + // Optionally embed the -cc1 level arguments into the debug info, for build + // analysis. + if (getToolChain().UseDwarfDebugFlags()) { + llvm::SmallString<256> Flags; + Flags += Exec; + for (unsigned i = 0, e = CmdArgs.size(); i != e; ++i) { + Flags += " "; + Flags += CmdArgs[i]; + } + CmdArgs.push_back("-dwarf-debug-flags"); + CmdArgs.push_back(Args.MakeArgString(Flags.str())); + } + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); // Explicitly warn that these options are unsupported, even though @@ -1135,7 +1200,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getHost().getDriver(); + const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; for (ArgList::const_iterator @@ -1155,7 +1220,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, // If using a driver driver, force the arch. const std::string &Arch = getToolChain().getArchName(); - if (getToolChain().getHost().useDriverDriver()) { + if (getToolChain().getTriple().getOS() == llvm::Triple::Darwin) { CmdArgs.push_back("-arch"); // FIXME: Remove these special cases. @@ -1223,8 +1288,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, II.getInputArg().render(Args, CmdArgs); } - const char *GCCName = - getToolChain().getHost().getDriver().CCCGenericGCCName.c_str(); + const char *GCCName = getToolChain().getDriver().CCCGenericGCCName.c_str(); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, GCCName)); Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); @@ -1304,7 +1368,7 @@ darwin::CC1::getDependencyFileName(const ArgList &Args, void darwin::CC1::AddCC1Args(const ArgList &Args, ArgStringList &CmdArgs) const { - const Driver &D = getToolChain().getHost().getDriver(); + const Driver &D = getToolChain().getDriver(); CheckCodeGenerationOptions(D, Args); @@ -1333,7 +1397,7 @@ void darwin::CC1::AddCC1Args(const ArgList &Args, void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, const InputInfoList &Inputs, const ArgStringList &OutputArgs) const { - const Driver &D = getToolChain().getHost().getDriver(); + const Driver &D = getToolChain().getDriver(); // Derived from cc1_options spec. if (Args.hasArg(options::OPT_fast) || @@ -1481,7 +1545,7 @@ void darwin::CC1::AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, const InputInfoList &Inputs) const { - const Driver &D = getToolChain().getHost().getDriver(); + const Driver &D = getToolChain().getDriver(); CheckPreprocessingOptions(D, Args); @@ -1624,7 +1688,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getHost().getDriver(); + const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; assert(Inputs.size() == 1 && "Unexpected number of inputs!"); @@ -1873,7 +1937,7 @@ void darwin::DarwinTool::AddDarwinSubArch(const ArgList &Args, void darwin::Link::AddLinkArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - const Driver &D = getToolChain().getHost().getDriver(); + const Driver &D = getToolChain().getDriver(); // Derived from the "link" spec. Args.AddAllArgs(CmdArgs, options::OPT_static); @@ -2159,7 +2223,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, !Args.hasArg(options::OPT_nodefaultlibs)) { // FIXME: g++ is more complicated here, it tries to put -lstdc++ // before -lm, for example. - if (getToolChain().getHost().getDriver().CCCIsCXX) + if (getToolChain().getDriver().CCCIsCXX) CmdArgs.push_back("-lstdc++"); // link_ssp spec is empty. @@ -2273,7 +2337,7 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getHost().getDriver(); + const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; if ((!Args.hasArg(options::OPT_nostdlib)) && @@ -2404,7 +2468,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getHost().getDriver(); + const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; if ((!Args.hasArg(options::OPT_nostdlib)) && @@ -2539,7 +2603,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getHost().getDriver(); + const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; if (Args.hasArg(options::OPT_static)) { @@ -2691,7 +2755,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getHost().getDriver(); + const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; if (Args.hasArg(options::OPT_static)) { diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index 6729da8..8f7da52 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -137,7 +137,7 @@ namespace darwin { } public: - DarwinTool(const char *Name, const ToolChain &TC) : Tool(Name, TC) {}; + DarwinTool(const char *Name, const ToolChain &TC) : Tool(Name, TC) {} }; class VISIBILITY_HIDDEN CC1 : public DarwinTool { diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index a74bbc2..6824d8f 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -14,10 +14,10 @@ #include "clang/Frontend/AnalysisConsumer.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ParentMap.h" #include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/LocalCheckers.h" #include "clang/Analysis/ManagerRegistry.h" @@ -228,6 +228,19 @@ void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) { break; } + case Decl::CXXMethod: { + CXXMethodDecl *CXXMD = cast<CXXMethodDecl>(D); + + if (Opts.AnalyzeSpecificFunction.size() > 0 && + Opts.AnalyzeSpecificFunction != CXXMD->getName()) + return; + + Stmt *Body = CXXMD->getBody(); + if (Body) + HandleCode(CXXMD, Body, FunctionActions); + break; + } + default: break; } @@ -240,7 +253,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { if (!TranslationUnitActions.empty()) { // Find the entry function definition (if any). FunctionDecl *FD = 0; - + // Must specify an entry function. if (!Opts.AnalyzeSpecificFunction.empty()) { for (DeclContext::decl_iterator I=TU->decls_begin(), E=TU->decls_end(); I != E; ++I) { @@ -253,9 +266,11 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { } } - for (Actions::iterator I = TranslationUnitActions.begin(), - E = TranslationUnitActions.end(); I != E; ++I) - (*I)(*this, *Mgr, FD); + if (FD) { + for (Actions::iterator I = TranslationUnitActions.begin(), + E = TranslationUnitActions.end(); I != E; ++I) + (*I)(*this, *Mgr, FD); + } } if (!ObjCImplementationActions.empty()) { @@ -358,7 +373,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, if (C.Opts.EnableExperimentalChecks) RegisterExperimentalChecks(Eng); - Eng.setTransferFunctions(tf); + Eng.setTransferFunctionsAndCheckers(tf); // Set the graph auditor. llvm::OwningPtr<ExplodedNode::Auditor> Auditor; @@ -475,8 +490,36 @@ static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr, static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr, Decl *D) { + // FIXME: This is largely copy of ActionGRExprEngine. Needs cleanup. + // Display progress. + C.DisplayFunction(D); + + GRExprEngine Eng(mgr); + + if (C.Opts.EnableExperimentalInternalChecks) + RegisterExperimentalInternalChecks(Eng); - ActionGRExprEngine(C, mgr, D, CreateCallInliner(mgr.getASTContext())); + RegisterAppleChecks(Eng, *D); + + if (C.Opts.EnableExperimentalChecks) + RegisterExperimentalChecks(Eng); + + // Make a fake transfer function. The GRTransferFunc interface will be + // removed. + Eng.setTransferFunctionsAndCheckers(new GRTransferFuncs()); + + // Register call inliner as the last checker. + RegisterCallInliner(Eng); + + // Execute the worklist algorithm. + Eng.ExecuteWorkList(mgr.getStackFrame(D)); + + // Visualize the exploded graph. + if (mgr.shouldVisualizeGraphviz()) + Eng.ViewGraph(mgr.shouldTrimGraph()); + + // Display warnings. + Eng.getBugReporter().FlushReports(); } //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 03123d3..58aaa43 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -31,7 +31,6 @@ add_clang_library(clangFrontend PlistDiagnostics.cpp PrintParserCallbacks.cpp PrintPreprocessedOutput.cpp - RewriteBlocks.cpp RewriteMacros.cpp RewriteObjC.cpp RewriteTest.cpp diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 7a3388f..63f66fa 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -122,6 +122,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-disable-llvm-optzns"); if (Opts.DisableRedZone) Res.push_back("-disable-red-zone"); + if (!Opts.DwarfDebugFlags.empty()) { + Res.push_back("-dwarf-debug-flags"); + Res.push_back(Opts.DwarfDebugFlags); + } if (!Opts.MergeAllConstants) Res.push_back("-fno-merge-all-constants"); if (Opts.NoCommon) @@ -276,7 +280,6 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::ParseSyntaxOnly: return "-fsyntax-only"; case frontend::PrintDeclContext: return "-print-decl-contexts"; case frontend::PrintPreprocessedInput: return "-E"; - case frontend::RewriteBlocks: return "-rewrite-blocks"; case frontend::RewriteMacros: return "-rewrite-macros"; case frontend::RewriteObjC: return "-rewrite-objc"; case frontend::RewriteTest: return "-rewrite-test"; @@ -440,7 +443,7 @@ static void LangOptsToArgs(const LangOptions &Opts, if (Opts.DollarIdents) Res.push_back("-fdollars-in-identifiers"); if (Opts.Microsoft) - Res.push_back("-fms-extensions=1"); + Res.push_back("-fms-extensions"); if (Opts.ObjCNonFragileABI) Res.push_back("-fobjc-nonfragile-abi"); // NoInline is implicit. @@ -466,6 +469,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-ffreestanding"); if (Opts.NoBuiltin) Res.push_back("-fno-builtin"); + if (!Opts.AssumeSaneOperatorNew) + Res.push_back("-fno-assume-sane-operator-new"); if (Opts.ThreadsafeStatics) llvm::llvm_report_error("FIXME: Not yet implemented!"); if (Opts.POSIXThreads) @@ -593,7 +598,7 @@ static void TargetOptsToArgs(const TargetOptions &Opts, Res.push_back("-triple"); Res.push_back(Opts.Triple); if (!Opts.CPU.empty()) { - Res.push_back("-mcpu"); + Res.push_back("-target-cpu"); Res.push_back(Opts.CPU); } if (!Opts.ABI.empty()) { @@ -747,6 +752,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.DebugInfo = Args.hasArg(OPT_g); Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); + Opts.DwarfDebugFlags = getLastArgValue(Args, OPT_dwarf_debug_flags); Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); @@ -851,8 +857,6 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { Opts.ProgramAction = frontend::PrintDeclContext; break; case OPT_E: Opts.ProgramAction = frontend::PrintPreprocessedInput; break; - case OPT_rewrite_blocks: - Opts.ProgramAction = frontend::RewriteBlocks; break; case OPT_rewrite_macros: Opts.ProgramAction = frontend::RewriteMacros; break; case OPT_rewrite_objc: @@ -1124,10 +1128,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_trigraphs)) Opts.Trigraphs = 1; - Opts.DollarIdents = !Opts.AsmPreprocessor; - if (Args.hasArg(OPT_fdollars_in_identifiers)) - Opts.DollarIdents = 1; - + Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers, + OPT_fno_dollars_in_identifiers, + !Opts.AsmPreprocessor); Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); Opts.Microsoft = Args.hasArg(OPT_fms_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); @@ -1140,6 +1143,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); Opts.Freestanding = Args.hasArg(OPT_ffreestanding); Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; + Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); Opts.AccessControl = Args.hasArg(OPT_faccess_control); Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); @@ -1245,7 +1249,7 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { using namespace cc1options; Opts.ABI = getLastArgValue(Args, OPT_target_abi); - Opts.CPU = getLastArgValue(Args, OPT_mcpu); + Opts.CPU = getLastArgValue(Args, OPT_target_cpu); Opts.Triple = getLastArgValue(Args, OPT_triple); Opts.Features = getAllArgValues(Args, OPT_target_feature); diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index e3c313a..4c647fda 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -154,11 +154,6 @@ ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, return 0; } -ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { - return CreateBlockRewriter(InFile, CI.getDiagnostics(), CI.getLangOpts()); -} - ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { return new ASTConsumer(); diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index b4ea257..9555125 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -478,6 +478,14 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl "i686-apple-darwin8", "", "", triple); break; case llvm::Triple::Linux: + // Exherbo (2009-10-26) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "x86_64-pc-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "i686-pc-linux-gnu", "", "", triple); + // Debian sid + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "x86_64-linux-gnu", "32", "", triple); // Ubuntu 7.10 - Gutsy Gibbon AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3", "i486-linux-gnu", "", "", triple); @@ -543,11 +551,6 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", "i686-pc-linux-gnu", "", "", triple); - // Exherbo (2009-10-26) - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", - "x86_64-pc-linux-gnu", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", - "i686-pc-linux-gnu", "", "", triple); break; case llvm::Triple::FreeBSD: // DragonFly diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 48ef2ac..d8fd791 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1761,11 +1761,6 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getQualifiedType(Base, Quals); } - case pch::TYPE_FIXED_WIDTH_INT: { - assert(Record.size() == 2 && "Incorrect encoding of fixed-width int type"); - return Context->getFixedWidthIntType(Record[0], Record[1]); - } - case pch::TYPE_COMPLEX: { assert(Record.size() == 1 && "Incorrect encoding of complex type"); QualType ElemType = GetType(Record[0]); @@ -1854,17 +1849,18 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { } case pch::TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 1) { + if (Record.size() != 2) { Error("incorrect encoding of no-proto function type"); return QualType(); } QualType ResultType = GetType(Record[0]); - return Context->getFunctionNoProtoType(ResultType); + return Context->getFunctionNoProtoType(ResultType, Record[1]); } case pch::TYPE_FUNCTION_PROTO: { QualType ResultType = GetType(Record[0]); - unsigned Idx = 1; + bool NoReturn = Record[1]; + unsigned Idx = 2; unsigned NumParams = Record[Idx++]; llvm::SmallVector<QualType, 16> ParamTypes; for (unsigned I = 0; I != NumParams; ++I) @@ -1880,7 +1876,7 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams, isVariadic, Quals, hasExceptionSpec, hasAnyExceptionSpec, NumExceptions, - Exceptions.data()); + Exceptions.data(), NoReturn); } case pch::TYPE_UNRESOLVED_USING: @@ -1986,9 +1982,6 @@ void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } -void TypeLocReader::VisitFixedWidthIntTypeLoc(FixedWidthIntTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index f28e61e..ba82d26 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -858,7 +858,9 @@ unsigned PCHStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { VisitExpr(E); E->setConstructor(cast<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++]))); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); E->setElidable(Record[Idx++]); + E->setRequiresZeroInitialization(Record[Idx++]); for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I])); return E->getNumArgs(); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 681c1ff..2875f09 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -69,12 +69,6 @@ void PCHTypeWriter::VisitBuiltinType(const BuiltinType *T) { assert(false && "Built-in types are never serialized"); } -void PCHTypeWriter::VisitFixedWidthIntType(const FixedWidthIntType *T) { - Record.push_back(T->getWidth()); - Record.push_back(T->isSigned()); - Code = pch::TYPE_FIXED_WIDTH_INT; -} - void PCHTypeWriter::VisitComplexType(const ComplexType *T) { Writer.AddTypeRef(T->getElementType(), Record); Code = pch::TYPE_COMPLEX; @@ -144,6 +138,7 @@ void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) { void PCHTypeWriter::VisitFunctionType(const FunctionType *T) { Writer.AddTypeRef(T->getResultType(), Record); + Record.push_back(T->getNoReturnAttr()); } void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { @@ -282,9 +277,6 @@ void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } -void TypeLocWriter::VisitFixedWidthIntTypeLoc(FixedWidthIntTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } @@ -558,7 +550,6 @@ void PCHWriter::WriteBlockInfoBlock() { // Decls and Types block. BLOCK(DECLTYPES_BLOCK); RECORD(TYPE_EXT_QUAL); - RECORD(TYPE_FIXED_WIDTH_INT); RECORD(TYPE_COMPLEX); RECORD(TYPE_POINTER); RECORD(TYPE_BLOCK_POINTER); @@ -1645,10 +1636,10 @@ public: II->hasMacroDefinition() && !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro(); Bits = (uint32_t)II->getObjCOrBuiltinID(); - Bits = (Bits << 1) | hasMacroDefinition; - Bits = (Bits << 1) | II->isExtensionToken(); - Bits = (Bits << 1) | II->isPoisoned(); - Bits = (Bits << 1) | II->isCPlusPlusOperatorKeyword(); + Bits = (Bits << 1) | unsigned(hasMacroDefinition); + Bits = (Bits << 1) | unsigned(II->isExtensionToken()); + Bits = (Bits << 1) | unsigned(II->isPoisoned()); + Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword()); clang::io::Emit16(Out, Bits); if (hasMacroDefinition) diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 22f7ad6..abf4eaa 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -785,7 +785,9 @@ void PCHStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) { VisitExpr(E); Writer.AddDeclRef(E->getConstructor(), Record); + Writer.AddSourceLocation(E->getLocation(), Record); Record.push_back(E->isElidable()); + Record.push_back(E->requiresZeroInitialization()); Record.push_back(E->getNumArgs()); for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) Writer.WriteSubStmt(E->getArg(I)); diff --git a/lib/Frontend/RewriteBlocks.cpp b/lib/Frontend/RewriteBlocks.cpp deleted file mode 100644 index 25e7fc4..0000000 --- a/lib/Frontend/RewriteBlocks.cpp +++ /dev/null @@ -1,1152 +0,0 @@ -//===--- RewriteBlocks.cpp ----------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Hacks and fun related to the closure rewriter. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/ASTConsumers.h" -#include "clang/Rewrite/Rewriter.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/LangOptions.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/SmallPtrSet.h" - -using namespace clang; -using llvm::utostr; - -namespace { - -class RewriteBlocks : public ASTConsumer { - Rewriter Rewrite; - Diagnostic &Diags; - const LangOptions &LangOpts; - unsigned RewriteFailedDiag; - - ASTContext *Context; - SourceManager *SM; - FileID MainFileID; - const char *MainFileStart, *MainFileEnd; - - // Block expressions. - llvm::SmallVector<BlockExpr *, 32> Blocks; - llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs; - llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs; - - // Block related declarations. - llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls; - llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls; - llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls; - - llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs; - - // The function/method we are rewriting. - FunctionDecl *CurFunctionDef; - ObjCMethodDecl *CurMethodDef; - - bool IsHeader; - - std::string Preamble; -public: - RewriteBlocks(std::string inFile, Diagnostic &D, - const LangOptions &LOpts); - ~RewriteBlocks() { - // Get the buffer corresponding to MainFileID. - // If we haven't changed it, then we are done. - if (const RewriteBuffer *RewriteBuf = - Rewrite.getRewriteBufferFor(MainFileID)) { - std::string S(RewriteBuf->begin(), RewriteBuf->end()); - printf("%s\n", S.c_str()); - } else { - printf("No changes\n"); - } - } - - void Initialize(ASTContext &context); - - void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen); - void ReplaceText(SourceLocation Start, unsigned OrigLength, - const char *NewStr, unsigned NewLength); - - // Top Level Driver code. - virtual void HandleTopLevelDecl(DeclGroupRef D) { - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) - HandleTopLevelSingleDecl(*I); - } - void HandleTopLevelSingleDecl(Decl *D); - void HandleDeclInMainFile(Decl *D); - - // Top level - Stmt *RewriteFunctionBody(Stmt *S); - void InsertBlockLiteralsWithinFunction(FunctionDecl *FD); - void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD); - - // Block specific rewrite rules. - std::string SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD=0); - - void RewriteBlockCall(CallExpr *Exp); - void RewriteBlockPointerDecl(NamedDecl *VD); - void RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD); - void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); - - std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - const char *funcName, std::string Tag); - std::string SynthesizeBlockFunc(BlockExpr *CE, int i, - const char *funcName, std::string Tag); - std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - bool hasCopyDisposeHelpers); - std::string SynthesizeBlockCall(CallExpr *Exp); - void SynthesizeBlockLiterals(SourceLocation FunLocStart, - const char *FunName); - - void CollectBlockDeclRefInfo(BlockExpr *Exp); - void GetBlockCallExprs(Stmt *S); - void GetBlockDeclRefExprs(Stmt *S); - - // We avoid calling Type::isBlockPointerType(), since it operates on the - // canonical type. We only care if the top-level type is a closure pointer. - bool isBlockPointerType(QualType T) { return isa<BlockPointerType>(T); } - - // FIXME: This predicate seems like it would be useful to add to ASTContext. - bool isObjCType(QualType T) { - if (!LangOpts.ObjC1 && !LangOpts.ObjC2) - return false; - - QualType OCT = Context->getCanonicalType(T).getUnqualifiedType(); - - if (OCT == Context->getCanonicalType(Context->getObjCIdType()) || - OCT == Context->getCanonicalType(Context->getObjCClassType())) - return true; - - if (const PointerType *PT = OCT->getAs<PointerType>()) { - if (isa<ObjCInterfaceType>(PT->getPointeeType()) || - PT->getPointeeType()->isObjCQualifiedIdType()) - return true; - } - return false; - } - // ObjC rewrite methods. - void RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl); - void RewriteCategoryDecl(ObjCCategoryDecl *CatDecl); - void RewriteProtocolDecl(ObjCProtocolDecl *PDecl); - void RewriteMethodDecl(ObjCMethodDecl *MDecl); - - void RewriteFunctionProtoType(QualType funcType, NamedDecl *D); - void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND); - void RewriteCastExpr(CastExpr *CE); - - bool PointerTypeTakesAnyBlockArguments(QualType QT); - void GetExtentOfArgList(const char *Name, const char *&LParen, const char *&RParen); -}; - -} - -static bool IsHeaderFile(const std::string &Filename) { - std::string::size_type DotPos = Filename.rfind('.'); - - if (DotPos == std::string::npos) { - // no file extension - return false; - } - - std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end()); - // C header: .h - // C++ header: .hh or .H; - return Ext == "h" || Ext == "hh" || Ext == "H"; -} - -RewriteBlocks::RewriteBlocks(std::string inFile, - Diagnostic &D, const LangOptions &LOpts) : - Diags(D), LangOpts(LOpts) { - IsHeader = IsHeaderFile(inFile); - CurFunctionDef = 0; - CurMethodDef = 0; - RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning, - "rewriting failed"); -} - -ASTConsumer *clang::CreateBlockRewriter(const std::string& InFile, - Diagnostic &Diags, - const LangOptions &LangOpts) { - return new RewriteBlocks(InFile, Diags, LangOpts); -} - -void RewriteBlocks::Initialize(ASTContext &context) { - Context = &context; - SM = &Context->getSourceManager(); - - // Get the ID and start/end of the main file. - MainFileID = SM->getMainFileID(); - const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID); - MainFileStart = MainBuf->getBufferStart(); - MainFileEnd = MainBuf->getBufferEnd(); - - Rewrite.setSourceMgr(Context->getSourceManager(), LangOpts); - - if (IsHeader) - Preamble = "#pragma once\n"; - Preamble += "#ifndef BLOCK_IMPL\n"; - Preamble += "#define BLOCK_IMPL\n"; - Preamble += "struct __block_impl {\n"; - Preamble += " void *isa;\n"; - Preamble += " int Flags;\n"; - Preamble += " int Size;\n"; - Preamble += " void *FuncPtr;\n"; - Preamble += "};\n"; - Preamble += "enum {\n"; - Preamble += " BLOCK_HAS_COPY_DISPOSE = (1<<25),\n"; - Preamble += " BLOCK_IS_GLOBAL = (1<<28)\n"; - Preamble += "};\n"; - if (LangOpts.Microsoft) - Preamble += "#define __OBJC_RW_EXTERN extern \"C\" __declspec(dllimport)\n"; - else - Preamble += "#define __OBJC_RW_EXTERN extern\n"; - Preamble += "// Runtime copy/destroy helper functions\n"; - Preamble += "__OBJC_RW_EXTERN void _Block_copy_assign(void *, void *);\n"; - Preamble += "__OBJC_RW_EXTERN void _Block_byref_assign_copy(void *, void *);\n"; - Preamble += "__OBJC_RW_EXTERN void _Block_destroy(void *);\n"; - Preamble += "__OBJC_RW_EXTERN void _Block_byref_release(void *);\n"; - Preamble += "__OBJC_RW_EXTERN void *_NSConcreteGlobalBlock;\n"; - Preamble += "__OBJC_RW_EXTERN void *_NSConcreteStackBlock;\n"; - Preamble += "#endif\n"; - - InsertText(SM->getLocForStartOfFile(MainFileID), - Preamble.c_str(), Preamble.size()); -} - -void RewriteBlocks::InsertText(SourceLocation Loc, const char *StrData, - unsigned StrLen) { - if (!Rewrite.InsertText(Loc, StrData, StrLen)) - return; - Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); -} - -void RewriteBlocks::ReplaceText(SourceLocation Start, unsigned OrigLength, - const char *NewStr, unsigned NewLength) { - if (!Rewrite.ReplaceText(Start, OrigLength, - llvm::StringRef(NewStr, NewLength))) - return; - Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag); -} - -void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) { - bool haveBlockPtrs = false; - for (ObjCMethodDecl::param_iterator I = Method->param_begin(), - E = Method->param_end(); I != E; ++I) - if (isBlockPointerType((*I)->getType())) - haveBlockPtrs = true; - - if (!haveBlockPtrs) - return; - - // Do a fuzzy rewrite. - // We have 1 or more arguments that have closure pointers. - SourceLocation Loc = Method->getLocStart(); - SourceLocation LocEnd = Method->getLocEnd(); - const char *startBuf = SM->getCharacterData(Loc); - const char *endBuf = SM->getCharacterData(LocEnd); - - const char *methodPtr = startBuf; - std::string Tag = "struct __block_impl *"; - - while (*methodPtr++ && (methodPtr != endBuf)) { - switch (*methodPtr) { - case ':': - methodPtr++; - if (*methodPtr == '(') { - const char *scanType = ++methodPtr; - bool foundBlockPointer = false; - unsigned parenCount = 1; - - while (parenCount) { - switch (*scanType) { - case '(': - parenCount++; - break; - case ')': - parenCount--; - break; - case '^': - foundBlockPointer = true; - break; - } - scanType++; - } - if (foundBlockPointer) { - // advance the location to startArgList. - Loc = Loc.getFileLocWithOffset(methodPtr-startBuf); - assert((Loc.isValid()) && "Invalid Loc"); - ReplaceText(Loc, scanType-methodPtr-1, Tag.c_str(), Tag.size()); - - // Advance startBuf. Since the underlying buffer has changed, - // it's very important to advance startBuf (so we can correctly - // compute a relative Loc the next time around). - startBuf = methodPtr; - } - // Advance the method ptr to the end of the type. - methodPtr = scanType; - } - break; - } - } - return; -} - -void RewriteBlocks::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { - for (ObjCInterfaceDecl::instmeth_iterator - I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDecl(*I); - for (ObjCInterfaceDecl::classmeth_iterator - I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDecl(*I); -} - -void RewriteBlocks::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { - for (ObjCCategoryDecl::instmeth_iterator - I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDecl(*I); - for (ObjCCategoryDecl::classmeth_iterator - I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDecl(*I); -} - -void RewriteBlocks::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { - for (ObjCProtocolDecl::instmeth_iterator - I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDecl(*I); - for (ObjCProtocolDecl::classmeth_iterator - I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDecl(*I); -} - -//===----------------------------------------------------------------------===// -// Top Level Driver Code -//===----------------------------------------------------------------------===// - -void RewriteBlocks::HandleTopLevelSingleDecl(Decl *D) { - // Two cases: either the decl could be in the main file, or it could be in a - // #included file. If the former, rewrite it now. If the later, check to see - // if we rewrote the #include/#import. - SourceLocation Loc = D->getLocation(); - Loc = SM->getInstantiationLoc(Loc); - - // If this is for a builtin, ignore it. - if (Loc.isInvalid()) return; - - if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) - RewriteInterfaceDecl(MD); - else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) - RewriteCategoryDecl(CD); - else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) - RewriteProtocolDecl(PD); - - // If we have a decl in the main file, see if we should rewrite it. - if (SM->isFromMainFile(Loc)) - HandleDeclInMainFile(D); - return; -} - -std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i, - const char *funcName, - std::string Tag) { - const FunctionType *AFT = CE->getFunctionType(); - QualType RT = AFT->getResultType(); - std::string StructRef = "struct " + Tag; - std::string S = "static " + RT.getAsString() + " __" + - funcName + "_" + "block_func_" + utostr(i); - - BlockDecl *BD = CE->getBlockDecl(); - - if (isa<FunctionNoProtoType>(AFT)) { - S += "()"; - } else if (BD->param_empty()) { - S += "(" + StructRef + " *__cself)"; - } else { - const FunctionProtoType *FT = cast<FunctionProtoType>(AFT); - assert(FT && "SynthesizeBlockFunc: No function proto"); - S += '('; - // first add the implicit argument. - S += StructRef + " *__cself, "; - std::string ParamStr; - for (BlockDecl::param_iterator AI = BD->param_begin(), - E = BD->param_end(); AI != E; ++AI) { - if (AI != BD->param_begin()) S += ", "; - ParamStr = (*AI)->getNameAsString(); - (*AI)->getType().getAsStringInternal(ParamStr, Context->PrintingPolicy); - S += ParamStr; - } - if (FT->isVariadic()) { - if (!BD->param_empty()) S += ", "; - S += "..."; - } - S += ')'; - } - S += " {\n"; - - // Create local declarations to avoid rewriting all closure decl ref exprs. - // First, emit a declaration for all "by ref" decls. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - S += " "; - std::string Name = (*I)->getNameAsString(); - Context->getPointerType((*I)->getType()).getAsStringInternal(Name, - Context->PrintingPolicy); - S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; - } - // Next, emit a declaration for all "by copy" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - S += " "; - std::string Name = (*I)->getNameAsString(); - // Handle nested closure invocation. For example: - // - // void (^myImportedClosure)(void); - // myImportedClosure = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherClosure)(void); - // anotherClosure = ^(void) { - // myImportedClosure(); // import and invoke the closure - // }; - // - if (isBlockPointerType((*I)->getType())) - S += "struct __block_impl *"; - else - (*I)->getType().getAsStringInternal(Name, Context->PrintingPolicy); - S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; - } - std::string RewrittenStr = RewrittenBlockExprs[CE]; - const char *cstr = RewrittenStr.c_str(); - while (*cstr++ != '{') ; - S += cstr; - S += "\n"; - return S; -} - -std::string RewriteBlocks::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - const char *funcName, - std::string Tag) { - std::string StructRef = "struct " + Tag; - std::string S = "static void __"; - - S += funcName; - S += "_block_copy_" + utostr(i); - S += "(" + StructRef; - S += "*dst, " + StructRef; - S += "*src) {"; - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), - E = ImportedBlockDecls.end(); I != E; ++I) { - S += "_Block_copy_assign(&dst->"; - S += (*I)->getNameAsString(); - S += ", src->"; - S += (*I)->getNameAsString(); - S += ");}"; - } - S += "\nstatic void __"; - S += funcName; - S += "_block_dispose_" + utostr(i); - S += "(" + StructRef; - S += "*src) {"; - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), - E = ImportedBlockDecls.end(); I != E; ++I) { - S += "_Block_destroy(src->"; - S += (*I)->getNameAsString(); - S += ");"; - } - S += "}\n"; - return S; -} - -std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - bool hasCopyDisposeHelpers) { - std::string S = "struct " + Tag; - std::string Constructor = " " + Tag; - - S += " {\n struct __block_impl impl;\n"; - - if (hasCopyDisposeHelpers) - S += " void *copy;\n void *dispose;\n"; - - Constructor += "(void *fp"; - - if (hasCopyDisposeHelpers) - Constructor += ", void *copyHelp, void *disposeHelp"; - - if (BlockDeclRefs.size()) { - // Output all "by copy" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - S += " "; - std::string FieldName = (*I)->getNameAsString(); - std::string ArgName = "_" + FieldName; - // Handle nested closure invocation. For example: - // - // void (^myImportedBlock)(void); - // myImportedBlock = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherBlock)(void); - // anotherBlock = ^(void) { - // myImportedBlock(); // import and invoke the closure - // }; - // - if (isBlockPointerType((*I)->getType())) { - S += "struct __block_impl *"; - Constructor += ", void *" + ArgName; - } else { - (*I)->getType().getAsStringInternal(FieldName, Context->PrintingPolicy); - (*I)->getType().getAsStringInternal(ArgName, Context->PrintingPolicy); - Constructor += ", " + ArgName; - } - S += FieldName + ";\n"; - } - // Output all "by ref" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - S += " "; - std::string FieldName = (*I)->getNameAsString(); - std::string ArgName = "_" + FieldName; - // Handle nested closure invocation. For example: - // - // void (^myImportedBlock)(void); - // myImportedBlock = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherBlock)(void); - // anotherBlock = ^(void) { - // myImportedBlock(); // import and invoke the closure - // }; - // - if (isBlockPointerType((*I)->getType())) { - S += "struct __block_impl *"; - Constructor += ", void *" + ArgName; - } else { - Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName, - Context->PrintingPolicy); - Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName, - Context->PrintingPolicy); - Constructor += ", " + ArgName; - } - S += FieldName + "; // by ref\n"; - } - // Finish writing the constructor. - // FIXME: handle NSConcreteGlobalBlock. - Constructor += ", int flags=0) {\n"; - Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof("; - Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - - if (hasCopyDisposeHelpers) - Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n"; - - // Initialize all "by copy" arguments. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - Constructor += " "; - if (isBlockPointerType((*I)->getType())) - Constructor += Name + " = (struct __block_impl *)_"; - else - Constructor += Name + " = _"; - Constructor += Name + ";\n"; - } - // Initialize all "by ref" arguments. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - Constructor += " "; - if (isBlockPointerType((*I)->getType())) - Constructor += Name + " = (struct __block_impl *)_"; - else - Constructor += Name + " = _"; - Constructor += Name + ";\n"; - } - } else { - // Finish writing the constructor. - // FIXME: handle NSConcreteGlobalBlock. - Constructor += ", int flags=0) {\n"; - Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof("; - Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - if (hasCopyDisposeHelpers) - Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n"; - } - Constructor += " "; - Constructor += "}\n"; - S += Constructor; - S += "};\n"; - return S; -} - -void RewriteBlocks::SynthesizeBlockLiterals(SourceLocation FunLocStart, - const char *FunName) { - // Insert closures that were part of the function. - for (unsigned i = 0; i < Blocks.size(); i++) { - - CollectBlockDeclRefInfo(Blocks[i]); - - std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); - - std::string CI = SynthesizeBlockImpl(Blocks[i], Tag, - ImportedBlockDecls.size() > 0); - - InsertText(FunLocStart, CI.c_str(), CI.size()); - - std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag); - - InsertText(FunLocStart, CF.c_str(), CF.size()); - - if (ImportedBlockDecls.size()) { - std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag); - InsertText(FunLocStart, HF.c_str(), HF.size()); - } - - BlockDeclRefs.clear(); - BlockByRefDecls.clear(); - BlockByCopyDecls.clear(); - BlockCallExprs.clear(); - ImportedBlockDecls.clear(); - } - Blocks.clear(); - RewrittenBlockExprs.clear(); -} - -void RewriteBlocks::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { - SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); - const char *FuncName = FD->getNameAsCString(); - - SynthesizeBlockLiterals(FunLocStart, FuncName); -} - -void RewriteBlocks::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) { - SourceLocation FunLocStart = MD->getLocStart(); - std::string FuncName = MD->getSelector().getAsString(); - // Convert colons to underscores. - std::string::size_type loc = 0; - while ((loc = FuncName.find(":", loc)) != std::string::npos) - FuncName.replace(loc, 1, "_"); - - SynthesizeBlockLiterals(FunLocStart, FuncName.c_str()); -} - -void RewriteBlocks::GetBlockDeclRefExprs(Stmt *S) { - for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); - CI != E; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) - GetBlockDeclRefExprs(CBE->getBody()); - else - GetBlockDeclRefExprs(*CI); - } - // Handle specific things. - if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) - // FIXME: Handle enums. - if (!isa<FunctionDecl>(CDRE->getDecl())) - BlockDeclRefs.push_back(CDRE); - return; -} - -void RewriteBlocks::GetBlockCallExprs(Stmt *S) { - for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); - CI != E; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) - GetBlockCallExprs(CBE->getBody()); - else - GetBlockCallExprs(*CI); - } - - if (CallExpr *CE = dyn_cast<CallExpr>(S)) { - if (CE->getCallee()->getType()->isBlockPointerType()) { - BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE; - } - } - return; -} - -std::string RewriteBlocks::SynthesizeBlockCall(CallExpr *Exp) { - // Navigate to relevant type information. - const char *closureName = 0; - const BlockPointerType *CPT = 0; - - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) { - closureName = DRE->getDecl()->getNameAsCString(); - CPT = DRE->getType()->getAs<BlockPointerType>(); - } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) { - closureName = CDRE->getDecl()->getNameAsCString(); - CPT = CDRE->getType()->getAs<BlockPointerType>(); - } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) { - closureName = MExpr->getMemberDecl()->getNameAsCString(); - CPT = MExpr->getType()->getAs<BlockPointerType>(); - } else { - assert(1 && "RewriteBlockClass: Bad type"); - } - assert(CPT && "RewriteBlockClass: Bad type"); - const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>(); - assert(FT && "RewriteBlockClass: Bad type"); - const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT); - // FTP will be null for closures that don't take arguments. - - // Build a closure call - start with a paren expr to enforce precedence. - std::string BlockCall = "("; - - // Synthesize the cast. - BlockCall += "(" + Exp->getType().getAsString() + "(*)"; - BlockCall += "(struct __block_impl *"; - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I && (I != E); ++I) - BlockCall += ", " + (*I).getAsString(); - } - BlockCall += "))"; // close the argument list and paren expression. - - // Invoke the closure. We need to cast it since the declaration type is - // bogus (it's a function pointer type) - BlockCall += "((struct __block_impl *)"; - std::string closureExprBufStr; - llvm::raw_string_ostream closureExprBuf(closureExprBufStr); - Exp->getCallee()->printPretty(closureExprBuf, *Context, 0, - PrintingPolicy(LangOpts)); - BlockCall += closureExprBuf.str(); - BlockCall += ")->FuncPtr)"; - - // Add the arguments. - BlockCall += "((struct __block_impl *)"; - BlockCall += closureExprBuf.str(); - for (CallExpr::arg_iterator I = Exp->arg_begin(), - E = Exp->arg_end(); I != E; ++I) { - std::string syncExprBufS; - llvm::raw_string_ostream Buf(syncExprBufS); - (*I)->printPretty(Buf, *Context, 0, PrintingPolicy(LangOpts)); - BlockCall += ", " + Buf.str(); - } - return BlockCall; -} - -void RewriteBlocks::RewriteBlockCall(CallExpr *Exp) { - std::string BlockCall = SynthesizeBlockCall(Exp); - - const char *startBuf = SM->getCharacterData(Exp->getLocStart()); - const char *endBuf = SM->getCharacterData(Exp->getLocEnd()); - - ReplaceText(Exp->getLocStart(), endBuf-startBuf, - BlockCall.c_str(), BlockCall.size()); -} - -void RewriteBlocks::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) { - // FIXME: Add more elaborate code generation required by the ABI. - InsertText(BDRE->getLocStart(), "*", 1); -} - -void RewriteBlocks::RewriteCastExpr(CastExpr *CE) { - SourceLocation LocStart = CE->getLocStart(); - SourceLocation LocEnd = CE->getLocEnd(); - - if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd)) - return; - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - - // advance the location to startArgList. - const char *argPtr = startBuf; - - while (*argPtr++ && (argPtr < endBuf)) { - switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf); - ReplaceText(LocStart, 1, "*", 1); - break; - } - } - return; -} - -void RewriteBlocks::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { - SourceLocation DeclLoc = FD->getLocation(); - unsigned parenCount = 0; - - // We have 1 or more arguments that have closure pointers. - const char *startBuf = SM->getCharacterData(DeclLoc); - const char *startArgList = strchr(startBuf, '('); - - assert((*startArgList == '(') && "Rewriter fuzzy parser confused"); - - parenCount++; - // advance the location to startArgList. - DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf); - assert((DeclLoc.isValid()) && "Invalid DeclLoc"); - - const char *argPtr = startArgList; - - while (*argPtr++ && parenCount) { - switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList); - ReplaceText(DeclLoc, 1, "*", 1); - break; - case '(': - parenCount++; - break; - case ')': - parenCount--; - break; - } - } - return; -} - -bool RewriteBlocks::PointerTypeTakesAnyBlockArguments(QualType QT) { - const FunctionProtoType *FTP; - const PointerType *PT = QT->getAs<PointerType>(); - if (PT) { - FTP = PT->getPointeeType()->getAs<FunctionProtoType>(); - } else { - const BlockPointerType *BPT = QT->getAs<BlockPointerType>(); - assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); - FTP = BPT->getPointeeType()->getAs<FunctionProtoType>(); - } - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I != E; ++I) - if (isBlockPointerType(*I)) - return true; - } - return false; -} - -void RewriteBlocks::GetExtentOfArgList(const char *Name, - const char *&LParen, const char *&RParen) { - const char *argPtr = strchr(Name, '('); - assert((*argPtr == '(') && "Rewriter fuzzy parser confused"); - - LParen = argPtr; // output the start. - argPtr++; // skip past the left paren. - unsigned parenCount = 1; - - while (*argPtr && parenCount) { - switch (*argPtr) { - case '(': parenCount++; break; - case ')': parenCount--; break; - default: break; - } - if (parenCount) argPtr++; - } - assert((*argPtr == ')') && "Rewriter fuzzy parser confused"); - RParen = argPtr; // output the end -} - -void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { - RewriteBlockPointerFunctionArgs(FD); - return; - } - // Handle Variables and Typedefs. - SourceLocation DeclLoc = ND->getLocation(); - QualType DeclT; - if (VarDecl *VD = dyn_cast<VarDecl>(ND)) - DeclT = VD->getType(); - else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND)) - DeclT = TDD->getUnderlyingType(); - else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND)) - DeclT = FD->getType(); - else - assert(0 && "RewriteBlockPointerDecl(): Decl type not yet handled"); - - const char *startBuf = SM->getCharacterData(DeclLoc); - const char *endBuf = startBuf; - // scan backward (from the decl location) for the end of the previous decl. - while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart) - startBuf--; - - // *startBuf != '^' if we are dealing with a pointer to function that - // may take block argument types (which will be handled below). - if (*startBuf == '^') { - // Replace the '^' with '*', computing a negative offset. - DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf); - ReplaceText(DeclLoc, 1, "*", 1); - } - if (PointerTypeTakesAnyBlockArguments(DeclT)) { - // Replace the '^' with '*' for arguments. - DeclLoc = ND->getLocation(); - startBuf = SM->getCharacterData(DeclLoc); - const char *argListBegin, *argListEnd; - GetExtentOfArgList(startBuf, argListBegin, argListEnd); - while (argListBegin < argListEnd) { - if (*argListBegin == '^') { - SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf); - ReplaceText(CaretLoc, 1, "*", 1); - } - argListBegin++; - } - } - return; -} - -void RewriteBlocks::CollectBlockDeclRefInfo(BlockExpr *Exp) { - // Add initializers for any closure decl refs. - GetBlockDeclRefExprs(Exp->getBody()); - if (BlockDeclRefs.size()) { - // Unique all "by copy" declarations. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (!BlockDeclRefs[i]->isByRef()) - BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl()); - // Unique all "by ref" declarations. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->isByRef()) { - BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl()); - } - // Find any imported blocks...they will need special attention. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (isBlockPointerType(BlockDeclRefs[i]->getType())) { - GetBlockCallExprs(Blocks[i]); - ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl()); - } - } -} - -std::string RewriteBlocks::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD) { - Blocks.push_back(Exp); - - CollectBlockDeclRefInfo(Exp); - std::string FuncName; - - if (CurFunctionDef) - FuncName = std::string(CurFunctionDef->getNameAsString()); - else if (CurMethodDef) { - FuncName = CurMethodDef->getSelector().getAsString(); - // Convert colons to underscores. - std::string::size_type loc = 0; - while ((loc = FuncName.find(":", loc)) != std::string::npos) - FuncName.replace(loc, 1, "_"); - } else if (VD) - FuncName = std::string(VD->getNameAsString()); - - std::string BlockNumber = utostr(Blocks.size()-1); - - std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber; - std::string Func = "__" + FuncName + "_block_func_" + BlockNumber; - - std::string FunkTypeStr; - - // Get a pointer to the function type so we can cast appropriately. - Context->getPointerType(QualType(Exp->getFunctionType(),0)) - .getAsStringInternal(FunkTypeStr, Context->PrintingPolicy); - - // Rewrite the closure block with a compound literal. The first cast is - // to prevent warnings from the C compiler. - std::string Init = "(" + FunkTypeStr; - - Init += ")&" + Tag; - - // Initialize the block function. - Init += "((void*)" + Func; - - if (ImportedBlockDecls.size()) { - std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber; - Init += ",(void*)" + Buf; - Buf = "__" + FuncName + "_block_dispose_" + BlockNumber; - Init += ",(void*)" + Buf; - } - // Add initializers for any closure decl refs. - if (BlockDeclRefs.size()) { - // Output all "by copy" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - Init += ","; - if (isObjCType((*I)->getType())) { - Init += "[["; - Init += (*I)->getNameAsString(); - Init += " retain] autorelease]"; - } else if (isBlockPointerType((*I)->getType())) { - Init += "(void *)"; - Init += (*I)->getNameAsString(); - } else { - Init += (*I)->getNameAsString(); - } - } - // Output all "by ref" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - Init += ",&"; - Init += (*I)->getNameAsString(); - } - } - Init += ")"; - BlockDeclRefs.clear(); - BlockByRefDecls.clear(); - BlockByCopyDecls.clear(); - ImportedBlockDecls.clear(); - - return Init; -} - -//===----------------------------------------------------------------------===// -// Function Body / Expression rewriting -//===----------------------------------------------------------------------===// - -Stmt *RewriteBlocks::RewriteFunctionBody(Stmt *S) { - // Start by rewriting all children. - for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); - CI != E; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) { - RewriteFunctionBody(CBE->getBody()); - - // We've just rewritten the block body in place. - // Now we snarf the rewritten text and stash it away for later use. - std::string S = Rewrite.getRewritenText(CBE->getSourceRange()); - RewrittenBlockExprs[CBE] = S; - std::string Init = SynthesizeBlockInitExpr(CBE); - // Do the rewrite, using S.size() which contains the rewritten size. - ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size()); - } else { - RewriteFunctionBody(*CI); - } - } - // Handle specific things. - if (CallExpr *CE = dyn_cast<CallExpr>(S)) { - if (CE->getCallee()->getType()->isBlockPointerType()) - RewriteBlockCall(CE); - } - if (CastExpr *CE = dyn_cast<CastExpr>(S)) { - RewriteCastExpr(CE); - } - if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) { - for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); - DI != DE; ++DI) { - - Decl *SD = *DI; - if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) { - if (isBlockPointerType(ND->getType())) - RewriteBlockPointerDecl(ND); - else if (ND->getType()->isFunctionPointerType()) - CheckFunctionPointerDecl(ND->getType(), ND); - } - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { - if (isBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - } - } - } - // Handle specific things. - if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { - if (BDRE->isByRef()) - RewriteBlockDeclRefExpr(BDRE); - } - // Return this stmt unmodified. - return S; -} - -void RewriteBlocks::RewriteFunctionProtoType(QualType funcType, NamedDecl *D) { - if (FunctionProtoType *fproto = dyn_cast<FunctionProtoType>(funcType)) { - for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(), - E = fproto->arg_type_end(); I && (I != E); ++I) - if (isBlockPointerType(*I)) { - // All the args are checked/rewritten. Don't call twice! - RewriteBlockPointerDecl(D); - break; - } - } -} - -void RewriteBlocks::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) { - const PointerType *PT = funcType->getAs<PointerType>(); - if (PT && PointerTypeTakesAnyBlockArguments(funcType)) - RewriteFunctionProtoType(PT->getPointeeType(), ND); -} - -/// HandleDeclInMainFile - This is called for each top-level decl defined in the -/// main file of the input. -void RewriteBlocks::HandleDeclInMainFile(Decl *D) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // Since function prototypes don't have ParmDecl's, we check the function - // prototype. This enables us to rewrite function declarations and - // definitions using the same code. - RewriteFunctionProtoType(FD->getType(), FD); - - // FIXME: Handle CXXTryStmt - if (CompoundStmt *Body = FD->getCompoundBody()) { - CurFunctionDef = FD; - FD->setBody(cast_or_null<CompoundStmt>(RewriteFunctionBody(Body))); - // This synthesizes and inserts the block "impl" struct, invoke function, - // and any copy/dispose helper functions. - InsertBlockLiteralsWithinFunction(FD); - CurFunctionDef = 0; - } - return; - } - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - RewriteMethodDecl(MD); - if (Stmt *Body = MD->getBody()) { - CurMethodDef = MD; - RewriteFunctionBody(Body); - InsertBlockLiteralsWithinMethod(MD); - CurMethodDef = 0; - } - } - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (isBlockPointerType(VD->getType())) { - RewriteBlockPointerDecl(VD); - if (VD->getInit()) { - if (BlockExpr *CBE = dyn_cast<BlockExpr>(VD->getInit())) { - RewriteFunctionBody(CBE->getBody()); - - // We've just rewritten the block body in place. - // Now we snarf the rewritten text and stash it away for later use. - std::string S = Rewrite.getRewritenText(CBE->getSourceRange()); - RewrittenBlockExprs[CBE] = S; - std::string Init = SynthesizeBlockInitExpr(CBE, VD); - // Do the rewrite, using S.size() which contains the rewritten size. - ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size()); - SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), - VD->getNameAsCString()); - } else if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) { - RewriteCastExpr(CE); - } - } - } else if (VD->getType()->isFunctionPointerType()) { - CheckFunctionPointerDecl(VD->getType(), VD); - if (VD->getInit()) { - if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) { - RewriteCastExpr(CE); - } - } - } - return; - } - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { - if (isBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - return; - } - if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) { - if (RD->isDefinition()) { - for (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; - if (isBlockPointerType(FD->getType())) - RewriteBlockPointerDecl(FD); - } - } - return; - } -} diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index df85c13..c347472 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -30,6 +30,28 @@ using llvm::utostr; namespace { class RewriteObjC : public ASTConsumer { + enum { + BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), + block, ... */ + BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */ + BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the + __block variable */ + BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy + helpers */ + BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose + support routines */ + BLOCK_BYREF_CURRENT_MAX = 256 + }; + + enum { + BLOCK_NEEDS_FREE = (1 << 24), + BLOCK_HAS_COPY_DISPOSE = (1 << 25), + BLOCK_HAS_CXX_OBJ = (1 << 26), + BLOCK_IS_GC = (1 << 27), + BLOCK_IS_GLOBAL = (1 << 28), + BLOCK_HAS_DESCRIPTOR = (1 << 29) + }; + Rewriter Rewrite; Diagnostic &Diags; const LangOptions &LangOpts; @@ -324,6 +346,7 @@ namespace { // Block specific rewrite rules. void RewriteBlockCall(CallExpr *Exp); void RewriteBlockPointerDecl(NamedDecl *VD); + void RewriteByRefVar(VarDecl *VD); Stmt *RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD); void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); @@ -337,7 +360,7 @@ namespace { std::string ImplTag, int i, const char *funcName, unsigned hasCopy); - Stmt *SynthesizeBlockCall(CallExpr *Exp); + Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp); void SynthesizeBlockLiterals(SourceLocation FunLocStart, const char *FunName); void RewriteRecordBody(RecordDecl *RD); @@ -565,8 +588,8 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; Preamble += "#else\n"; - Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT \"C\" void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT \"C\" void _Block_object_dispose(const void *, const int);\n"; Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n"; Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; Preamble += "#endif\n"; @@ -576,6 +599,8 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; Preamble += "#define __attribute__(X)\n"; } + else + Preamble += "#define __block\n"; } @@ -3731,8 +3756,8 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, E = BlockByRefDecls.end(); I != E; ++I) { S += " "; std::string Name = (*I)->getNameAsString(); - Context->getPointerType((*I)->getType()).getAsStringInternal(Name, - Context->PrintingPolicy); + std::string TypeString = "struct __Block_byref_" + Name + " *"; + Name = TypeString + Name; S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; } // Next, emit a declaration for all "by copy" declarations. @@ -3781,8 +3806,13 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, S += (*I)->getNameAsString(); S += ", (void*)src->"; S += (*I)->getNameAsString(); - S += ", 3/*BLOCK_FIELD_IS_OBJECT*/);}"; + if (BlockByRefDecls.count((*I))) + S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; + else + S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; } + S += "}\n"; + S += "\nstatic void __"; S += funcName; S += "_block_dispose_" + utostr(i); @@ -3792,7 +3822,10 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, E = ImportedBlockDecls.end(); I != E; ++I) { S += "_Block_object_dispose((void*)src->"; S += (*I)->getNameAsString(); - S += ", 3/*BLOCK_FIELD_IS_OBJECT*/);"; + if (BlockByRefDecls.count((*I))) + S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; + else + S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; } S += "}\n"; return S; @@ -3858,10 +3891,10 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, S += "struct __block_impl *"; Constructor += ", void *" + ArgName; } else { - Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName, - Context->PrintingPolicy); - Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName, - Context->PrintingPolicy); + std::string TypeString = "struct __Block_byref_" + FieldName; + TypeString += " *"; + FieldName = TypeString + FieldName; + ArgName = TypeString + ArgName; Constructor += ", " + ArgName; } S += FieldName + "; // by ref\n"; @@ -3896,7 +3929,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, Constructor += Name + " = (struct __block_impl *)_"; else Constructor += Name + " = _"; - Constructor += Name + ";\n"; + Constructor += Name + "->__forwarding;\n"; } } else { // Finish writing the constructor. @@ -3924,7 +3957,12 @@ std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, S += " {\n unsigned long reserved;\n"; S += " unsigned long Block_size;\n"; if (hasCopy) { - S += " void *copy;\n void *dispose;\n"; + S += " void (*copy)(struct "; + S += ImplTag; S += "*, struct "; + S += ImplTag; S += "*);\n"; + + S += " void (*dispose)(struct "; + S += ImplTag; S += "*);\n"; } S += "} "; @@ -4030,20 +4068,38 @@ void RewriteObjC::GetBlockCallExprs(Stmt *S) { return; } -Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) { +Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { // Navigate to relevant type information. - const char *closureName = 0; const BlockPointerType *CPT = 0; - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) { - closureName = DRE->getDecl()->getNameAsCString(); + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) { CPT = DRE->getType()->getAs<BlockPointerType>(); - } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) { - closureName = CDRE->getDecl()->getNameAsCString(); + } else if (const BlockDeclRefExpr *CDRE = + dyn_cast<BlockDeclRefExpr>(BlockExp)) { CPT = CDRE->getType()->getAs<BlockPointerType>(); - } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) { - closureName = MExpr->getMemberDecl()->getNameAsCString(); + } else if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(BlockExp)) { CPT = MExpr->getType()->getAs<BlockPointerType>(); + } + else if (const ParenExpr *PRE = dyn_cast<ParenExpr>(BlockExp)) { + return SynthesizeBlockCall(Exp, PRE->getSubExpr()); + } + else if (const ImplicitCastExpr *IEXPR = dyn_cast<ImplicitCastExpr>(BlockExp)) + CPT = IEXPR->getType()->getAs<BlockPointerType>(); + else if (const ConditionalOperator *CEXPR = + dyn_cast<ConditionalOperator>(BlockExp)) { + Expr *LHSExp = CEXPR->getLHS(); + Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp); + Expr *RHSExp = CEXPR->getRHS(); + Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp); + Expr *CONDExp = CEXPR->getCond(); + ConditionalOperator *CondExpr = + new (Context) ConditionalOperator(CONDExp, + SourceLocation(), cast<Expr>(LHSStmt), + SourceLocation(), cast<Expr>(RHSStmt), + Exp->getType()); + return CondExpr; + } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) { + CPT = IRE->getType()->getAs<BlockPointerType>(); } else { assert(1 && "RewriteBlockClass: Bad type"); } @@ -4083,7 +4139,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) { CastExpr *BlkCast = new (Context) CStyleCastExpr(PtrBlock, CastExpr::CK_Unknown, - Exp->getCallee(), + const_cast<Expr*>(BlockExp), PtrBlock, SourceLocation(), SourceLocation()); // Don't forget the parens to enforce the proper binding. @@ -4119,7 +4175,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) { } void RewriteObjC::RewriteBlockCall(CallExpr *Exp) { - Stmt *BlockCall = SynthesizeBlockCall(Exp); + Stmt *BlockCall = SynthesizeBlockCall(Exp, Exp->getCallee()); ReplaceStmt(Exp, BlockCall); } @@ -4137,12 +4193,27 @@ void RewriteObjC::RewriteBlockCall(CallExpr *Exp) { // }; //} Stmt *RewriteObjC::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) { - // FIXME: Add more elaborate code generation required by the ABI. - Expr *DerefExpr = new (Context) UnaryOperator(BDRE, UnaryOperator::Deref, - Context->getPointerType(BDRE->getType()), - SourceLocation()); + // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR + // for each BDRE where BYREFVAR is name of the variable. + FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), + &Context->Idents.get("__forwarding"), + Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true); + MemberExpr *ME = new (Context) MemberExpr(BDRE, true, FD, SourceLocation(), + FD->getType()); + const char *Name = BDRE->getDecl()->getNameAsCString(); + FD = FieldDecl::Create(*Context, 0, SourceLocation(), + &Context->Idents.get(Name), + Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true); + ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), + BDRE->getType()); + + + // Need parens to enforce precedence. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), DerefExpr); + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + ME); ReplaceStmt(BDRE, PE); return PE; } @@ -4298,6 +4369,94 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { return; } +/// RewriteByRefVar - For each __block typex ND variable this routine transforms +/// the declaration into: +/// struct __Block_byref_ND { +/// void *__isa; // NULL for everything except __weak pointers +/// struct __Block_byref_ND *__forwarding; +/// int32_t __flags; +/// int32_t __size; +/// void *__ByrefKeepFuncPtr; // Only if variable is __block ObjC object +/// void *__ByrefDestroyFuncPtr; // Only if variable is __block ObjC object +/// typex ND; +/// }; +/// +/// It then replaces declaration of ND variable with: +/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag, +/// __size=sizeof(struct __Block_byref_ND), +/// ND=initializer-if-any}; +/// +/// +void RewriteObjC::RewriteByRefVar(VarDecl *ND) { + SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); + const char *startBuf = SM->getCharacterData(DeclLoc); + SourceLocation X = ND->getLocEnd(); + X = SM->getInstantiationLoc(X); + const char *endBuf = SM->getCharacterData(X); + std::string Name(ND->getNameAsString()); + std::string ByrefType = "struct __Block_byref_"; + ByrefType += Name; + ByrefType += " {\n"; + ByrefType += " void *__isa;\n"; + ByrefType += " struct __Block_byref_" + Name + " *__forwarding;\n"; + ByrefType += " int __flags;\n"; + ByrefType += " int __size;\n"; + // FIXME. Add void *__ByrefKeepFuncPtr; void *__ByrefDestroyFuncPtr; + // if needed. + ND->getType().getAsStringInternal(Name, Context->PrintingPolicy); + ByrefType += " " + Name + ";\n"; + ByrefType += "};\n"; + // Insert this type in global scope. It is needed by helper function. + assert(CurFunctionDef && "RewriteByRefVar - CurFunctionDef is null"); + SourceLocation FunLocStart = CurFunctionDef->getTypeSpecStartLoc(); + InsertText(FunLocStart, ByrefType.c_str(), ByrefType.size()); + + // struct __Block_byref_ND ND = + // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND), + // initializer-if-any}; + bool hasInit = (ND->getInit() != 0); + Name = ND->getNameAsString(); + ByrefType = "struct __Block_byref_" + Name; + if (!hasInit) { + ByrefType += " " + Name + " = "; + ByrefType += "{0, &" + Name + ", "; + // FIXME. Compute the flag. + ByrefType += "0, "; + ByrefType += "sizeof(struct __Block_byref_" + Name + ")"; + ByrefType += "};\n"; + ReplaceText(DeclLoc, endBuf-startBuf+Name.size(), + ByrefType.c_str(), ByrefType.size()); + } + else { + SourceLocation startLoc = ND->getInit()->getLocStart(); + ByrefType += " " + Name; + ReplaceText(DeclLoc, endBuf-startBuf, + ByrefType.c_str(), ByrefType.size()); + ByrefType = " = {0, &" + Name + ", "; + // FIXME. Compute the flag. + ByrefType += "0, "; + ByrefType += "sizeof(struct __Block_byref_" + Name + "), "; + InsertText(startLoc, ByrefType.c_str(), ByrefType.size()); + + // Complete the newly synthesized compound expression by inserting a right + // curly brace before the end of the declaration. + // FIXME: This approach avoids rewriting the initializer expression. It + // also assumes there is only one declarator. For example, the following + // isn't currently supported by this routine (in general): + // + // double __block BYREFVAR = 1.34, BYREFVAR2 = 1.37; + // + const char *startBuf = SM->getCharacterData(startLoc); + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'"); + SourceLocation semiLoc = + startLoc.getFileLocWithOffset(semiBuf-startBuf); + + InsertText(semiLoc, "}", 1); + } + return; +} + void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { // Add initializers for any closure decl refs. GetBlockDeclRefExprs(Exp->getBody()); @@ -4313,7 +4472,9 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { } // Find any imported blocks...they will need special attention. for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->getType()->isBlockPointerType()) { + if (BlockDeclRefs[i]->isByRef() || + BlockDeclRefs[i]->getType()->isObjCObjectPointerType() || + BlockDeclRefs[i]->getType()->isBlockPointerType()) { GetBlockCallExprs(BlockDeclRefs[i]); ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl()); } @@ -4422,16 +4583,14 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { InitExprs.push_back(Exp); } } - if (ImportedBlockDecls.size()) { // generate "1<<25" to indicate we have helper functions. + if (ImportedBlockDecls.size()) { + // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR + int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR); unsigned IntSize = static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); - BinaryOperator *Exp = new (Context) BinaryOperator( - new (Context) IntegerLiteral(llvm::APInt(IntSize, 1), - Context->IntTy,SourceLocation()), - new (Context) IntegerLiteral(llvm::APInt(IntSize, 25), - Context->IntTy, SourceLocation()), - BinaryOperator::Shl, Context->IntTy, SourceLocation()); - InitExprs.push_back(Exp); + Expr *FlagExp = new (Context) IntegerLiteral(llvm::APInt(IntSize, flag), + Context->IntTy, SourceLocation()); + InitExprs.push_back(FlagExp); } NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(), FType, SourceLocation()); @@ -4479,7 +4638,8 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { Stmts.push_back(S); else if (isa<ObjCForCollectionStmt>(S)) { Stmts.push_back(S); - ObjCBcLabelNo.push_back(++BcLabelCount); + ++BcLabelCount; + ObjCBcLabelNo.push_back(BcLabelCount); } SourceRange OrigStmtRange = S->getSourceRange(); @@ -4640,6 +4800,9 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { RewriteBlockPointerDecl(ND); else if (ND->getType()->isFunctionPointerType()) CheckFunctionPointerDecl(ND->getType(), ND); + if (VarDecl *VD = dyn_cast<VarDecl>(SD)) + if (VD->hasAttr<BlocksAttr>()) + RewriteByRefVar(VD); } if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { if (isTopLevelBlockPointerType(TD->getUnderlyingType())) @@ -4668,7 +4831,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { } if (CallExpr *CE = dyn_cast<CallExpr>(S)) { if (CE->getCallee()->getType()->isBlockPointerType()) { - Stmt *BlockCall = SynthesizeBlockCall(CE); + Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee()); ReplaceStmt(S, BlockCall); return BlockCall; } diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp index ff44c90..4bf507d 100644 --- a/lib/Frontend/Warnings.cpp +++ b/lib/Frontend/Warnings.cpp @@ -13,12 +13,12 @@ // // This file is responsible for handling all warning options. This includes // a number of -Wfoo options and their variants, which are driven by TableGen- -// generated data, and the special cases -pedantic, -pedantic-errors, -w and -// -Werror. +// generated data, and the special cases -pedantic, -pedantic-errors, -w, +// -Werror and -Wfatal-errors. // // Each warning option controls any number of actual warnings. // Given a warning option 'foo', the following are valid: -// -Wfoo, -Wno-foo, -Werror=foo +// -Wfoo, -Wno-foo, -Werror=foo, -Wfatal-errors=foo // #include "clang/Frontend/Utils.h" #include "clang/Basic/Diagnostic.h" @@ -26,7 +26,6 @@ #include "clang/Lex/LexDiagnostic.h" #include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" -#include <cstdio> #include <cstring> #include <utility> #include <algorithm> @@ -47,8 +46,6 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags, else Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore); - // FIXME: -Wfatal-errors / -Wfatal-errors=foo - for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) { const std::string &Opt = Opts.Warnings[i]; const char *OptStart = &Opt[0]; @@ -81,8 +78,8 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags, if (OptEnd-OptStart != 5) { // Specifier must be present. if ((OptStart[5] != '=' && OptStart[5] != '-') || OptEnd-OptStart == 6) { - fprintf(stderr, "warning: unknown -Werror warning specifier: -W%s\n", - Opt.c_str()); + Diags.Report(diag::warn_unknown_warning_specifier) + << "-Werror" << ("-W" + Opt); continue; } Specifier = OptStart+6; @@ -98,6 +95,30 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags, OptStart = Specifier; } + // -Wfatal-errors is yet another special case. + if (OptEnd-OptStart >= 12 && memcmp(OptStart, "fatal-errors", 12) == 0) { + const char* Specifier = 0; + if (OptEnd-OptStart != 12) { + if ((OptStart[12] != '=' && OptStart[12] != '-') || + OptEnd-OptStart == 13) { + Diags.Report(diag::warn_unknown_warning_specifier) + << "-Wfatal-errors" << ("-W" + Opt); + continue; + } + Specifier = OptStart + 13; + } + + if (Specifier == 0) { + Diags.setErrorsAsFatal(isPositive); + continue; + } + + // -Wfatal-errors=foo maps foo to Fatal, -Wno-fatal-errors=foo + // maps it to Error. + Mapping = isPositive ? diag::MAP_FATAL : diag::MAP_ERROR_NO_WFATAL; + OptStart = Specifier; + } + if (Diags.setDiagnosticGroupMapping(OptStart, Mapping)) Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt); } diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index a91e404..d5a4643 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -33,7 +33,7 @@ #include <cctype> using namespace clang; -static void InitCharacterInfo(LangOptions); +static void InitCharacterInfo(); //===----------------------------------------------------------------------===// // Token Class Implementation @@ -59,7 +59,7 @@ tok::ObjCKeywordKind Token::getObjCKeywordID() const { void Lexer::InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd) { - InitCharacterInfo(Features); + InitCharacterInfo(); BufferStart = BufStart; BufferPtr = BufPtr; @@ -254,7 +254,7 @@ enum { // Statically initialize CharInfo table based on ASCII character set // Reference: FreeBSD 7.2 /usr/share/misc/ascii -static unsigned char CharInfo[256] = +static const unsigned char CharInfo[256] = { // 0 NUL 1 SOH 2 STX 3 ETX // 4 EOT 5 ENQ 6 ACK 7 BEL @@ -322,7 +322,7 @@ static unsigned char CharInfo[256] = 0 , 0 , 0 , 0 }; -static void InitCharacterInfo(LangOptions Features) { +static void InitCharacterInfo() { static bool isInited = false; if (isInited) return; // check the statically-initialized CharInfo table @@ -341,10 +341,6 @@ static void InitCharacterInfo(LangOptions Features) { for (unsigned i = '0'; i <= '9'; ++i) assert(CHAR_NUMBER == CharInfo[i]); - if (Features.Microsoft) - // Hack to treat DOS & CP/M EOF (^Z) as horizontal whitespace. - CharInfo[26/*sub*/] = CHAR_HORZ_WS; - isInited = true; } @@ -1549,6 +1545,22 @@ LexNextToken: return; // KeepWhitespaceMode goto LexNextToken; // GCC isn't tail call eliminating. + + case 26: // DOS & CP/M EOF: "^Z". + // If we're in Microsoft extensions mode, treat this as end of file. + if (Features.Microsoft) { + // Read the PP instance variable into an automatic variable, because + // LexEndOfFile will often delete 'this'. + Preprocessor *PPCache = PP; + if (LexEndOfFile(Result, CurPtr-1)) // Retreat back into the file. + return; // Got a token to return. + assert(PPCache && "Raw buffer::LexEndOfFile should return a token"); + return PPCache->Lex(Result); + } + // If Microsoft extensions are disabled, this is just random garbage. + Kind = tok::unknown; + break; + case '\n': case '\r': // If we are inside a preprocessor directive and we see the end of line, @@ -1599,7 +1611,7 @@ LexNextToken: goto SkipHorizontalWhitespace; } goto LexNextToken; // GCC isn't tail call eliminating. - + // C99 6.4.4.1: Integer Constants. // C99 6.4.4.2: Floating Constants. case '0': case '1': case '2': case '3': case '4': diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index ab66942..9aaa82d 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -610,28 +610,14 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) { return OverflowOccurred; } -llvm::APFloat NumericLiteralParser:: -GetFloatValue(const llvm::fltSemantics &Format, bool* isExact) { +llvm::APFloat::opStatus +NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) { using llvm::APFloat; using llvm::StringRef; - llvm::SmallVector<char,256> floatChars; unsigned n = std::min(SuffixBegin - ThisTokBegin, ThisTokEnd - ThisTokBegin); - for (unsigned i = 0; i != n; ++i) - floatChars.push_back(ThisTokBegin[i]); - - floatChars.push_back('\0'); - - APFloat V (Format, APFloat::fcZero, false); - APFloat::opStatus status; - - status = V.convertFromString(StringRef(&floatChars[0], n), - APFloat::rmNearestTiesToEven); - - if (isExact) - *isExact = status == APFloat::opOK; - - return V; + return Result.convertFromString(StringRef(ThisTokBegin, n), + APFloat::rmNearestTiesToEven); } diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp index 376cce8..2f1a34c 100644 --- a/lib/Lex/MacroArgs.cpp +++ b/lib/Lex/MacroArgs.cpp @@ -24,12 +24,37 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI, Preprocessor &PP) { assert(MI->isFunctionLike() && "Can't have args for an object-like macro!"); - - // Allocate memory for the MacroArgs object with the lexer tokens at the end. - MacroArgs *Result = (MacroArgs*)malloc(sizeof(MacroArgs) + - NumToks*sizeof(Token)); - // Construct the macroargs object. - new (Result) MacroArgs(NumToks, VarargsElided); + MacroArgs **ResultEnt = 0; + unsigned ClosestMatch = ~0U; + + // See if we have an entry with a big enough argument list to reuse on the + // free list. If so, reuse it. + for (MacroArgs **Entry = &PP.MacroArgCache; *Entry; + Entry = &(*Entry)->ArgCache) + if ((*Entry)->NumUnexpArgTokens >= NumToks && + (*Entry)->NumUnexpArgTokens < ClosestMatch) { + ResultEnt = Entry; + + // If we have an exact match, use it. + if ((*Entry)->NumUnexpArgTokens == NumToks) + break; + // Otherwise, use the best fit. + ClosestMatch = (*Entry)->NumUnexpArgTokens; + } + + MacroArgs *Result; + if (ResultEnt == 0) { + // Allocate memory for a MacroArgs object with the lexer tokens at the end. + Result = (MacroArgs*)malloc(sizeof(MacroArgs) + NumToks*sizeof(Token)); + // Construct the MacroArgs object. + new (Result) MacroArgs(NumToks, VarargsElided); + } else { + Result = *ResultEnt; + // Unlink this node from the preprocessors singly linked list. + *ResultEnt = Result->ArgCache; + Result->NumUnexpArgTokens = NumToks; + Result->VarargsElided = VarargsElided; + } // Copy the actual unexpanded tokens to immediately after the result ptr. if (NumToks) @@ -42,10 +67,16 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI, /// destroy - Destroy and deallocate the memory for this object. /// void MacroArgs::destroy(Preprocessor &PP) { - // Run the dtor to deallocate the vectors. - this->~MacroArgs(); - // Release the memory for the object. - free(this); + StringifiedArgs.clear(); + + // Don't clear PreExpArgTokens, just clear the entries. Clearing the entries + // would deallocate the element vectors. + for (unsigned i = 0, e = PreExpArgTokens.size(); i != e; ++i) + PreExpArgTokens[i].clear(); + + // Add this to the preprocessor's free list. + ArgCache = PP.MacroArgCache; + PP.MacroArgCache = this; } /// deallocate - This should only be called by the Preprocessor when managing @@ -110,13 +141,14 @@ bool MacroArgs::ArgNeedsPreexpansion(const Token *ArgTok, /// getPreExpArgument - Return the pre-expanded form of the specified /// argument. const std::vector<Token> & -MacroArgs::getPreExpArgument(unsigned Arg, Preprocessor &PP) { - assert(Arg < NumUnexpArgTokens && "Invalid argument number!"); +MacroArgs::getPreExpArgument(unsigned Arg, const MacroInfo *MI, + Preprocessor &PP) { + assert(Arg < MI->getNumArgs() && "Invalid argument number!"); // If we have already computed this, return it. - if (PreExpArgTokens.empty()) - PreExpArgTokens.resize(NumUnexpArgTokens); - + if (PreExpArgTokens.size() < MI->getNumArgs()) + PreExpArgTokens.resize(MI->getNumArgs()); + std::vector<Token> &Result = PreExpArgTokens[Arg]; if (!Result.empty()) return Result; @@ -156,7 +188,7 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks, Preprocessor &PP, bool Charify) { Token Tok; Tok.startToken(); - Tok.setKind(tok::string_literal); + Tok.setKind(Charify ? tok::char_constant : tok::string_literal); const Token *ArgTokStart = ArgToks; diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h index fa040c7..6ff4856 100644 --- a/lib/Lex/MacroArgs.h +++ b/lib/Lex/MacroArgs.h @@ -82,7 +82,7 @@ public: /// getPreExpArgument - Return the pre-expanded form of the specified /// argument. const std::vector<Token> & - getPreExpArgument(unsigned Arg, Preprocessor &PP); + getPreExpArgument(unsigned Arg, const MacroInfo *MI, Preprocessor &PP); /// getStringifiedArgument - Compute, cache, and return the specified argument /// that has been 'stringified' as required by the # operator. diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index f5c60eb..9e3d283 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -220,32 +220,28 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, // Get the identifier name without trigraphs or embedded newlines. Note // that we can't use Tok.getIdentifierInfo() because its lookup is disabled // when skipping. - // TODO: could do this with zero copies in the no-clean case by using - // strncmp below. - char Directive[20]; - unsigned IdLen; + char DirectiveBuf[20]; + llvm::StringRef Directive; if (!Tok.needsCleaning() && Tok.getLength() < 20) { - IdLen = Tok.getLength(); - memcpy(Directive, RawCharData, IdLen); - Directive[IdLen] = 0; + Directive = llvm::StringRef(RawCharData, Tok.getLength()); } else { std::string DirectiveStr = getSpelling(Tok); - IdLen = DirectiveStr.size(); + unsigned IdLen = DirectiveStr.size(); if (IdLen >= 20) { CurPPLexer->ParsingPreprocessorDirective = false; // Restore comment saving mode. if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments); continue; } - memcpy(Directive, &DirectiveStr[0], IdLen); - Directive[IdLen] = 0; - FirstChar = Directive[0]; + memcpy(DirectiveBuf, &DirectiveStr[0], IdLen); + Directive = llvm::StringRef(DirectiveBuf, IdLen); } - if (FirstChar == 'i' && Directive[1] == 'f') { - if ((IdLen == 2) || // "if" - (IdLen == 5 && !strcmp(Directive+2, "def")) || // "ifdef" - (IdLen == 6 && !strcmp(Directive+2, "ndef"))) { // "ifndef" + if (Directive.startswith("if")) { + llvm::StringRef Sub = Directive.substr(2); + if (Sub.empty() || // "if" + Sub == "def" || // "ifdef" + Sub == "ndef") { // "ifndef" // We know the entire #if/#ifdef/#ifndef block will be skipped, don't // bother parsing the condition. DiscardUntilEndOfDirective(); @@ -253,8 +249,9 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, /*foundnonskip*/false, /*fnddelse*/false); } - } else if (FirstChar == 'e') { - if (IdLen == 5 && !strcmp(Directive+1, "ndif")) { // "endif" + } else if (Directive[0] == 'e') { + llvm::StringRef Sub = Directive.substr(1); + if (Sub == "ndif") { // "endif" CheckEndOfDirective("endif"); PPConditionalInfo CondInfo; CondInfo.WasSkipping = true; // Silence bogus warning. @@ -265,7 +262,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, // If we popped the outermost skipping block, we're done skipping! if (!CondInfo.WasSkipping) break; - } else if (IdLen == 4 && !strcmp(Directive+1, "lse")) { // "else". + } else if (Sub == "lse") { // "else". // #else directive in a skipping conditional. If not in some other // skipping conditional, and if #else hasn't already been seen, enter it // as a non-skipping conditional. @@ -284,7 +281,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, CondInfo.FoundNonSkip = true; break; } - } else if (IdLen == 4 && !strcmp(Directive+1, "lif")) { // "elif". + } else if (Sub == "lif") { // "elif". PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel(); bool ShouldEnter; diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index d4e441b..81966cb 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -446,19 +446,10 @@ void Preprocessor::EnterMainSourceFile() { if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID)) HeaderInfo.IncrementIncludeCount(FE); - std::vector<char> PrologFile; - PrologFile.reserve(4080); - - // FIXME: Don't make a copy. - PrologFile.insert(PrologFile.end(), Predefines.begin(), Predefines.end()); - - // Memory buffer must end with a null byte! - PrologFile.push_back(0); - - // Now that we have emitted the predefined macros, #includes, etc into - // PrologFile, preprocess it to populate the initial preprocessor state. + // Preprocess Predefines to populate the initial preprocessor state. llvm::MemoryBuffer *SB = - llvm::MemoryBuffer::getMemBufferCopy(&PrologFile.front(),&PrologFile.back(), + llvm::MemoryBuffer::getMemBufferCopy(Predefines.data(), + Predefines.data() + Predefines.size(), "<built-in>"); assert(SB && "Cannot fail to create predefined source buffer"); FileID FID = SourceMgr.createFileIDForMemBuffer(SB); diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index a40bb62..5d95eb3 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -175,7 +175,7 @@ void TokenLexer::ExpandFunctionArguments() { // avoids some work in common cases. const Token *ArgTok = ActualArgs->getUnexpArgument(ArgNo); if (ActualArgs->ArgNeedsPreexpansion(ArgTok, PP)) - ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, PP)[0]; + ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, Macro, PP)[0]; else ResultArgToks = ArgTok; // Use non-preexpanded tokens. @@ -414,7 +414,7 @@ bool TokenLexer::PasteTokens(Token &Tok) { ResultTokTmp.startToken(); // Claim that the tmp token is a string_literal so that we can get the - // character pointer back from CreateString. + // character pointer back from CreateString in getLiteralData(). ResultTokTmp.setKind(tok::string_literal); PP.CreateString(&Buffer[0], Buffer.size(), ResultTokTmp); SourceLocation ResultTokLoc = ResultTokTmp.getLocation(); diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index b9314d2..f1e639c 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -95,9 +95,12 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { if (HasTemplateScope) Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate); + // The current scope is still active if we're the top-level class. + // Otherwise we'll need to push and enter a new scope. bool HasClassScope = !Class.TopLevelClass; - ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, - HasClassScope); + ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope); + if (HasClassScope) + Actions.ActOnStartDelayedMemberDeclarations(CurScope, Class.TagOrTemplate); for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) { LateParsedMethodDeclaration &LM = Class.MethodDecls.front(); @@ -148,6 +151,9 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I) ParseLexedMethodDeclarations(*Class.NestedClasses[I]); + + if (HasClassScope) + Actions.ActOnFinishDelayedMemberDeclarations(CurScope, Class.TagOrTemplate); } /// ParseLexedMethodDefs - We finished parsing the member specification of a top diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 5dd78f7..f429ac9 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -550,13 +550,17 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, SourceLocation DelLoc = ConsumeToken(); Actions.SetDeclDeleted(ThisDecl, DelLoc); } else { - if (getLang().CPlusPlus) + if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + EnterScope(0); Actions.ActOnCXXEnterDeclInitializer(CurScope, ThisDecl); + } OwningExprResult Init(ParseInitializer()); - if (getLang().CPlusPlus) + if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(CurScope, ThisDecl); + ExitScope(); + } if (Init.isInvalid()) { SkipUntil(tok::semi, true, true); @@ -570,14 +574,30 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, ExprVector Exprs(Actions); CommaLocsTy CommaLocs; + if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + EnterScope(0); + Actions.ActOnCXXEnterDeclInitializer(CurScope, ThisDecl); + } + if (ParseExpressionList(Exprs, CommaLocs)) { SkipUntil(tok::r_paren); + + if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + Actions.ActOnCXXExitDeclInitializer(CurScope, ThisDecl); + ExitScope(); + } } else { // Match the ')'. SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() && "Unexpected number of commas!"); + + if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + Actions.ActOnCXXExitDeclInitializer(CurScope, ThisDecl); + ExitScope(); + } + Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc, move_arg(Exprs), CommaLocs.data(), RParenLoc); @@ -2349,7 +2369,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*EnteringContext=*/true, /*AllowDestructorName=*/true, - /*AllowConstructorName=*/!D.getDeclSpec().hasTypeSpecifier(), + /*AllowConstructorName=*/!D.getDeclSpec().hasTypeSpecifier(), /*ObjectType=*/0, D.getName())) { D.SetIdentifier(0, Tok.getLocation()); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index d4d19a0..265d0f3 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -852,20 +852,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SS, Name, StartLoc, NameLoc); } - // Parse the optional base clause (C++ only). - if (getLang().CPlusPlus && Tok.is(tok::colon)) - ParseBaseClause(TagOrTempResult.get()); - // If there is a body, parse it and inform the actions module. - if (Tok.is(tok::l_brace)) + if (TUK == Action::TUK_Definition) { + assert(Tok.is(tok::l_brace) || + (getLang().CPlusPlus && Tok.is(tok::colon))); if (getLang().CPlusPlus) ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get()); else ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get()); - else if (TUK == Action::TUK_Definition) { - // FIXME: Complain that we have a base-specifier list but no - // definition. - Diag(Tok, diag::err_expected_lbrace); } void *Result; @@ -1364,8 +1358,6 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, PP.getSourceManager(), "parsing struct/union/class body"); - SourceLocation LBraceLoc = ConsumeBrace(); - // Determine whether this is a top-level (non-nested) class. bool TopLevelClass = ClassStack.empty() || CurScope->isInCXXInlineMethodScope(); @@ -1378,11 +1370,27 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (TagDecl) Actions.ActOnTagStartDefinition(CurScope, TagDecl); - else { + + if (Tok.is(tok::colon)) { + ParseBaseClause(TagDecl); + + if (!Tok.is(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace_after_base_specifiers); + return; + } + } + + assert(Tok.is(tok::l_brace)); + + SourceLocation LBraceLoc = ConsumeBrace(); + + if (!TagDecl) { SkipUntil(tok::r_brace, false, false); return; } + Actions.ActOnStartCXXMemberDeclarations(CurScope, TagDecl, LBraceLoc); + // C++ 11p3: Members of a class defined with the keyword class are private // by default. Members of a class defined with the keywords struct or union // are public by default. diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 2c53847..9904a2c 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -1589,7 +1589,7 @@ Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { // Otherwise, eat the semicolon. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); - return Actions.ActOnExprStmt(Actions.FullExpr(Res)); + return Actions.ActOnExprStmt(Actions.MakeFullExpr(Res)); } Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index a2ac646..9085b87 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -131,7 +131,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } // Otherwise, eat the semicolon. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); - return Actions.ActOnExprStmt(Actions.FullExpr(Expr)); + return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr)); } case tok::kw_case: // C99 6.8.1: labeled-statement @@ -494,7 +494,7 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { // Eat the semicolon at the end of stmt and convert the expr into a // statement. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); - R = Actions.ActOnExprStmt(Actions.FullExpr(Res)); + R = Actions.ActOnExprStmt(Actions.MakeFullExpr(Res)); } } @@ -593,7 +593,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { if (ParseParenExprOrCondition(CondExp, CondVar)) return StmtError(); - FullExprArg FullCondExp(Actions.FullExpr(CondExp)); + FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp)); // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this @@ -720,7 +720,7 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { if (ParseParenExprOrCondition(Cond, CondVar)) return StmtError(); - FullExprArg FullCond(Actions.FullExpr(Cond)); + FullExprArg FullCond(Actions.MakeFullExpr(Cond)); OwningStmtResult Switch = Actions.ActOnStartOfSwitchStmt(FullCond, CondVar); @@ -801,7 +801,7 @@ Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) { if (ParseParenExprOrCondition(Cond, CondVar)) return StmtError(); - FullExprArg FullCond(Actions.FullExpr(Cond)); + FullExprArg FullCond(Actions.MakeFullExpr(Cond)); // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this @@ -993,7 +993,7 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { // Turn the expression into a stmt. if (!Value.isInvalid()) - FirstPart = Actions.ActOnExprStmt(Actions.FullExpr(Value)); + FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value)); if (Tok.is(tok::semi)) { ConsumeToken(); @@ -1060,8 +1060,8 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { if (!ForEach) return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart), - Actions.FullExpr(SecondPart), SecondVar, - Actions.FullExpr(ThirdPart), RParenLoc, + Actions.MakeFullExpr(SecondPart), SecondVar, + Actions.MakeFullExpr(ThirdPart), RParenLoc, move(Body)); return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, @@ -1232,7 +1232,6 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { // Remember if this was a volatile asm. bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; - bool isSimple = false; if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "asm"; SkipUntil(tok::r_paren); @@ -1249,53 +1248,73 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { ExprVector Exprs(Actions); ExprVector Clobbers(Actions); - unsigned NumInputs = 0, NumOutputs = 0; - - SourceLocation RParenLoc; if (Tok.is(tok::r_paren)) { - // We have a simple asm expression - isSimple = true; - - RParenLoc = ConsumeParen(); - } else { - // Parse Outputs, if present. - if (ParseAsmOperandsOpt(Names, Constraints, Exprs)) - return StmtError(); - - NumOutputs = Names.size(); + // We have a simple asm expression like 'asm("foo")'. + SourceLocation RParenLoc = ConsumeParen(); + return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, + /*NumOutputs*/ 0, /*NumInputs*/ 0, 0, + move_arg(Constraints), move_arg(Exprs), + move(AsmString), move_arg(Clobbers), + RParenLoc); + } - // Parse Inputs, if present. - if (ParseAsmOperandsOpt(Names, Constraints, Exprs)) - return StmtError(); + // Parse Outputs, if present. + bool AteExtraColon = false; + if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { + // In C++ mode, parse "::" like ": :". + AteExtraColon = Tok.is(tok::coloncolon); + ConsumeToken(); + + if (!AteExtraColon && + ParseAsmOperandsOpt(Names, Constraints, Exprs)) + return StmtError(); + } + + unsigned NumOutputs = Names.size(); + + // Parse Inputs, if present. + if (AteExtraColon || + Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { + // In C++ mode, parse "::" like ": :". + if (AteExtraColon) + AteExtraColon = false; + else { + AteExtraColon = Tok.is(tok::coloncolon); + ConsumeToken(); + } + + if (!AteExtraColon && + ParseAsmOperandsOpt(Names, Constraints, Exprs)) + return StmtError(); + } - assert(Names.size() == Constraints.size() && - Constraints.size() == Exprs.size() - && "Input operand size mismatch!"); + assert(Names.size() == Constraints.size() && + Constraints.size() == Exprs.size() && + "Input operand size mismatch!"); - NumInputs = Names.size() - NumOutputs; + unsigned NumInputs = Names.size() - NumOutputs; - // Parse the clobbers, if present. - if (Tok.is(tok::colon)) { + // Parse the clobbers, if present. + if (AteExtraColon || Tok.is(tok::colon)) { + if (!AteExtraColon) ConsumeToken(); - // Parse the asm-string list for clobbers. - while (1) { - OwningExprResult Clobber(ParseAsmStringLiteral()); + // Parse the asm-string list for clobbers. + while (1) { + OwningExprResult Clobber(ParseAsmStringLiteral()); - if (Clobber.isInvalid()) - break; + if (Clobber.isInvalid()) + break; - Clobbers.push_back(Clobber.release()); + Clobbers.push_back(Clobber.release()); - if (Tok.isNot(tok::comma)) break; - ConsumeToken(); - } + if (Tok.isNot(tok::comma)) break; + ConsumeToken(); } - - RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc); } - return Actions.ActOnAsmStmt(AsmLoc, isSimple, isVolatile, + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc); + return Actions.ActOnAsmStmt(AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(), move_arg(Constraints), move_arg(Exprs), move(AsmString), move_arg(Clobbers), @@ -1303,8 +1322,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { } /// ParseAsmOperands - Parse the asm-operands production as used by -/// asm-statement. We also parse a leading ':' token. If the leading colon is -/// not present, we do not parse anything. +/// asm-statement, assuming the leading ':' token was eaten. /// /// [GNU] asm-operands: /// asm-operand @@ -1319,10 +1337,6 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names, llvm::SmallVectorImpl<ExprTy*> &Constraints, llvm::SmallVectorImpl<ExprTy*> &Exprs) { - // Only do anything if this operand is present. - if (Tok.isNot(tok::colon)) return false; - ConsumeToken(); - // 'asm-operands' isn't present? if (!isTokenStringLiteral() && Tok.isNot(tok::l_square)) return false; diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index cc28541..8b8af99 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -643,8 +643,10 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, } } - if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater)) + if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater)) { + Diag(Tok.getLocation(), diag::err_expected_greater); return true; + } // Determine the location of the '>' or '>>'. Only consume this // token if the caller asked us to. @@ -989,7 +991,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { ConsumeToken(); } - return Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater); + return false; } /// \brief Parse a C++ explicit template instantiation diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index dabd065..51c5670 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -680,10 +680,11 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { // Otherwise, not a typename. return TPResult::False(); - case tok::coloncolon: // ::foo::bar - if (NextToken().is(tok::kw_new) || // ::new - NextToken().is(tok::kw_delete)) // ::delete - return TPResult::False(); + case tok::coloncolon: { // ::foo::bar + const Token &Next = NextToken(); + if (Next.is(tok::kw_new) || // ::new + Next.is(tok::kw_delete)) // ::delete + return TPResult::False(); // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. @@ -691,7 +692,8 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { return isCXXDeclarationSpecifier(); // Otherwise, not a typename. return TPResult::False(); - + } + // decl-specifier: // storage-class-specifier // type-specifier @@ -699,7 +701,6 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { // 'friend' // 'typedef' // 'constexpr' - case tok::kw_friend: case tok::kw_typedef: case tok::kw_constexpr: @@ -750,6 +751,12 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw___forceinline: return TPResult::True(); + case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed + // We've already annotated a scope; try to annotate a type. + if (!(TryAnnotateTypeOrScopeToken() && Tok.is(tok::annot_typename))) + return TPResult::False(); + // If that succeeded, fallthrough into the generic simple-type-id case. + // The ambiguity resides in a simple-type-specifier/typename-specifier // followed by a '('. The '(' could either be the start of: // diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index a864e7c..52c0153 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -880,7 +880,7 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { /// as the current tokens, so only call it in contexts where these are invalid. bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) - || Tok.is(tok::kw_typename)) && + || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) && "Cannot be a type or scope token!"); if (Tok.is(tok::kw_typename)) { @@ -935,6 +935,9 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { return true; } + // Remembers whether the token was originally a scope annotation. + bool wasScopeAnnotation = Tok.is(tok::annot_cxxscope); + CXXScopeSpec SS; if (getLang().CPlusPlus) ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext); @@ -1017,9 +1020,11 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { Tok.setAnnotationValue(SS.getScopeRep()); Tok.setAnnotationRange(SS.getRange()); - // In case the tokens were cached, have Preprocessor replace them with the - // annotation token. - PP.AnnotateCachedTokens(Tok); + // In case the tokens were cached, have Preprocessor replace them + // with the annotation token. We don't need to do this if we've + // just reverted back to the state we were in before being called. + if (!wasScopeAnnotation) + PP.AnnotateCachedTokens(Tok); return true; } diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index d8ed894..b9b85df 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -37,6 +37,7 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) case CK_Text: case CK_Placeholder: case CK_Informative: + case CK_ResultType: case CK_CurrentParameter: { char *New = new char [Text.size() + 1]; std::memcpy(New, Text.data(), Text.size()); @@ -112,6 +113,11 @@ CodeCompletionString::Chunk::CreateInformative(StringRef Informative) { } CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreateResultType(StringRef ResultType) { + return Chunk(CK_ResultType, ResultType); +} + +CodeCompletionString::Chunk CodeCompletionString::Chunk::CreateCurrentParameter( StringRef CurrentParameter) { return Chunk(CK_CurrentParameter, CurrentParameter); @@ -123,6 +129,7 @@ CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const { case CK_Text: case CK_Placeholder: case CK_Informative: + case CK_ResultType: case CK_CurrentParameter: case CK_LeftParen: case CK_RightParen: @@ -156,6 +163,7 @@ CodeCompletionString::Chunk::Destroy() { case CK_Text: case CK_Placeholder: case CK_Informative: + case CK_ResultType: case CK_CurrentParameter: delete [] Text; break; @@ -186,7 +194,12 @@ std::string CodeCompletionString::getAsString() const { switch (C->Kind) { case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break; case CK_Placeholder: OS << "<#" << C->Text << "#>"; break; - case CK_Informative: OS << "[#" << C->Text << "#]"; break; + + case CK_Informative: + case CK_ResultType: + OS << "[#" << C->Text << "#]"; + break; + case CK_CurrentParameter: OS << "<#" << C->Text << "#>"; break; default: OS << C->Text; break; } @@ -236,6 +249,7 @@ void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { case CK_Text: case CK_Placeholder: case CK_Informative: + case CK_ResultType: case CK_CurrentParameter: { const char *Text = C->Text; unsigned StrLen = strlen(Text); @@ -286,6 +300,7 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, case CK_Text: case CK_Placeholder: case CK_Informative: + case CK_ResultType: case CK_CurrentParameter: { unsigned StrLen; if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd)) diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index 78f79ea..c5eecda 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -121,6 +121,8 @@ public: typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy; typedef DeclsTy::const_iterator iterator; + typedef bool (*ResultFilter)(NamedDecl*, unsigned IDNS); + LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc, Sema::LookupNameKind LookupKind, Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) @@ -130,11 +132,14 @@ public: Name(Name), NameLoc(NameLoc), LookupKind(LookupKind), + IsAcceptableFn(0), IDNS(0), Redecl(Redecl != Sema::NotForRedeclaration), HideTags(true), Diagnose(Redecl == Sema::NotForRedeclaration) - {} + { + configure(); + } /// Creates a temporary lookup result, initializing its core data /// using the information from another result. Diagnostics are always @@ -146,6 +151,7 @@ public: Name(Other.Name), NameLoc(Other.NameLoc), LookupKind(Other.LookupKind), + IsAcceptableFn(Other.IsAcceptableFn), IDNS(Other.IDNS), Redecl(Other.Redecl), HideTags(Other.HideTags), @@ -162,6 +168,11 @@ public: return Name; } + /// \brief Sets the name to look up. + void setLookupName(DeclarationName Name) { + this->Name = Name; + } + /// Gets the kind of lookup to perform. Sema::LookupNameKind getLookupKind() const { return LookupKind; @@ -178,17 +189,6 @@ public: HideTags = Hide; } - /// The identifier namespace of this lookup. This information is - /// private to the lookup routines. - unsigned getIdentifierNamespace() const { - assert(IDNS); - return IDNS; - } - - void setIdentifierNamespace(unsigned NS) { - IDNS = NS; - } - bool isAmbiguous() const { return getResultKind() == Ambiguous; } @@ -231,7 +231,19 @@ public: return Paths; } - /// \brief Add a declaration to these results. + /// \brief Tests whether the given declaration is acceptable. + bool isAcceptableDecl(NamedDecl *D) const { + assert(IsAcceptableFn); + return IsAcceptableFn(D, IDNS); + } + + /// \brief Returns the identifier namespace mask for this lookup. + unsigned getIdentifierNamespace() const { + return IDNS; + } + + /// \brief Add a declaration to these results. Does not test the + /// acceptance criteria. void addDecl(NamedDecl *D) { Decls.push_back(D); ResultKind = Found; @@ -334,6 +346,7 @@ public: void clear(Sema::LookupNameKind Kind) { clear(); LookupKind = Kind; + configure(); } void print(llvm::raw_ostream &); @@ -362,6 +375,10 @@ public: return NameLoc; } + /// \brief Get the Sema object that this lookup result is searching + /// with. + Sema &getSema() const { return SemaRef; } + /// A class for iterating through a result set and possibly /// filtering out results. The results returned are possibly /// sugared. @@ -438,6 +455,7 @@ private: } void addDeclsFromBasePaths(const CXXBasePaths &P); + void configure(); // Sanity checks. void sanity() const { @@ -476,7 +494,9 @@ private: SourceLocation NameLoc; SourceRange NameContextRange; Sema::LookupNameKind LookupKind; - unsigned IDNS; // ill-defined until set by lookup + ResultFilter IsAcceptableFn; // set by configure() + unsigned IDNS; // set by configure() + bool Redecl; /// \brief True if tag declarations should be hidden if non-tags @@ -486,6 +506,26 @@ private: bool Diagnose; }; + /// \brief Consumes visible declarations found when searching for + /// all visible names within a given scope or context. + /// + /// This abstract class is meant to be subclassed by clients of \c + /// Sema::LookupVisibleDecls(), each of which should override the \c + /// FoundDecl() function to process declarations as they are found. + class VisibleDeclConsumer { + public: + /// \brief Destroys the visible declaration consumer. + virtual ~VisibleDeclConsumer(); + + /// \brief Invoked each time \p Sema::LookupVisibleDecls() finds a + /// declaration visible from the current scope or context. + /// + /// \param ND the declaration found. + /// + /// \param Hiding a declaration that hides the declaration \p ND, + /// or NULL if no such declaration exists. + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding) = 0; + }; } #endif diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index ef61474..40ad90a 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -350,7 +350,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), - PreDeclaratorDC(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0), + CurBlock(0), PackContext(0), ParsingDeclDepth(0), IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), @@ -389,12 +389,6 @@ static bool getIntProperties(ASTContext &C, const Type *T, return true; } - if (const FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) { - BitWidth = FWIT->getWidth(); - Signed = FWIT->isSigned(); - return true; - } - return false; } @@ -655,8 +649,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T) { } // If the target is integral, always warn. - if ((TargetBT && TargetBT->isInteger()) || - isa<FixedWidthIntType>(Target)) + if ((TargetBT && TargetBT->isInteger())) // TODO: don't warn for integer values? return DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer); @@ -815,7 +808,7 @@ void Sema::ActOnEndOfTranslationUnit() { //===----------------------------------------------------------------------===// DeclContext *Sema::getFunctionLevelDeclContext() { - DeclContext *DC = PreDeclaratorDC ? PreDeclaratorDC : CurContext; + DeclContext *DC = CurContext; while (isa<BlockDecl>(DC)) DC = DC->getParent(); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index ada8aa1..4cecee4 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -24,6 +24,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/FullExpr.h" #include "clang/Parse/Action.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallVector.h" @@ -57,6 +58,7 @@ namespace clang { class DesignatedInitExpr; class CallExpr; class DeclRefExpr; + class UnresolvedLookupExpr; class VarDecl; class ParmVarDecl; class TypedefDecl; @@ -98,7 +100,8 @@ namespace clang { class InitializedEntity; class InitializationKind; class InitializationSequence; - + class VisibleDeclConsumer; + /// BlockSemaInfo - When a block is being parsed, this contains information /// about the block. It is pointed to from Sema::CurBlock. struct BlockSemaInfo { @@ -190,10 +193,6 @@ public: /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; - /// PreDeclaratorDC - Keeps the declaration context before switching to the - /// context of a declarator's nested-name-specifier. - DeclContext *PreDeclaratorDC; - /// CurBlock - If inside of a block definition, this contains a pointer to /// the active block object that represents it. BlockSemaInfo *CurBlock; @@ -611,10 +610,6 @@ public: const LookupResult &Previous, Scope *S); void DiagnoseFunctionSpecifiers(Declarator& D); - bool CheckRedeclaration(DeclContext *DC, - DeclarationName Name, - SourceLocation NameLoc, - unsigned Diagnostic); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, bool &Redeclaration); @@ -763,6 +758,12 @@ public: /// struct, or union). virtual void ActOnTagStartDefinition(Scope *S, DeclPtrTy TagDecl); + /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a + /// C++ record definition's base-specifiers clause and are starting its + /// member declarations. + virtual void ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagDecl, + SourceLocation LBraceLoc); + /// ActOnTagFinishDefinition - Invoked once we have finished parsing /// the definition of a tag (enumeration, class, struct, or union). virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl, @@ -841,6 +842,18 @@ public: void MergeVarDecl(VarDecl *New, LookupResult &OldDecls); bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old); + // AssignmentAction - This is used by all the assignment diagnostic functions + // to represent what is actually causing the operation + enum AssignmentAction { + AA_Assigning, + AA_Passing, + AA_Returning, + AA_Converting, + AA_Initializing, + AA_Sending, + AA_Casting + }; + /// C++ Overloading. enum OverloadKind { /// This is a legitimate overload: the existing declarations are @@ -917,9 +930,13 @@ public: TryCopyInitialization(Expr* From, QualType ToType, bool SuppressUserConversions, bool ForceRValue, bool InOverloadResolution); + bool PerformCopyInitialization(Expr *&From, QualType ToType, - const char *Flavor, bool Elidable = false); + AssignmentAction Action, bool Elidable = false); + OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity, + SourceLocation EqualLoc, + OwningExprResult Init); ImplicitConversionSequence TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method, CXXRecordDecl *ActingContext); @@ -1020,27 +1037,23 @@ public: FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain); + FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From); + Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); OwningExprResult FixOverloadedFunctionReference(OwningExprResult, FunctionDecl *Fn); - void AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*>& Callees, - DeclarationName &UnqualifiedName, - bool ArgumentDependentLookup, - const TemplateArgumentListInfo *ExplicitTemplateArgs, + void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, bool PartialOverloading = false); - FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, - llvm::SmallVectorImpl<NamedDecl*> &Fns, - DeclarationName UnqualifiedName, - const TemplateArgumentListInfo *ExplicitTemplateArgs, - SourceLocation LParenLoc, - Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc, - bool ArgumentDependentLookup); + OwningExprResult BuildOverloadedCallExpr(Expr *Fn, + UnresolvedLookupExpr *ULE, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc); OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned Opc, @@ -1133,7 +1146,7 @@ public: // members. LookupOperatorName, /// Look up of a name that precedes the '::' scope resolution - /// operator in C++. This lookup completely ignores operator, + /// operator in C++. This lookup completely ignores operator, object, /// function, and enumerator names (C++ [basic.lookup.qual]p1). LookupNestedNameSpecifierName, /// Look up a namespace name within a C++ using directive or @@ -1164,36 +1177,6 @@ private: bool CppLookupName(LookupResult &R, Scope *S); public: - /// Determines whether D is a suitable lookup result according to the - /// lookup criteria. - static bool isAcceptableLookupResult(NamedDecl *D, LookupNameKind NameKind, - unsigned IDNS) { - switch (NameKind) { - case Sema::LookupOrdinaryName: - case Sema::LookupTagName: - case Sema::LookupMemberName: - case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping - case Sema::LookupUsingDeclName: - case Sema::LookupObjCProtocolName: - case Sema::LookupObjCImplementationName: - return D->isInIdentifierNamespace(IDNS); - - case Sema::LookupOperatorName: - return D->isInIdentifierNamespace(IDNS) && - !D->getDeclContext()->isRecord(); - - case Sema::LookupNestedNameSpecifierName: - return isa<TypedefDecl>(D) || D->isInIdentifierNamespace(Decl::IDNS_Tag); - - case Sema::LookupNamespaceName: - return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D); - } - - assert(false && - "isAcceptableLookupResult always returns before this point"); - return false; - } - /// \brief Look up a name, looking for a single declaration. Return /// null if the results were absent, ambiguous, or overloaded. /// @@ -1215,11 +1198,20 @@ public: void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, FunctionSet &Functions); - + void ArgumentDependentLookup(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, FunctionSet &Functions); + void LookupVisibleDecls(Scope *S, LookupNameKind Kind, + VisibleDeclConsumer &Consumer); + void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, + VisibleDeclConsumer &Consumer); + + bool CorrectTypo(LookupResult &R, Scope *S, const CXXScopeSpec *SS, + DeclContext *MemberContext = 0, + bool EnteringContext = false); + void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, AssociatedNamespaceSet &AssociatedNamespaces, AssociatedClassSet &AssociatedClasses); @@ -1455,7 +1447,8 @@ public: virtual void PopExpressionEvaluationContext(); void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); - + bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD); + // Primary Expressions. virtual SourceRange getExprRange(ExprTy *E) const; @@ -1465,6 +1458,8 @@ public: bool HasTrailingLParen, bool IsAddressOfOperand); + bool DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, LookupResult &R); + OwningExprResult LookupInObjCMethod(LookupResult &R, Scope *S, IdentifierInfo *II); @@ -1485,6 +1480,9 @@ public: FieldDecl *Field, Expr *BaseObjectExpr = 0, SourceLocation OpLoc = SourceLocation()); + OwningExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs); OwningExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, @@ -1611,16 +1609,6 @@ public: Expr **Args, unsigned NumArgs, SourceLocation RParenLoc); - void DeconstructCallFunction(Expr *FnExpr, - llvm::SmallVectorImpl<NamedDecl*>& Fns, - DeclarationName &Name, - NestedNameSpecifier *&Qualifier, - SourceRange &QualifierRange, - bool &ArgumentDependentLookup, - bool &Overloaded, - bool &HasExplicitTemplateArgs, - TemplateArgumentListInfo &ExplicitTemplateArgs); - /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. @@ -1812,7 +1800,8 @@ public: OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, - MultiExprArg Exprs); + MultiExprArg Exprs, + bool RequiresZeroInit = false); // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if // the constructor can be elidable? @@ -1820,7 +1809,8 @@ public: QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, - MultiExprArg Exprs); + MultiExprArg Exprs, + bool RequiresZeroInit = false); OwningExprResult BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Cons, QualType writtenTy, @@ -1972,7 +1962,8 @@ public: bool AllowMissing, FunctionDecl *&Operator); void DeclareGlobalNewDelete(); void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, - QualType Argument); + QualType Argument, + bool addMallocAttr = false); bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, FunctionDecl* &Operator); @@ -2003,9 +1994,10 @@ public: /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is /// non-empty, will create a new CXXExprWithTemporaries expression. /// Otherwise, just returs the passed in expression. - Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, - bool ShouldDestroyTemporaries); - + Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr); + OwningExprResult MaybeCreateCXXExprWithTemporaries(OwningExprResult SubExpr); + FullExpr CreateFullExpr(Expr *SubExpr); + virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr); bool RequireCompleteDeclContext(const CXXScopeSpec &SS); @@ -2216,11 +2208,15 @@ public: SourceLocation RBrac); virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template); + virtual void ActOnStartDelayedMemberDeclarations(Scope *S, + DeclPtrTy Record); virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy Method); virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param); virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy Method); + virtual void ActOnFinishDelayedMemberDeclarations(Scope *S, + DeclPtrTy Record); virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc, ExprArg AssertExpr, @@ -2681,7 +2677,10 @@ public: TDK_TooFewArguments, /// \brief The explicitly-specified template arguments were not valid /// template arguments for the given template. - TDK_InvalidExplicitArguments + TDK_InvalidExplicitArguments, + /// \brief The arguments included an overloaded function name that could + /// not be resolved to a suitable function. + TDK_FailedOverloadResolution }; /// \brief Provides information about an attempted template argument @@ -2795,6 +2794,12 @@ public: CXXConversionDecl *&Specialization, TemplateDeductionInfo &Info); + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + const TemplateArgumentListInfo *ExplicitTemplateArgs, + FunctionDecl *&Specialization, + TemplateDeductionInfo &Info); + FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, TemplatePartialOrderingContext TPOC); @@ -3555,14 +3560,14 @@ public: /// represent it in the AST. Incompatible }; - + /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the /// assignment conversion type specified by ConvTy. This returns true if the /// conversion was invalid or false if the conversion was accepted. bool DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, - Expr *SrcExpr, const char *Flavor); + Expr *SrcExpr, AssignmentAction Action); /// CheckAssignmentConstraints - Perform type checking for assignment, /// argument passing, variable initialization, and function return values. @@ -3597,25 +3602,24 @@ public: bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); bool PerformImplicitConversion(Expr *&From, QualType ToType, - const char *Flavor, + AssignmentAction Action, bool AllowExplicit = false, bool Elidable = false); bool PerformImplicitConversion(Expr *&From, QualType ToType, - const char *Flavor, + AssignmentAction Action, bool AllowExplicit, bool Elidable, ImplicitConversionSequence& ICS); bool PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence& ICS, - const char *Flavor, + AssignmentAction Action, bool IgnoreBaseAccess = false); bool PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, - const char *Flavor, bool IgnoreBaseAccess); + AssignmentAction Action, bool IgnoreBaseAccess); bool BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, - const ImplicitConversionSequence& ICS, - const char *Flavor); + const ImplicitConversionSequence& ICS); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). @@ -3675,15 +3679,10 @@ public: SourceLocation CmpLoc); /// type checking declaration initializers (C99 6.7.8) - - bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType, - SourceLocation InitLoc,DeclarationName InitEntity, - bool DirectInit); - bool CheckInitList(InitListExpr *&InitList, QualType &DeclType); + bool CheckInitList(const InitializedEntity &Entity, + InitListExpr *&InitList, QualType &DeclType); bool CheckForConstantInitializer(Expr *e, QualType t); - bool CheckValueInitialization(QualType Type, SourceLocation Loc); - // type checking C++ declaration initializers (C++ [dcl.init]). /// ReferenceCompareResult - Expresses the result of comparing two diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 21f83a5..b7cc37b 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -37,6 +37,8 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, << MemberDecl << LexicalAS; Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) << PrevMemberDecl << PrevMemberDecl->getAccess(); + + MemberDecl->setAccess(LexicalAS); return true; } diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 814af90..800c544 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -899,7 +899,7 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, // The conversion is possible, so commit to it. Kind = CastExpr::CK_NoOp; msg = 0; - return Self.PerformImplicitConversion(SrcExpr, DestType, ICS, "casting", + return Self.PerformImplicitConversion(SrcExpr, DestType, ICS, Sema::AA_Casting, /*IgnoreBaseAccess*/CStyle) ? TC_Failed : TC_Success; } @@ -959,8 +959,9 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, // as must be the final pointee type. while (SrcType != DestType && Self.UnwrapSimilarPointerTypes(SrcType, DestType)) { - SrcType = SrcType.getUnqualifiedType(); - DestType = DestType.getUnqualifiedType(); + Qualifiers Quals; + SrcType = Self.Context.getUnqualifiedArrayType(SrcType, Quals); + DestType = Self.Context.getUnqualifiedArrayType(DestType, Quals); } // Since we're dealing in canonical types, the remainder must be the same. @@ -975,8 +976,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, const SourceRange &OpRange, unsigned &msg, CastExpr::CastKind &Kind) { - QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); - DestType = Self.Context.getCanonicalType(DestType); QualType SrcType = SrcExpr->getType(); if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) { @@ -1053,8 +1052,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, return TC_NotApplicable; // If both types have the same size, we can successfully cast. - if (Self.Context.getTypeSize(SrcType) == Self.Context.getTypeSize(DestType)) + if (Self.Context.getTypeSize(SrcType) + == Self.Context.getTypeSize(DestType)) { + Kind = CastExpr::CK_BitCast; return TC_Success; + } if (destIsScalar) msg = diag::err_bad_cxx_cast_vector_to_scalar_different_size; @@ -1083,6 +1085,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, // to the same type. However, the behavior of compilers is pretty consistent // on this point: allow same-type conversion if the involved types are // pointers, disallow otherwise. + Kind = CastExpr::CK_NoOp; return TC_Success; } diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 039691f..82d58ea 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -329,7 +329,7 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { /// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in /// that it contains an extra parameter \p ScopeLookupResult, which provides /// the result of name lookup within the scope of the nested-name-specifier -/// that was computed at template definitino time. +/// that was computed at template definition time. /// /// If ErrorRecoveryLookup is true, then this call is used to improve error /// recovery. This means that it should not emit diagnostics, it should @@ -428,6 +428,28 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, } // FIXME: Deal with ambiguities cleanly. + + if (Found.empty() && !ErrorRecoveryLookup) { + // We haven't found anything, and we're not recovering from a + // different kind of error, so look for typos. + DeclarationName Name = Found.getLookupName(); + if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext) && + Found.isSingleResult() && + isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) { + if (LookupCtx) + Diag(Found.getNameLoc(), diag::err_no_member_suggest) + << Name << LookupCtx << Found.getLookupName() << SS.getRange() + << CodeModificationHint::CreateReplacement(Found.getNameLoc(), + Found.getLookupName().getAsString()); + else + Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest) + << Name << Found.getLookupName() + << CodeModificationHint::CreateReplacement(Found.getNameLoc(), + Found.getLookupName().getAsString()); + } else + Found.clear(); + } + NamedDecl *SD = Found.getAsSingle<NamedDecl>(); if (isAcceptableNestedNameSpecifier(SD)) { if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) { @@ -605,15 +627,18 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { /// The 'SS' should be a non-empty valid CXXScopeSpec. bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); - if (DeclContext *DC = computeDeclContext(SS, true)) { - // Before we enter a declarator's context, we need to make sure that - // it is a complete declaration context. - if (!DC->isDependentContext() && RequireCompleteDeclContext(SS)) - return true; - - EnterDeclaratorContext(S, DC); - } - + + if (SS.isInvalid()) return true; + + DeclContext *DC = computeDeclContext(SS, true); + if (!DC) return true; + + // Before we enter a declarator's context, we need to make sure that + // it is a complete declaration context. + if (!DC->isDependentContext() && RequireCompleteDeclContext(SS)) + return true; + + EnterDeclaratorContext(S, DC); return false; } @@ -626,6 +651,7 @@ void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); if (SS.isInvalid()) return; - if (computeDeclContext(SS, true)) - ExitDeclaratorContext(S); + assert(!SS.isInvalid() && computeDeclContext(SS, true) && + "exiting declarator scope we never really entered"); + ExitDeclaratorContext(S); } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 28de500..f10fa07 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -747,6 +747,7 @@ bool Sema::SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall) { /// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr, /// int type). This simply type checks that type is one of the defined /// constants (0-3). +// For compatability check 0-3, llvm only handles 0 and 2. bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) { Expr *Arg = TheCall->getArg(1); if (Arg->isTypeDependent()) @@ -800,7 +801,7 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, switch (E->getStmtClass()) { case Stmt::ConditionalOperatorClass: { const ConditionalOperator *C = cast<ConditionalOperator>(E); - return SemaCheckStringLiteral(C->getLHS(), TheCall, + return SemaCheckStringLiteral(C->getTrueExpr(), TheCall, HasVAListArg, format_idx, firstDataArg) && SemaCheckStringLiteral(C->getRHS(), TheCall, HasVAListArg, format_idx, firstDataArg); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 4ce9330..ef82a94 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -829,6 +829,39 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, } } +/// \brief If the given declaration has an associated type, add it as a result +/// type chunk. +static void AddResultTypeChunk(ASTContext &Context, + NamedDecl *ND, + CodeCompletionString *Result) { + if (!ND) + return; + + // Determine the type of the declaration (if it has a type). + QualType T; + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) + T = Function->getResultType(); + else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) + T = Method->getResultType(); + else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) + T = FunTmpl->getTemplatedDecl()->getResultType(); + else if (EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND)) + T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext())); + else if (isa<UnresolvedUsingValueDecl>(ND)) { + /* Do nothing: ignore unresolved using declarations*/ + } else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND)) + T = Value->getType(); + else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND)) + T = Property->getType(); + + if (T.isNull() || Context.hasSameType(T, Context.DependentTy)) + return; + + std::string TypeStr; + T.getAsStringInternal(TypeStr, Context.PrintingPolicy); + Result->AddResultTypeChunk(TypeStr); +} + /// \brief Add function parameter chunks to the given code completion string. static void AddFunctionParameterChunks(ASTContext &Context, FunctionDecl *Function, @@ -1042,6 +1075,8 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { return Result; } + AddResultTypeChunk(S.Context, ND, Result); + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); @@ -1170,6 +1205,13 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { Result->AddPlaceholderChunk(Arg); } + if (Method->isVariadic()) { + if (AllParametersAreInformative) + Result->AddInformativeChunk(", ..."); + else + Result->AddPlaceholderChunk(", ..."); + } + return Result; } @@ -1189,6 +1231,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( CodeCompletionString *Result = new CodeCompletionString; FunctionDecl *FDecl = getFunction(); + AddResultTypeChunk(S.Context, FDecl, Result); const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(getFunctionType()); if (!FDecl && !Proto) { @@ -1706,33 +1749,24 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, CodeCompleteOrdinaryName(S); return; } - - llvm::SmallVector<NamedDecl*,8> Fns; - DeclarationName UnqualifiedName; - NestedNameSpecifier *Qualifier; - SourceRange QualifierRange; - bool ArgumentDependentLookup; - bool Overloaded; - bool HasExplicitTemplateArgs; - TemplateArgumentListInfo ExplicitTemplateArgs; - - DeconstructCallFunction(Fn, Fns, UnqualifiedName, Qualifier, QualifierRange, - ArgumentDependentLookup, Overloaded, - HasExplicitTemplateArgs, ExplicitTemplateArgs); - + // Build an overload candidate set based on the functions we find. + OverloadCandidateSet CandidateSet; + // FIXME: What if we're calling something that isn't a function declaration? // FIXME: What if we're calling a pseudo-destructor? // FIXME: What if we're calling a member function? - // Build an overload candidate set based on the functions we find. - OverloadCandidateSet CandidateSet; - AddOverloadedCallCandidates(Fns, UnqualifiedName, - ArgumentDependentLookup, - (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0), - Args, NumArgs, - CandidateSet, - /*PartialOverloading=*/true); + Expr *NakedFn = Fn->IgnoreParenCasts(); + if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn)) + AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet, + /*PartialOverloading=*/ true); + else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(NakedFn)) { + FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()); + if (FDecl) + AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet, + false, false, /*PartialOverloading*/ true); + } // Sort the overload candidate set by placing the best overloads first. std::stable_sort(CandidateSet.begin(), CandidateSet.end(), @@ -2419,7 +2453,6 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, typedef CodeCompleteConsumer::Result Result; Expr *RecExpr = static_cast<Expr *>(Receiver); - QualType RecType = RecExpr->getType(); // If necessary, apply function/array conversion to the receiver. // C99 6.7.5.3p[7,8]. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 14d2377..2253f09 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -35,6 +35,7 @@ #include "clang/Lex/HeaderSearch.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" #include <algorithm> #include <cstring> #include <functional> @@ -106,8 +107,12 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS)) return 0; } - - LookupResult Result(*this, &II, NameLoc, LookupOrdinaryName); + + // FIXME: LookupNestedNameSpecifierName isn't the right kind of + // lookup for class-names. + LookupNameKind Kind = isClassName ? LookupNestedNameSpecifierName : + LookupOrdinaryName; + LookupResult Result(*this, &II, NameLoc, Kind); if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access @@ -250,10 +255,41 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, // We don't have anything to suggest (yet). SuggestedType = 0; + // There may have been a typo in the name of the type. Look up typo + // results, in case we have something that we can suggest. + LookupResult Lookup(*this, &II, IILoc, LookupOrdinaryName, + NotForRedeclaration); + + // FIXME: It would be nice if we could correct for typos in built-in + // names, such as "itn" for "int". + + if (CorrectTypo(Lookup, S, SS) && Lookup.isSingleResult()) { + NamedDecl *Result = Lookup.getAsSingle<NamedDecl>(); + if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) && + !Result->isInvalidDecl()) { + // We found a similarly-named type or interface; suggest that. + if (!SS || !SS->isSet()) + Diag(IILoc, diag::err_unknown_typename_suggest) + << &II << Lookup.getLookupName() + << CodeModificationHint::CreateReplacement(SourceRange(IILoc), + Result->getNameAsString()); + else if (DeclContext *DC = computeDeclContext(*SS, false)) + Diag(IILoc, diag::err_unknown_nested_typename_suggest) + << &II << DC << Lookup.getLookupName() << SS->getRange() + << CodeModificationHint::CreateReplacement(SourceRange(IILoc), + Result->getNameAsString()); + else + llvm_unreachable("could not have corrected a typo here"); + + SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS); + return true; + } + } + // FIXME: Should we move the logic that tries to recover from a missing tag // (struct, union, enum) from Parser::ParseImplicitInt here, instead? - if (!SS) + if (!SS || (!SS->isSet() && !SS->isInvalid())) Diag(IILoc, diag::err_unknown_typename) << &II; else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, diag::err_typename_nested_not_found) @@ -321,23 +357,47 @@ void Sema::PopDeclContext() { /// EnterDeclaratorContext - Used when we must lookup names in the context /// of a declarator's nested name specifier. +/// void Sema::EnterDeclaratorContext(Scope *S, DeclContext *DC) { - assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?"); - PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity()); + // C++0x [basic.lookup.unqual]p13: + // A name used in the definition of a static data member of class + // X (after the qualified-id of the static member) is looked up as + // if the name was used in a member function of X. + // C++0x [basic.lookup.unqual]p14: + // If a variable member of a namespace is defined outside of the + // scope of its namespace then any name used in the definition of + // the variable member (after the declarator-id) is looked up as + // if the definition of the variable member occurred in its + // namespace. + // Both of these imply that we should push a scope whose context + // is the semantic context of the declaration. We can't use + // PushDeclContext here because that context is not necessarily + // lexically contained in the current context. Fortunately, + // the containing scope should have the appropriate information. + + assert(!S->getEntity() && "scope already has entity"); + +#ifndef NDEBUG + Scope *Ancestor = S->getParent(); + while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent(); + assert(Ancestor->getEntity() == CurContext && "ancestor context mismatch"); +#endif + CurContext = DC; - assert(CurContext && "No context?"); - S->setEntity(CurContext); + S->setEntity(DC); } void Sema::ExitDeclaratorContext(Scope *S) { - S->setEntity(PreDeclaratorDC); - PreDeclaratorDC = 0; + assert(S->getEntity() == CurContext && "Context imbalance!"); - // Reset CurContext to the nearest enclosing context. - while (!S->getEntity() && S->getParent()) - S = S->getParent(); - CurContext = static_cast<DeclContext*>(S->getEntity()); - assert(CurContext && "No context?"); + // Switch back to the lexical context. The safety of this is + // enforced by an assert in EnterDeclaratorContext. + Scope *Ancestor = S->getParent(); + while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent(); + CurContext = (DeclContext*) Ancestor->getEntity(); + + // We don't need to do anything with the scope, which is going to + // disappear. } /// \brief Determine whether we allow overloading of the function @@ -667,9 +727,8 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { } // Verify the old decl was also a type. - TypeDecl *Old = 0; - if (!OldDecls.isSingleResult() || - !(Old = dyn_cast<TypeDecl>(OldDecls.getFoundDecl()))) { + TypeDecl *Old = OldDecls.getAsSingle<TypeDecl>(); + if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); @@ -704,6 +763,13 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { return New->setInvalidDecl(); } + // The types match. Link up the redeclaration chain if the old + // declaration was a typedef. + // FIXME: this is a potential source of wierdness if the type + // spellings don't match exactly. + if (isa<TypedefDecl>(Old)) + New->setPreviousDeclaration(cast<TypedefDecl>(Old)); + if (getLangOptions().Microsoft) return; @@ -772,7 +838,7 @@ static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx, if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) { if (Ctor->isDefaultConstructor()) return Sema::CXXDefaultConstructor; - if (Ctor->isCopyConstructor(Ctx)) + if (Ctor->isCopyConstructor()) return Sema::CXXCopyConstructor; } @@ -901,7 +967,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // (C++98 8.3.5p3): // All declarations for a function shall agree exactly in both the // return type and the parameter-type-list. - if (OldQType == NewQType) + // attributes should be ignored when comparing. + if (Context.getNoReturnType(OldQType, false) == + Context.getNoReturnType(NewQType, false)) return MergeCompatibleFunctionDecls(New, Old); // Fall through for conflicting redeclarations and redefinitions. @@ -1253,11 +1321,6 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { HasFakeEdge = true; continue; } - if (isa<AsmStmt>(S)) { - HasFakeEdge = true; - HasLiveReturn = true; - continue; - } bool NoReturnEdge = false; if (CallExpr *C = dyn_cast<CallExpr>(S)) { Expr *CEE = C->getCallee()->IgnoreParenCasts(); @@ -1445,7 +1508,6 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { // FIXME: Error on auto/register at file scope // FIXME: Error on inline/virtual/explicit - // FIXME: Error on invalid restrict // FIXME: Warn on useless __thread // FIXME: Warn on useless const/volatile // FIXME: Warn on useless static/extern/typedef/private_extern/mutable @@ -1467,6 +1529,15 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { Tag = dyn_cast<TagDecl>(TagD); } + if (unsigned TypeQuals = DS.getTypeQualifiers()) { + // Enforce C99 6.7.3p2: "Types other than pointer types derived from object + // or incomplete types shall not be restrict-qualified." + if (TypeQuals & DeclSpec::TQ_restrict) + Diag(DS.getRestrictSpecLoc(), + diag::err_typecheck_invalid_restrict_not_pointer_noarg) + << DS.getSourceRange(); + } + if (DS.isFriendSpecified()) { // If we're dealing with a class template decl, assume that the // template routines are handling it. @@ -1516,29 +1587,27 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { return DeclPtrTy::make(Tag); } -/// We are trying to introduce the given name into the given context; +/// We are trying to inject an anonymous member into the given scope; /// check if there's an existing declaration that can't be overloaded. /// /// \return true if this is a forbidden redeclaration -bool Sema::CheckRedeclaration(DeclContext *DC, - DeclarationName Name, - SourceLocation NameLoc, - unsigned diagnostic) { - LookupResult R(*this, Name, NameLoc, LookupOrdinaryName, - ForRedeclaration); - LookupQualifiedName(R, DC); - - if (R.empty()) return false; - - if (R.getResultKind() == LookupResult::Found && - isa<TagDecl>(R.getFoundDecl())) +static bool CheckAnonMemberRedeclaration(Sema &SemaRef, + Scope *S, + DeclarationName Name, + SourceLocation NameLoc, + unsigned diagnostic) { + LookupResult R(SemaRef, Name, NameLoc, Sema::LookupMemberName, + Sema::ForRedeclaration); + if (!SemaRef.LookupName(R, S)) return false; + + if (R.getAsSingle<TagDecl>()) return false; // Pick a representative declaration. - NamedDecl *PrevDecl = (*R.begin())->getUnderlyingDecl(); + NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl(); - Diag(NameLoc, diagnostic) << Name; - Diag(PrevDecl->getLocation(), diag::note_previous_declaration); + SemaRef.Diag(NameLoc, diagnostic) << Name; + SemaRef.Diag(PrevDecl->getLocation(), diag::note_previous_declaration); return true; } @@ -1570,8 +1639,8 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, FEnd = AnonRecord->field_end(); F != FEnd; ++F) { if ((*F)->getDeclName()) { - if (CheckRedeclaration(Owner, (*F)->getDeclName(), - (*F)->getLocation(), diagKind)) { + if (CheckAnonMemberRedeclaration(*this, S, (*F)->getDeclName(), + (*F)->getLocation(), diagKind)) { // C++ [class.union]p2: // The names of the members of an anonymous union shall be // distinct from the names of any other entity in the @@ -1889,9 +1958,12 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, if (DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), true)) { // FIXME: Preserve type source info. QualType T = GetTypeFromParser(DS.getTypeRep()); - EnterDeclaratorContext(S, DC); + + DeclContext *SavedContext = CurContext; + CurContext = DC; T = RebuildTypeInCurrentInstantiation(T, D.getIdentifierLoc(), Name); - ExitDeclaratorContext(S); + CurContext = SavedContext; + if (T.isNull()) return DeclPtrTy(); DS.UpdateTypeRep(T.getAsOpaquePtr()); @@ -3364,7 +3436,16 @@ void Sema::CheckMain(FunctionDecl* FD) { unsigned nparams = FTP->getNumArgs(); assert(FD->getNumParams() == nparams); - if (nparams > 3) { + bool HasExtraParameters = (nparams > 3); + + // Darwin passes an undocumented fourth argument of type char**. If + // other platforms start sprouting these, the logic below will start + // getting shifty. + if (nparams == 4 && + Context.Target.getTriple().getOS() == llvm::Triple::Darwin) + HasExtraParameters = false; + + if (HasExtraParameters) { Diag(FD->getLocation(), diag::err_main_surplus_args) << nparams; FD->setInvalidDecl(true); nparams = 3; @@ -3375,7 +3456,7 @@ void Sema::CheckMain(FunctionDecl* FD) { QualType CharPP = Context.getPointerType(Context.getPointerType(Context.CharTy)); - QualType Expected[] = { Context.IntTy, CharPP, CharPP }; + QualType Expected[] = { Context.IntTy, CharPP, CharPP, CharPP }; for (unsigned i = 0; i < nparams; ++i) { QualType AT = FTP->getArgType(i); @@ -3504,6 +3585,18 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { Expr *Init = init.takeAs<Expr>(); assert(Init && "missing initializer"); + // Capture the variable that is being initialized and the style of + // initialization. + InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); + + // FIXME: Poor source location information. + InitializationKind Kind + = DirectInit? InitializationKind::CreateDirect(VDecl->getLocation(), + Init->getLocStart(), + Init->getLocEnd()) + : InitializationKind::CreateCopy(VDecl->getLocation(), + Init->getLocStart()); + // Get the decls type and save a reference for later, since // CheckInitializerTypes may change it. QualType DclT = VDecl->getType(), SavT = DclT; @@ -3512,37 +3605,16 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); } else if (!VDecl->isInvalidDecl()) { - if (VDecl->getType()->isReferenceType() - || isa<InitListExpr>(Init)) { - InitializedEntity Entity - = InitializedEntity::InitializeVariable(VDecl); - - // FIXME: Poor source location information. - InitializationKind Kind - = DirectInit? InitializationKind::CreateDirect(VDecl->getLocation(), - SourceLocation(), - SourceLocation()) - : InitializationKind::CreateCopy(VDecl->getLocation(), - SourceLocation()); - InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); - if (InitSeq) { - OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, (void**)&Init, 1), - &DclT); - if (Result.isInvalid()) { - VDecl->setInvalidDecl(); - return; - } - - Init = Result.takeAs<Expr>(); - } else { - InitSeq.Diagnose(*this, Entity, Kind, &Init, 1); - VDecl->setInvalidDecl(); - return; - } - } else if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), - VDecl->getDeclName(), DirectInit)) + InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); + OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&Init, 1), + &DclT); + if (Result.isInvalid()) { VDecl->setInvalidDecl(); + return; + } + + Init = Result.takeAs<Expr>(); // C++ 3.6.2p2, allow dynamic initialization of static initializers. // Don't check invalid declarations to avoid emitting useless diagnostics. @@ -3601,10 +3673,18 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { } else if (VDecl->isFileVarDecl()) { if (VDecl->getStorageClass() == VarDecl::Extern) Diag(VDecl->getLocation(), diag::warn_extern_init); - if (!VDecl->isInvalidDecl()) - if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), - VDecl->getDeclName(), DirectInit)) + if (!VDecl->isInvalidDecl()) { + InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); + OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&Init, 1), + &DclT); + if (Result.isInvalid()) { VDecl->setInvalidDecl(); + return; + } + + Init = Result.takeAs<Expr>(); + } // C++ 3.6.2p2, allow dynamic initialization of static initializers. // Don't check invalid declarations to avoid emitting useless diagnostics. @@ -3622,8 +3702,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { Init->setType(DclT); } - Init = MaybeCreateCXXExprWithTemporaries(Init, - /*ShouldDestroyTemporaries=*/true); + Init = MaybeCreateCXXExprWithTemporaries(Init); // Attach the initializer to the decl. VDecl->setInit(Context, Init); @@ -3635,6 +3714,15 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { assert(Deleted && "Unrecorded tentative definition?"); Deleted=Deleted; } + if (getLangOptions().CPlusPlus) { + // Make sure we mark the destructor as used if necessary. + QualType InitType = VDecl->getType(); + if (const ArrayType *Array = Context.getAsArrayType(InitType)) + InitType = Context.getBaseElementType(Array); + if (InitType->isRecordType()) + FinalizeVarWithDestructor(VDecl, InitType); + } + return; } @@ -3722,28 +3810,19 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, InitType->isRecordType() && !InitType->isDependentType()) { if (!RequireCompleteType(Var->getLocation(), InitType, diag::err_invalid_incomplete_type_use)) { - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - - CXXConstructorDecl *Constructor - = PerformInitializationByConstructor(InitType, - MultiExprArg(*this, 0, 0), - Var->getLocation(), - SourceRange(Var->getLocation(), - Var->getLocation()), - Var->getDeclName(), - InitializationKind::CreateDefault(Var->getLocation()), - ConstructorArgs); - - // FIXME: Location info for the variable initialization? - if (!Constructor) + InitializedEntity Entity + = InitializedEntity::InitializeVariable(Var); + InitializationKind Kind + = InitializationKind::CreateDefault(Var->getLocation()); + + InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); + OwningExprResult Init = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, 0, 0)); + if (Init.isInvalid()) Var->setInvalidDecl(); else { - // FIXME: Cope with initialization of arrays - if (!Constructor->isTrivial() && - InitializeVarWithConstructor(Var, Constructor, - move_arg(ConstructorArgs))) - Var->setInvalidDecl(); - + Var->setInit(Context, + MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>())); FinalizeVarWithDestructor(Var, InitType); } } else { @@ -4382,6 +4461,10 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { if (Context.BuiltinInfo.isNoReturn(BuiltinID)) FD->addAttr(::new (Context) NoReturnAttr()); + if (Context.BuiltinInfo.isNoThrow(BuiltinID)) + FD->addAttr(::new (Context) NoThrowAttr()); + if (Context.BuiltinInfo.isConst(BuiltinID)) + FD->addAttr(::new (Context) ConstAttr()); } IdentifierInfo *Name = FD->getIdentifier(); @@ -4939,31 +5022,36 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) { // Enter the tag context. PushDeclContext(S, Tag); +} - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Tag)) { - FieldCollector->StartClass(); - - if (Record->getIdentifier()) { - // C++ [class]p2: - // [...] The class-name is also inserted into the scope of the - // class itself; this is known as the injected-class-name. For - // purposes of access checking, the injected-class-name is treated - // as if it were a public member name. - CXXRecordDecl *InjectedClassName - = CXXRecordDecl::Create(Context, Record->getTagKind(), - CurContext, Record->getLocation(), - Record->getIdentifier(), - Record->getTagKeywordLoc(), - Record); - InjectedClassName->setImplicit(); - InjectedClassName->setAccess(AS_public); - if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) - InjectedClassName->setDescribedClassTemplate(Template); - PushOnScopeChains(InjectedClassName, S); - assert(InjectedClassName->isInjectedClassName() && - "Broken injected-class-name"); - } - } +void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD, + SourceLocation LBraceLoc) { + AdjustDeclIfTemplate(TagD); + CXXRecordDecl *Record = cast<CXXRecordDecl>(TagD.getAs<Decl>()); + + FieldCollector->StartClass(); + + if (!Record->getIdentifier()) + return; + + // C++ [class]p2: + // [...] The class-name is also inserted into the scope of the + // class itself; this is known as the injected-class-name. For + // purposes of access checking, the injected-class-name is treated + // as if it were a public member name. + CXXRecordDecl *InjectedClassName + = CXXRecordDecl::Create(Context, Record->getTagKind(), + CurContext, Record->getLocation(), + Record->getIdentifier(), + Record->getTagKeywordLoc(), + Record); + InjectedClassName->setImplicit(); + InjectedClassName->setAccess(AS_public); + if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) + InjectedClassName->setDescribedClassTemplate(Template); + PushOnScopeChains(InjectedClassName, S); + assert(InjectedClassName->isInjectedClassName() && + "Broken injected-class-name"); } void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, @@ -5808,7 +5896,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, const llvm::APSInt &InitVal = ECD->getInitVal(); assert(InitVal.getBitWidth() >= IntWidth && "Should have promoted value to int"); - if (InitVal.getBitWidth() > IntWidth) { + if (!getLangOptions().CPlusPlus && InitVal.getBitWidth() > IntWidth) { llvm::APSInt V(InitVal); V.trunc(IntWidth); V.extend(InitVal.getBitWidth()); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 84ee207..094e5b5 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -47,7 +47,7 @@ static const FunctionType *getFunctionType(const Decl *d, // FIXME: We should provide an abstraction around a method or function // to provide the following bits of information. -/// isFunctionOrMethod - Return true if the given decl has function +/// isFunction - Return true if the given decl has function /// type (function or function-typed variable). static bool isFunction(const Decl *d) { return getFunctionType(d, false) != NULL; @@ -730,15 +730,19 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) return; } - // TODO: could also be applied to methods? - FunctionDecl *Fn = dyn_cast<FunctionDecl>(D); - if (!Fn) { + if (!isFunctionOrMethod(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 0 /*function*/; return; } - Fn->addAttr(::new (S.Context) WarnUnusedResultAttr()); + if (getFunctionType(D)->getResultType()->isVoidType()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_void_function) + << Attr.getName(); + return; + } + + D->addAttr(::new (S.Context) WarnUnusedResultAttr()); } static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) { @@ -1610,7 +1614,10 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name; return; } - NewTy = S.Context.getFixedWidthIntType(128, OldTy->isSignedIntegerType()); + if (OldTy->isSignedIntegerType()) + NewTy = S.Context.Int128Ty; + else + NewTy = S.Context.UnsignedInt128Ty; break; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 228a716..204d776 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -109,8 +109,6 @@ namespace { bool Sema::SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg, SourceLocation EqualLoc) { - QualType ParamType = Param->getType(); - if (RequireCompleteType(Param->getLocation(), Param->getType(), diag::err_typecheck_decl_incomplete_type)) { Param->setInvalidDecl(); @@ -125,11 +123,17 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg, // the same semantic constraints as the initializer expression in // a declaration of a variable of the parameter type, using the // copy-initialization semantics (8.5). - if (CheckInitializerTypes(Arg, ParamType, EqualLoc, - Param->getDeclName(), /*DirectInit=*/false)) + InitializedEntity Entity = InitializedEntity::InitializeParameter(Param); + InitializationKind Kind = InitializationKind::CreateCopy(Param->getLocation(), + EqualLoc); + InitializationSequence InitSeq(*this, Entity, Kind, &Arg, 1); + OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&Arg, 1)); + if (Result.isInvalid()) return true; + Arg = Result.takeAs<Expr>(); - Arg = MaybeCreateCXXExprWithTemporaries(Arg, /*DestroyTemps=*/false); + Arg = MaybeCreateCXXExprWithTemporaries(Arg); // Okay: add the default argument to the parameter Param->setDefaultArg(Arg); @@ -152,7 +156,6 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, UnparsedDefaultArgLocs.erase(Param); ExprOwningPtr<Expr> DefaultArg(this, defarg.takeAs<Expr>()); - QualType ParamType = Param->getType(); // Default arguments are only permitted in C++ if (!getLangOptions().CPlusPlus) { @@ -945,6 +948,51 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, return DeclPtrTy::make(Member); } +/// \brief Find the direct and/or virtual base specifiers that +/// correspond to the given base type, for use in base initialization +/// within a constructor. +static bool FindBaseInitializer(Sema &SemaRef, + CXXRecordDecl *ClassDecl, + QualType BaseType, + const CXXBaseSpecifier *&DirectBaseSpec, + const CXXBaseSpecifier *&VirtualBaseSpec) { + // First, check for a direct base class. + DirectBaseSpec = 0; + for (CXXRecordDecl::base_class_const_iterator Base + = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + if (SemaRef.Context.hasSameUnqualifiedType(BaseType, Base->getType())) { + // We found a direct base of this type. That's what we're + // initializing. + DirectBaseSpec = &*Base; + break; + } + } + + // Check for a virtual base class. + // FIXME: We might be able to short-circuit this if we know in advance that + // there are no virtual bases. + VirtualBaseSpec = 0; + if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) { + // We haven't found a base yet; search the class hierarchy for a + // virtual base class. + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (SemaRef.IsDerivedFrom(SemaRef.Context.getTypeDeclType(ClassDecl), + BaseType, Paths)) { + for (CXXBasePaths::paths_iterator Path = Paths.begin(); + Path != Paths.end(); ++Path) { + if (Path->back().Base->isVirtual()) { + VirtualBaseSpec = Path->back().Base; + break; + } + } + } + } + + return DirectBaseSpec || VirtualBaseSpec; +} + /// ActOnMemInitializer - Handle a C++ member initializer. Sema::MemInitResult Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, @@ -1000,16 +1048,69 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, } // It didn't name a member, so see if it names a class. QualType BaseType; - TypeSourceInfo *TInfo = 0; - if (TemplateTypeTy) + + if (TemplateTypeTy) { BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo); - else - BaseType = QualType::getFromOpaquePtr(getTypeName(*MemberOrBase, IdLoc, - S, &SS)); - if (BaseType.isNull()) - return Diag(IdLoc, diag::err_mem_init_not_member_or_class) - << MemberOrBase << SourceRange(IdLoc, RParenLoc); + } else { + LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName); + LookupParsedName(R, S, &SS); + + TypeDecl *TyD = R.getAsSingle<TypeDecl>(); + if (!TyD) { + if (R.isAmbiguous()) return true; + + // If no results were found, try to correct typos. + if (R.empty() && + CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) { + if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) { + if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) { + // We have found a non-static data member with a similar + // name to what was typed; complain and initialize that + // member. + Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest) + << MemberOrBase << true << R.getLookupName() + << CodeModificationHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); + + return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, + LParenLoc, RParenLoc); + } + } else if (TypeDecl *Type = R.getAsSingle<TypeDecl>()) { + const CXXBaseSpecifier *DirectBaseSpec; + const CXXBaseSpecifier *VirtualBaseSpec; + if (FindBaseInitializer(*this, ClassDecl, + Context.getTypeDeclType(Type), + DirectBaseSpec, VirtualBaseSpec)) { + // We have found a direct or virtual base class with a + // similar name to what was typed; complain and initialize + // that base class. + Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest) + << MemberOrBase << false << R.getLookupName() + << CodeModificationHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); + + TyD = Type; + } + } + } + + if (!TyD) { + Diag(IdLoc, diag::err_mem_init_not_member_or_class) + << MemberOrBase << SourceRange(IdLoc, RParenLoc); + return true; + } + } + + BaseType = Context.getTypeDeclType(TyD); + if (SS.isSet()) { + NestedNameSpecifier *Qualifier = + static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + + // FIXME: preserve source range information + BaseType = Context.getQualifiedNameType(Qualifier, BaseType); + } + } if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc); @@ -1095,14 +1196,13 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, QualType FieldType = Member->getType(); if (const ArrayType *Array = Context.getAsArrayType(FieldType)) FieldType = Array->getElementType(); + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); if (FieldType->isDependentType()) { // Can't check init for dependent type. } else if (FieldType->isRecordType()) { // Member is a record (struct/union/class), so pass the initializer // arguments down to the record's constructor. if (!HasDependentArg) { - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - C = PerformInitializationByConstructor(FieldType, MultiExprArg(*this, (void**)Args, @@ -1137,7 +1237,8 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, } else NewExp = (Expr*)Args[0]; - if (PerformCopyInitialization(NewExp, FieldType, "passing")) + if (!Member->isInvalidDecl() && + PerformCopyInitialization(NewExp, FieldType, AA_Passing)) return true; Args[0] = NewExp; } @@ -1174,37 +1275,11 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // mem-initializer-list can initialize a base class using any // name that denotes that base class type. - // First, check for a direct base class. + // Check for direct and virtual base classes. const CXXBaseSpecifier *DirectBaseSpec = 0; - for (CXXRecordDecl::base_class_const_iterator Base = - ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) { - if (Context.hasSameUnqualifiedType(BaseType, Base->getType())) { - // We found a direct base of this type. That's what we're - // initializing. - DirectBaseSpec = &*Base; - break; - } - } - - // Check for a virtual base class. - // FIXME: We might be able to short-circuit this if we know in advance that - // there are no virtual bases. const CXXBaseSpecifier *VirtualBaseSpec = 0; - if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) { - // We haven't found a base yet; search the class hierarchy for a - // virtual base class. - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, - /*DetectVirtual=*/false); - if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) { - for (CXXBasePaths::paths_iterator Path = Paths.begin(); - Path != Paths.end(); ++Path) { - if (Path->back().Base->isVirtual()) { - VirtualBaseSpec = Path->back().Base; - break; - } - } - } - } + FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, + VirtualBaseSpec); // C++ [base.class.init]p2: // If a mem-initializer-id is ambiguous because it designates both @@ -1224,10 +1299,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, } CXXConstructorDecl *C = 0; + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); if (!BaseType->isDependentType() && !HasDependentArg) { DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(BaseType).getUnqualifiedType()); - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); C = PerformInitializationByConstructor(BaseType, MultiExprArg(*this, @@ -1977,6 +2052,12 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (!Record || Record->isInvalidDecl()) return; + if (!Record->isDependentType()) + AddImplicitlyDeclaredMembersToClass(Record); + + if (Record->isInvalidDecl()) + return; + if (!Record->isAbstract()) { // Collect all the pure virtual methods and see if this is an abstract // class after all. @@ -1987,9 +2068,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (Record->isAbstract()) (void)AbstractClassUsageDiagnoser(*this, Record); - - if (!Record->isDependentType() && !Record->isInvalidDecl()) - AddImplicitlyDeclaredMembersToClass(Record); } void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, @@ -2261,6 +2339,18 @@ void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) { } } +void Sema::ActOnStartDelayedMemberDeclarations(Scope *S, DeclPtrTy RecordD) { + if (!RecordD) return; + AdjustDeclIfTemplate(RecordD); + CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordD.getAs<Decl>()); + PushDeclContext(S, Record); +} + +void Sema::ActOnFinishDelayedMemberDeclarations(Scope *S, DeclPtrTy RecordD) { + if (!RecordD) return; + PopDeclContext(); +} + /// ActOnStartDelayedCXXMethodDeclaration - We have completed /// parsing a top-level (non-nested) C++ class, and we are now /// parsing those parts of the given Method declaration that could @@ -2270,18 +2360,6 @@ void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) { /// name. However, it should not bring the parameters into scope; /// that will be performed by ActOnDelayedCXXMethodParameter. void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) { - if (!MethodD) - return; - - AdjustDeclIfTemplate(MethodD); - - CXXScopeSpec SS; - FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>()); - QualType ClassTy - = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); - SS.setScopeRep( - NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr())); - ActOnCXXEnterDeclaratorScope(S, SS); } /// ActOnDelayedCXXMethodParameter - We've already started a delayed @@ -2318,12 +2396,6 @@ void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) { AdjustDeclIfTemplate(MethodD); FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>()); - CXXScopeSpec SS; - QualType ClassTy - = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); - SS.setScopeRep( - NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr())); - ActOnCXXExitDeclaratorScope(S, SS); // Now that we have our default arguments, check the constructor // again. It could produce additional diagnostics or affect whether @@ -2746,6 +2818,28 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, PushOnScopeChains(Namespc, DeclRegionScope); } else { // Anonymous namespaces. + assert(Namespc->isAnonymousNamespace()); + CurContext->addDecl(Namespc); + + // Link the anonymous namespace into its parent. + NamespaceDecl *PrevDecl; + DeclContext *Parent = CurContext->getLookupContext(); + if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) { + PrevDecl = TU->getAnonymousNamespace(); + TU->setAnonymousNamespace(Namespc); + } else { + NamespaceDecl *ND = cast<NamespaceDecl>(Parent); + PrevDecl = ND->getAnonymousNamespace(); + ND->setAnonymousNamespace(Namespc); + } + + // Link the anonymous namespace with its previous declaration. + if (PrevDecl) { + assert(PrevDecl->isAnonymousNamespace()); + assert(!PrevDecl->getNextNamespace()); + Namespc->setOriginalNamespace(PrevDecl->getOriginalNamespace()); + PrevDecl->setNextNamespace(Namespc); + } // C++ [namespace.unnamed]p1. An unnamed-namespace-definition // behaves as if it were replaced by @@ -2763,20 +2857,19 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // declarations semantically contained within an anonymous // namespace internal linkage. - assert(Namespc->isAnonymousNamespace()); - CurContext->addDecl(Namespc); - - UsingDirectiveDecl* UD - = UsingDirectiveDecl::Create(Context, CurContext, - /* 'using' */ LBrace, - /* 'namespace' */ SourceLocation(), - /* qualifier */ SourceRange(), - /* NNS */ NULL, - /* identifier */ SourceLocation(), - Namespc, - /* Ancestor */ CurContext); - UD->setImplicit(); - CurContext->addDecl(UD); + if (!PrevDecl) { + UsingDirectiveDecl* UD + = UsingDirectiveDecl::Create(Context, CurContext, + /* 'using' */ LBrace, + /* 'namespace' */ SourceLocation(), + /* qualifier */ SourceRange(), + /* NNS */ NULL, + /* identifier */ SourceLocation(), + Namespc, + /* Ancestor */ CurContext); + UD->setImplicit(); + CurContext->addDecl(UD); + } } // Although we could have an invalid decl (i.e. the namespace name is a @@ -3696,7 +3789,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *CopyConstructor, unsigned TypeQuals) { assert((CopyConstructor->isImplicit() && - CopyConstructor->isCopyConstructor(Context, TypeQuals) && + CopyConstructor->isCopyConstructor(TypeQuals) && !CopyConstructor->isUsed()) && "DefineImplicitCopyConstructor - call it for implicit copy ctor"); @@ -3736,7 +3829,8 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, Sema::OwningExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, - MultiExprArg ExprArgs) { + MultiExprArg ExprArgs, + bool RequiresZeroInit) { bool Elidable = false; // C++ [class.copy]p15: @@ -3747,8 +3841,13 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, // all, even if the class copy constructor or destructor have side effects. // FIXME: Is this enough? - if (Constructor->isCopyConstructor(Context)) { + if (Constructor->isCopyConstructor()) { Expr *E = ((Expr **)ExprArgs.get())[0]; + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) + if (ICE->getCastKind() == CastExpr::CK_NoOp) + E = ICE->getSubExpr(); + if (CXXFunctionalCastExpr *FCE = dyn_cast<CXXFunctionalCastExpr>(E)) + E = FCE->getSubExpr(); while (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E)) E = BE->getSubExpr(); if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) @@ -3759,10 +3858,12 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, Elidable = !CE->getCallReturnType()->isReferenceType(); else if (isa<CXXTemporaryObjectExpr>(E)) Elidable = true; + else if (isa<CXXConstructExpr>(E)) + Elidable = true; } return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, - Elidable, move(ExprArgs)); + Elidable, move(ExprArgs), RequiresZeroInit); } /// BuildCXXConstructExpr - Creates a complete call to a constructor, @@ -3770,13 +3871,15 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, Sema::OwningExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, - MultiExprArg ExprArgs) { + MultiExprArg ExprArgs, + bool RequiresZeroInit) { unsigned NumExprs = ExprArgs.size(); Expr **Exprs = (Expr **)ExprArgs.release(); MarkDeclarationReferenced(ConstructLoc, Constructor); - return Owned(CXXConstructExpr::Create(Context, DeclInitType, Constructor, - Elidable, Exprs, NumExprs)); + return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, + Constructor, Elidable, Exprs, NumExprs, + RequiresZeroInit)); } Sema::OwningExprResult @@ -3806,7 +3909,7 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD, Expr *Temp = TempResult.takeAs<Expr>(); MarkDeclarationReferenced(VD->getLocation(), Constructor); - Temp = MaybeCreateCXXExprWithTemporaries(Temp, /*DestroyTemps=*/true); + Temp = MaybeCreateCXXExprWithTemporaries(Temp); VD->setInit(Context, Temp); return false; @@ -3829,8 +3932,7 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, MultiExprArg Exprs, SourceLocation *CommaLocs, SourceLocation RParenLoc) { - unsigned NumExprs = Exprs.size(); - assert(NumExprs != 0 && Exprs.get() && "missing expressions"); + assert(Exprs.size() != 0 && Exprs.get() && "missing expressions"); Decl *RealDecl = Dcl.getAs<Decl>(); // If there is no declaration, there was an error parsing it. Just ignore @@ -3881,53 +3983,50 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, if (const ArrayType *Array = Context.getAsArrayType(DeclInitType)) DeclInitType = Context.getBaseElementType(Array); - // FIXME: This isn't the right place to complete the type. if (RequireCompleteType(VDecl->getLocation(), VDecl->getType(), diag::err_typecheck_decl_incomplete_type)) { VDecl->setInvalidDecl(); return; } - if (VDecl->getType()->isRecordType()) { - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - - CXXConstructorDecl *Constructor - = PerformInitializationByConstructor(DeclInitType, - move(Exprs), - VDecl->getLocation(), - SourceRange(VDecl->getLocation(), - RParenLoc), - VDecl->getDeclName(), - InitializationKind::CreateDirect(VDecl->getLocation(), - LParenLoc, - RParenLoc), - ConstructorArgs); - if (!Constructor) - RealDecl->setInvalidDecl(); - else { - VDecl->setCXXDirectInitializer(true); - if (InitializeVarWithConstructor(VDecl, Constructor, - move_arg(ConstructorArgs))) - RealDecl->setInvalidDecl(); - FinalizeVarWithDestructor(VDecl, DeclInitType); - } + // The variable can not have an abstract class type. + if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(), + diag::err_abstract_type_in_decl, + AbstractVariableType)) + VDecl->setInvalidDecl(); + + const VarDecl *Def = 0; + if (VDecl->getDefinition(Def)) { + Diag(VDecl->getLocation(), diag::err_redefinition) + << VDecl->getDeclName(); + Diag(Def->getLocation(), diag::note_previous_definition); + VDecl->setInvalidDecl(); return; } - - if (NumExprs > 1) { - Diag(CommaLocs[0], diag::err_builtin_direct_init_more_than_one_arg) - << SourceRange(VDecl->getLocation(), RParenLoc); - RealDecl->setInvalidDecl(); + + // Capture the variable that is being initialized and the style of + // initialization. + InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); + + // FIXME: Poor source location information. + InitializationKind Kind + = InitializationKind::CreateDirect(VDecl->getLocation(), + LParenLoc, RParenLoc); + + InitializationSequence InitSeq(*this, Entity, Kind, + (Expr**)Exprs.get(), Exprs.size()); + OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(Exprs)); + if (Result.isInvalid()) { + VDecl->setInvalidDecl(); return; } - - // Let clients know that initialization was done with a direct initializer. + + Result = MaybeCreateCXXExprWithTemporaries(move(Result)); + VDecl->setInit(Context, Result.takeAs<Expr>()); VDecl->setCXXDirectInitializer(true); - assert(NumExprs == 1 && "Expected 1 expression"); - // Set the init expression, handles conversions. - AddInitializerToDecl(Dcl, ExprArg(*this, Exprs.release()[0]), - /*DirectInit=*/true); + if (VDecl->getType()->getAs<RecordType>()) + FinalizeVarWithDestructor(VDecl, DeclInitType); } /// \brief Add the applicable constructor candidates for an initialization @@ -4164,7 +4263,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, /// type, and the first type (T1) is the pointee type of the reference /// type being initialized. Sema::ReferenceCompareResult -Sema::CompareReferenceRelationship(SourceLocation Loc, +Sema::CompareReferenceRelationship(SourceLocation Loc, QualType OrigT1, QualType OrigT2, bool& DerivedToBase) { assert(!OrigT1->isReferenceType() && @@ -4173,8 +4272,9 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, QualType T1 = Context.getCanonicalType(OrigT1); QualType T2 = Context.getCanonicalType(OrigT2); - QualType UnqualT1 = T1.getLocalUnqualifiedType(); - QualType UnqualT2 = T2.getLocalUnqualifiedType(); + Qualifiers T1Quals, T2Quals; + QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals); + QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals); // C++ [dcl.init.ref]p4: // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is @@ -4192,6 +4292,13 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, // At this point, we know that T1 and T2 are reference-related (at // least). + // If the type is an array type, promote the element qualifiers to the type + // for comparison. + if (isa<ArrayType>(T1) && T1Quals) + T1 = Context.getQualifiedType(UnqualT1, T1Quals); + if (isa<ArrayType>(T2) && T2Quals) + T2 = Context.getQualifiedType(UnqualT2, T2Quals); + // C++ [dcl.init.ref]p4: // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is // reference-related to T2 and cv1 is the same cv-qualification @@ -4199,7 +4306,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, // overload resolution, cases for which cv1 is greater // cv-qualification than cv2 are identified as // reference-compatible with added qualification (see 13.3.3.2). - if (T1.getCVRQualifiers() == T2.getCVRQualifiers()) + if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers()) return Ref_Compatible; else if (T1.isMoreQualifiedThan(T2)) return Ref_Compatible_With_Added_Qualification; @@ -4462,7 +4569,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) { if (!ICS) Diag(DeclLoc, diag::err_not_reference_to_const_init) - << T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value") + << T1 << int(InitLvalue != Expr::LV_Valid) << T2 << Init->getSourceRange(); return true; } @@ -4528,7 +4635,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // initialization fails. if (!ICS) Diag(DeclLoc, diag::err_reference_init_drops_quals) - << T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value") + << T1 << int(InitLvalue != Expr::LV_Valid) << T2 << Init->getSourceRange(); return true; } @@ -4542,7 +4649,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, (T1->isRecordType() || T2->isRecordType())) { if (!ICS) Diag(DeclLoc, diag::err_typecheck_convert_incompatible) - << DeclType << Init->getType() << "initializing" << Init->getSourceRange(); + << DeclType << Init->getType() << AA_Initializing << Init->getSourceRange(); return true; } @@ -4576,7 +4683,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, return ICS->ConversionKind == ImplicitConversionSequence::BadConversion; } else { ImplicitConversionSequence Conversions; - bool badConversion = PerformImplicitConversion(Init, T1, "initializing", + bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing, false, false, Conversions); if (badConversion) { @@ -4664,7 +4771,7 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, << FnDecl->getDeclName() << ExpectedFirstParamType; // Check that the first parameter type is what we expect. - if (SemaRef.Context.getCanonicalType(FirstParamType) != + if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() != ExpectedFirstParamType) return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag) << FnDecl->getDeclName() << ExpectedFirstParamType; @@ -5154,13 +5261,10 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // C++98 [class.friend]p1: A friend of a class is a function // or class that is not a member of the class . . . - // But that's a silly restriction which nobody implements for - // inner classes, and C++0x removes it anyway, so we only report - // this (as a warning) if we're being pedantic. - if (!getLangOptions().CPlusPlus0x) - if (const RecordType *RT = T->getAs<RecordType>()) - if (RT->getDecl()->getDeclContext() == CurContext) - Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class); + // This is fixed in DR77, which just barely didn't make the C++03 + // deadline. It's also a very silly restriction that seriously + // affects inner classes and which nobody else seems to implement; + // thus we never diagnose it, not even in -pedantic. Decl *D; if (TempParams.size()) @@ -5341,6 +5445,9 @@ Sema::ActOnFriendFunctionDecl(Scope *S, FrD->setAccess(AS_public); CurContext->addDecl(FrD); + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) + FrD->setSpecialization(true); + return DeclPtrTy::make(ND); } @@ -5421,6 +5528,18 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, return true; } + // C++ [class.virtual]p6: + // If the return type of D::f differs from the return type of B::f, the + // class type in the return type of D::f shall be complete at the point of + // declaration of D::f or shall be the class type D. + if (const RecordType *RT = NewClassTy->getAs<RecordType>()) { + if (!RT->isBeingDefined() && + RequireCompleteType(New->getLocation(), NewClassTy, + PDiag(diag::err_covariant_return_incomplete) + << New->getDeclName())) + return true; + } + if (!Context.hasSameUnqualifiedType(NewClassTy, OldClassTy)) { // Check if the new class derives from the old class. if (!IsDerivedFrom(NewClassTy, OldClassTy)) { @@ -5497,50 +5616,32 @@ bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) { return true; } -/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an -/// initializer for the declaration 'Dcl'. +/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse +/// an initializer for the out-of-line declaration 'Dcl'. The scope +/// is a fresh scope pushed for just this purpose. +/// /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a /// static data member of class X, names should be looked up in the scope of /// class X. void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) { - AdjustDeclIfTemplate(Dcl); - - Decl *D = Dcl.getAs<Decl>(); // If there is no declaration, there was an error parsing it. - if (D == 0) - return; - - // Check whether it is a declaration with a nested name specifier like - // int foo::bar; - if (!D->isOutOfLine()) - return; - - // C++ [basic.lookup.unqual]p13 - // - // A name used in the definition of a static data member of class X - // (after the qualified-id of the static member) is looked up as if the name - // was used in a member function of X. + Decl *D = Dcl.getAs<Decl>(); + if (D == 0) return; - // Change current context into the context of the initializing declaration. + // We should only get called for declarations with scope specifiers, like: + // int foo::bar; + assert(D->isOutOfLine()); EnterDeclaratorContext(S, D->getDeclContext()); } /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an -/// initializer for the declaration 'Dcl'. +/// initializer for the out-of-line declaration 'Dcl'. void Sema::ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl) { - AdjustDeclIfTemplate(Dcl); - - Decl *D = Dcl.getAs<Decl>(); // If there is no declaration, there was an error parsing it. - if (D == 0) - return; - - // Check whether it is a declaration with a nested name specifier like - // int foo::bar; - if (!D->isOutOfLine()) - return; + Decl *D = Dcl.getAs<Decl>(); + if (D == 0) return; - assert(S->getEntity() == D->getDeclContext() && "Context imbalance!"); + assert(D->isOutOfLine()); ExitDeclaratorContext(S); } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index a768e1b..beadb58 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1950,6 +1950,10 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, !(Attributes & ObjCDeclSpec::DQ_PR_retain) && !(Attributes & ObjCDeclSpec::DQ_PR_copy))); QualType T = GetTypeForDeclarator(FD.D, S); + if (T->isReferenceType()) { + Diag(AtLoc, diag::error_reference_property); + return DeclPtrTy(); + } Decl *ClassDecl = ClassCategory.getAs<Decl>(); ObjCInterfaceDecl *CCPrimary = 0; // continuation class's primary class // May modify Attributes. @@ -2028,7 +2032,14 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), FD.D.getIdentifier(), T); - DC->addDecl(PDecl); + DeclContext::lookup_result Found = DC->lookup(PDecl->getDeclName()); + if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) { + Diag(PDecl->getLocation(), diag::err_duplicate_property); + Diag((*Found.first)->getLocation(), diag::note_property_declare); + PDecl->setInvalidDecl(); + } + else + DC->addDecl(PDecl); if (T->isArrayType() || T->isFunctionType()) { Diag(AtLoc, diag::err_property_type) << T; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 358f445..7bf04d8 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -258,44 +259,17 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) { bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) { DefaultArgumentPromotion(Expr); - if (Expr->getType()->isObjCInterfaceType()) { - switch (ExprEvalContexts.back().Context ) { - case Unevaluated: - // The argument will never be evaluated, so don't complain. - break; - - case PotentiallyEvaluated: - Diag(Expr->getLocStart(), - diag::err_cannot_pass_objc_interface_to_vararg) - << Expr->getType() << CT; - return true; - - case PotentiallyPotentiallyEvaluated: - ExprEvalContexts.back().addDiagnostic(Expr->getLocStart(), - PDiag(diag::err_cannot_pass_objc_interface_to_vararg) - << Expr->getType() << CT); - break; - } - } - - if (!Expr->getType()->isPODType()) { - switch (ExprEvalContexts.back().Context ) { - case Unevaluated: - // The argument will never be evaluated, so don't complain. - break; - - case PotentiallyEvaluated: - Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg) - << Expr->getType() << CT; - break; + if (Expr->getType()->isObjCInterfaceType() && + DiagRuntimeBehavior(Expr->getLocStart(), + PDiag(diag::err_cannot_pass_objc_interface_to_vararg) + << Expr->getType() << CT)) + return true; - case PotentiallyPotentiallyEvaluated: - ExprEvalContexts.back().addDiagnostic(Expr->getLocStart(), - PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) - << Expr->getType() << CT); - break; - } - } + if (!Expr->getType()->isPODType() && + DiagRuntimeBehavior(Expr->getLocStart(), + PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) + << Expr->getType() << CT)) + return true; return false; } @@ -590,7 +564,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, == Context.getCanonicalType(ThisType)) || IsDerivedFrom(ThisType, AnonFieldType)) { // Our base object expression is "this". - BaseObjectExpr = new (Context) CXXThisExpr(SourceLocation(), + BaseObjectExpr = new (Context) CXXThisExpr(Loc, MD->getThisType(Context)); BaseObjectIsPointer = true; } @@ -761,23 +735,9 @@ static bool IsProvablyNotDerivedFrom(Sema &SemaRef, return true; } -/// Determines if this a C++ class member. -static bool IsClassMember(NamedDecl *D) { - DeclContext *DC = D->getDeclContext(); - - // C++0x [class.mem]p1: - // The enumerators of an unscoped enumeration defined in - // the class are members of the class. - // FIXME: support C++0x scoped enumerations. - if (isa<EnumDecl>(DC)) - DC = DC->getParent(); - - return DC->isRecord(); -} - /// Determines if this is an instance member of a class. static bool IsInstanceMember(NamedDecl *D) { - assert(IsClassMember(D) && + assert(D->isCXXClassMember() && "checking whether non-member is instance member"); if (isa<FieldDecl>(D)) return true; @@ -839,7 +799,7 @@ enum IMAKind { /// not be caught until template-instantiation. static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, const LookupResult &R) { - assert(!R.empty() && IsClassMember(*R.begin())); + assert(!R.empty() && (*R.begin())->isCXXClassMember()); bool isStaticContext = (!isa<CXXMethodDecl>(SemaRef.CurContext) || @@ -916,6 +876,112 @@ static void DiagnoseInstanceReference(Sema &SemaRef, SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range; } +/// Diagnose an empty lookup. +/// +/// \return false if new lookup candidates were found +bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, + LookupResult &R) { + DeclarationName Name = R.getLookupName(); + + unsigned diagnostic = diag::err_undeclared_var_use; + unsigned diagnostic_suggest = diag::err_undeclared_var_use_suggest; + if (Name.getNameKind() == DeclarationName::CXXOperatorName || + Name.getNameKind() == DeclarationName::CXXLiteralOperatorName || + Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { + diagnostic = diag::err_undeclared_use; + diagnostic_suggest = diag::err_undeclared_use_suggest; + } + + // If the original lookup was an unqualified lookup, fake an + // unqualified lookup. This is useful when (for example) the + // original lookup would not have found something because it was a + // dependent name. + for (DeclContext *DC = SS.isEmpty()? CurContext : 0; + DC; DC = DC->getParent()) { + if (isa<CXXRecordDecl>(DC)) { + LookupQualifiedName(R, DC); + + if (!R.empty()) { + // Don't give errors about ambiguities in this lookup. + R.suppressDiagnostics(); + + CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(CurContext); + bool isInstance = CurMethod && + CurMethod->isInstance() && + DC == CurMethod->getParent(); + + // Give a code modification hint to insert 'this->'. + // TODO: fixit for inserting 'Base<T>::' in the other cases. + // Actually quite difficult! + if (isInstance) + Diag(R.getNameLoc(), diagnostic) << Name + << CodeModificationHint::CreateInsertion(R.getNameLoc(), + "this->"); + else + Diag(R.getNameLoc(), diagnostic) << Name; + + // Do we really want to note all of these? + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + Diag((*I)->getLocation(), diag::note_dependent_var_use); + + // Tell the callee to try to recover. + return false; + } + } + } + + // We didn't find anything, so try to correct for a typo. + if (S && CorrectTypo(R, S, &SS)) { + if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) { + if (SS.isEmpty()) + Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() + << CodeModificationHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); + else + Diag(R.getNameLoc(), diag::err_no_member_suggest) + << Name << computeDeclContext(SS, false) << R.getLookupName() + << SS.getRange() + << CodeModificationHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); + + // Tell the callee to try to recover. + return false; + } + + if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) { + // FIXME: If we ended up with a typo for a type name or + // Objective-C class name, we're in trouble because the parser + // is in the wrong place to recover. Suggest the typo + // correction, but don't make it a fix-it since we're not going + // to recover well anyway. + if (SS.isEmpty()) + Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName(); + else + Diag(R.getNameLoc(), diag::err_no_member_suggest) + << Name << computeDeclContext(SS, false) << R.getLookupName() + << SS.getRange(); + + // Don't try to recover; it won't work. + return true; + } + + R.clear(); + } + + // Emit a special diagnostic for failed member lookups. + // FIXME: computing the declaration context might fail here (?) + if (!SS.isEmpty()) { + Diag(R.getNameLoc(), diag::err_no_member) + << Name << computeDeclContext(SS, false) + << SS.getRange(); + return true; + } + + // Give up, we can't recover. + Diag(R.getNameLoc(), diagnostic) << Name; + return true; +} + Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, const CXXScopeSpec &SS, UnqualifiedId &Id, @@ -988,17 +1054,11 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. if (R.empty()) { - if (!SS.isEmpty()) - return ExprError(Diag(NameLoc, diag::err_no_member) - << Name << computeDeclContext(SS, false) - << SS.getRange()); - else if (Name.getNameKind() == DeclarationName::CXXOperatorName || - Name.getNameKind() == DeclarationName::CXXLiteralOperatorName || - Name.getNameKind() == DeclarationName::CXXConversionFunctionName) - return ExprError(Diag(NameLoc, diag::err_undeclared_use) - << Name); - else - return ExprError(Diag(NameLoc, diag::err_undeclared_var_use) << Name); + if (DiagnoseEmptyLookup(S, SS, R)) + return ExprError(); + + assert(!R.empty() && + "DiagnoseEmptyLookup returned false but added no results"); } } @@ -1051,35 +1111,10 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // class member access expression. // But note that &SomeClass::foo is grammatically distinct, even // though we don't parse it that way. - if (!R.empty() && IsClassMember(*R.begin())) { + if (!R.empty() && (*R.begin())->isCXXClassMember()) { bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty()); - - if (!isAbstractMemberPointer) { - switch (ClassifyImplicitMemberAccess(*this, R)) { - case IMA_Instance: - return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); - - case IMA_AnonymousMember: - assert(R.isSingleResult()); - return BuildAnonymousStructUnionMemberReference(R.getNameLoc(), - R.getAsSingle<FieldDecl>()); - - case IMA_Mixed: - case IMA_Mixed_Unrelated: - case IMA_Unresolved: - return BuildImplicitMemberExpr(SS, R, TemplateArgs, false); - - case IMA_Static: - case IMA_Mixed_StaticContext: - case IMA_Unresolved_StaticContext: - break; - - case IMA_Error_StaticContext: - case IMA_Error_Unrelated: - DiagnoseInstanceReference(*this, SS, R); - return ExprError(); - } - } + if (!isAbstractMemberPointer) + return BuildPossibleImplicitMemberExpr(SS, R, TemplateArgs); } if (TemplateArgs) @@ -1088,6 +1123,42 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, return BuildDeclarationNameExpr(SS, R, ADL); } +/// Builds an expression which might be an implicit member expression. +Sema::OwningExprResult +Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs) { + switch (ClassifyImplicitMemberAccess(*this, R)) { + case IMA_Instance: + return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); + + case IMA_AnonymousMember: + assert(R.isSingleResult()); + return BuildAnonymousStructUnionMemberReference(R.getNameLoc(), + R.getAsSingle<FieldDecl>()); + + case IMA_Mixed: + case IMA_Mixed_Unrelated: + case IMA_Unresolved: + return BuildImplicitMemberExpr(SS, R, TemplateArgs, false); + + case IMA_Static: + case IMA_Mixed_StaticContext: + case IMA_Unresolved_StaticContext: + if (TemplateArgs) + return BuildTemplateIdExpr(SS, R, false, *TemplateArgs); + return BuildDeclarationNameExpr(SS, R, false); + + case IMA_Error_StaticContext: + case IMA_Error_Unrelated: + DiagnoseInstanceReference(*this, SS, R); + return ExprError(); + } + + llvm_unreachable("unexpected instance member access kind"); + return ExprError(); +} + /// BuildQualifiedDeclarationNameExpr - Build a C++ qualified /// declaration name, generally during template instantiation. /// There's a large number of things which don't need to be done along @@ -1315,7 +1386,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, // -- a declaration of a class member // Since using decls preserve this property, we check this on the // original decl. - if (IsClassMember(D)) + if (D->isCXXClassMember()) return false; // C++0x [basic.lookup.argdep]p3: @@ -1408,7 +1479,6 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, assert(D && "Cannot refer to a NULL declaration"); assert(!isa<FunctionTemplateDecl>(D) && "Cannot refer unambiguously to a function template"); - DeclarationName Name = D->getDeclName(); if (CheckDeclInExpr(*this, Loc, D)) return ExprError(); @@ -1427,7 +1497,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, if (!VD) { Diag(Loc, diag::err_ref_non_value) << D << SS.getRange(); - Diag(D->getLocation(), diag::note_previous_declaration); + Diag(D->getLocation(), diag::note_declared_at); return ExprError(); } @@ -1515,11 +1585,17 @@ Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) { if (Literal.hadError()) return ExprError(); - QualType type = getLangOptions().CPlusPlus ? Context.CharTy : Context.IntTy; + QualType Ty; + if (!getLangOptions().CPlusPlus) + Ty = Context.IntTy; // 'x' and L'x' -> int in C. + else if (Literal.isWide()) + Ty = Context.WCharTy; // L'x' -> wchar_t in C++. + else + Ty = Context.CharTy; // 'x' -> char in C++ return Owned(new (Context) CharacterLiteral(Literal.getValue(), Literal.isWide(), - type, Tok.getLocation())); + Ty, Tok.getLocation())); } Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { @@ -1558,9 +1634,31 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { const llvm::fltSemantics &Format = Context.getFloatTypeSemantics(Ty); - // isExact will be set by GetFloatValue(). - bool isExact = false; - llvm::APFloat Val = Literal.GetFloatValue(Format, &isExact); + using llvm::APFloat; + APFloat Val(Format); + + APFloat::opStatus result = Literal.GetFloatValue(Val); + + // Overflow is always an error, but underflow is only an error if + // we underflowed to zero (APFloat reports denormals as underflow). + if ((result & APFloat::opOverflow) || + ((result & APFloat::opUnderflow) && Val.isZero())) { + unsigned diagnostic; + llvm::SmallVector<char, 20> buffer; + if (result & APFloat::opOverflow) { + diagnostic = diag::err_float_overflow; + APFloat::getLargest(Format).toString(buffer); + } else { + diagnostic = diag::err_float_underflow; + APFloat::getSmallest(Format).toString(buffer); + } + + Diag(Tok.getLocation(), diagnostic) + << Ty + << llvm::StringRef(buffer.data(), buffer.size()); + } + + bool isExact = (result == APFloat::opOK); Res = new (Context) FloatingLiteral(Val, isExact, Ty, Tok.getLocation()); } else if (!Literal.isIntegerLiteral()) { @@ -1698,9 +1796,8 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, } if (RequireCompleteType(OpLoc, exprType, - isSizeof ? diag::err_sizeof_incomplete_type : - PDiag(diag::err_alignof_incomplete_type) - << ExprRange)) + PDiag(diag::err_sizeof_alignof_incomplete_type) + << int(!isSizeof) << ExprRange)) return true; // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode. @@ -2054,20 +2151,12 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, } } - // If this is a halving swizzle, verify that the base type has an even - // number of elements. - if (HalvingSwizzle && (vecType->getNumElements() & 1U)) { - Diag(OpLoc, diag::err_ext_vector_component_requires_even) - << baseType << SourceRange(CompLoc); - return QualType(); - } - // The component accessor looks fine - now we need to compute the actual type. // The vector type is implied by the component accessor. For example, // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc. // vec4.s0 is a float, vec4.s23 is a vec3, etc. // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2. - unsigned CompSize = HalvingSwizzle ? vecType->getNumElements() / 2 + unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2 : CompName->getLength(); if (HexSwizzle) CompSize--; @@ -2277,6 +2366,23 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, // The record definition is complete, now look up the member. SemaRef.LookupQualifiedName(R, DC); + if (!R.empty()) + return false; + + // We didn't find anything with the given name, so try to correct + // for typos. + DeclarationName Name = R.getLookupName(); + if (SemaRef.CorrectTypo(R, 0, &SS, DC) && + (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) { + SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) + << Name << DC << R.getLookupName() << SS.getRange() + << CodeModificationHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); + return false; + } else { + R.clear(); + } + return false; } @@ -2372,6 +2478,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, // result. if (R.isOverloadedResult() || R.isUnresolvableResult()) { bool Dependent = + BaseExprType->isDependentType() || R.isUnresolvableResult() || UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs); @@ -3059,28 +3166,36 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, if (Result.isInvalid()) return ExprError(); - if (SetParamDefaultArgument(Param, move(Result), - /*FIXME:EqualLoc*/ - UninstExpr->getSourceRange().getBegin())) + // Check the expression as an initializer for the parameter. + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Param); + InitializationKind Kind + = InitializationKind::CreateCopy(Param->getLocation(), + /*FIXME:EqualLoc*/UninstExpr->getSourceRange().getBegin()); + Expr *ResultE = Result.takeAs<Expr>(); + + InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1); + Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&ResultE, 1)); + if (Result.isInvalid()) return ExprError(); + + // Build the default argument expression. + return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param, + Result.takeAs<Expr>())); } - Expr *DefaultExpr = Param->getDefaultArg(); - // If the default expression creates temporaries, we need to // push them to the current stack of expression temporaries so they'll // be properly destroyed. - if (CXXExprWithTemporaries *E - = dyn_cast_or_null<CXXExprWithTemporaries>(DefaultExpr)) { - assert(!E->shouldDestroyTemporaries() && - "Can't destroy temporaries in a default argument expr!"); - for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I) - ExprTemporaries.push_back(E->getTemporary(I)); - } + // FIXME: We should really be rebuilding the default argument with new + // bound temporaries; see the comment in PR5810. + for (unsigned i = 0, e = Param->getNumDefaultArgTemporaries(); i != e; ++i) + ExprTemporaries.push_back(Param->getDefaultArgTemporary(i)); } // We already type-checked the argument, so we know it works. - return Owned(CXXDefaultArgExpr::Create(Context, Param)); + return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param)); } /// ConvertArgumentsForCall - Converts the arguments specified in @@ -3169,12 +3284,22 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, << Arg->getSourceRange())) return true; - // Pass the argument. - if (PerformCopyInitialization(Arg, ProtoArgType, "passing")) - return true; + // Pass the argument + ParmVarDecl *Param = 0; + if (FDecl && i < FDecl->getNumParams()) + Param = FDecl->getParamDecl(i); + - if (!ProtoArgType->isReferenceType()) - Arg = MaybeBindToTemporary(Arg).takeAs<Expr>(); + InitializedEntity Entity = + Param? InitializedEntity::InitializeParameter(Param) + : InitializedEntity::InitializeParameter(ProtoArgType); + OwningExprResult ArgE = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(Arg)); + if (ArgE.isInvalid()) + return true; + + Arg = ArgE.takeAs<Expr>(); } else { ParmVarDecl *Param = FDecl->getParamDecl(i); @@ -3200,64 +3325,6 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, return Invalid; } -/// \brief "Deconstruct" the function argument of a call expression to find -/// the underlying declaration (if any), the name of the called function, -/// whether argument-dependent lookup is available, whether it has explicit -/// template arguments, etc. -void Sema::DeconstructCallFunction(Expr *FnExpr, - llvm::SmallVectorImpl<NamedDecl*> &Fns, - DeclarationName &Name, - NestedNameSpecifier *&Qualifier, - SourceRange &QualifierRange, - bool &ArgumentDependentLookup, - bool &Overloaded, - bool &HasExplicitTemplateArguments, - TemplateArgumentListInfo &ExplicitTemplateArgs) { - // Set defaults for all of the output parameters. - Name = DeclarationName(); - Qualifier = 0; - QualifierRange = SourceRange(); - ArgumentDependentLookup = false; - Overloaded = false; - HasExplicitTemplateArguments = false; - - // If we're directly calling a function, get the appropriate declaration. - // Also, in C++, keep track of whether we should perform argument-dependent - // lookup and whether there were any explicitly-specified template arguments. - while (true) { - if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr)) - FnExpr = IcExpr->getSubExpr(); - else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) { - FnExpr = PExpr->getSubExpr(); - } else if (isa<UnaryOperator>(FnExpr) && - cast<UnaryOperator>(FnExpr)->getOpcode() - == UnaryOperator::AddrOf) { - FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr(); - } else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) { - Fns.push_back(cast<NamedDecl>(DRExpr->getDecl())); - ArgumentDependentLookup = false; - if ((Qualifier = DRExpr->getQualifier())) - QualifierRange = DRExpr->getQualifierRange(); - break; - } else if (UnresolvedLookupExpr *UnresLookup - = dyn_cast<UnresolvedLookupExpr>(FnExpr)) { - Name = UnresLookup->getName(); - Fns.append(UnresLookup->decls_begin(), UnresLookup->decls_end()); - ArgumentDependentLookup = UnresLookup->requiresADL(); - Overloaded = UnresLookup->isOverloaded(); - if ((Qualifier = UnresLookup->getQualifier())) - QualifierRange = UnresLookup->getQualifierRange(); - if (UnresLookup->hasExplicitTemplateArgs()) { - HasExplicitTemplateArguments = true; - UnresLookup->copyTemplateArgumentsInto(ExplicitTemplateArgs); - } - break; - } else { - break; - } - } -} - /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. @@ -3372,72 +3439,23 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, // If we're directly calling a function, get the appropriate declaration. // Also, in C++, keep track of whether we should perform argument-dependent // lookup and whether there were any explicitly-specified template arguments. - llvm::SmallVector<NamedDecl*,8> Fns; - DeclarationName UnqualifiedName; - bool Overloaded; - bool ADL; - bool HasExplicitTemplateArgs = 0; - TemplateArgumentListInfo ExplicitTemplateArgs; - NestedNameSpecifier *Qualifier = 0; - SourceRange QualifierRange; - DeconstructCallFunction(Fn, Fns, UnqualifiedName, Qualifier, QualifierRange, - ADL, Overloaded, HasExplicitTemplateArgs, - ExplicitTemplateArgs); - - NamedDecl *NDecl; // the specific declaration we're calling, if applicable - FunctionDecl *FDecl; // same, if it's known to be a function - - if (Overloaded || ADL) { -#ifndef NDEBUG - if (ADL) { - // To do ADL, we must have found an unqualified name. - assert(UnqualifiedName && "found no unqualified name for ADL"); - - // We don't perform ADL for implicit declarations of builtins. - // Verify that this was correctly set up. - if (Fns.size() == 1 && (FDecl = dyn_cast<FunctionDecl>(Fns[0])) && - FDecl->getBuiltinID() && FDecl->isImplicit()) - assert(0 && "performing ADL for builtin"); - - // We don't perform ADL in C. - assert(getLangOptions().CPlusPlus && "ADL enabled in C"); - } - - if (Overloaded) { - // To be overloaded, we must either have multiple functions or - // at least one function template (which is effectively an - // infinite set of functions). - assert((Fns.size() > 1 || - (Fns.size() == 1 && - isa<FunctionTemplateDecl>(Fns[0]->getUnderlyingDecl()))) - && "unrecognized overload situation"); - } -#endif - - FDecl = ResolveOverloadedCallFn(Fn, Fns, UnqualifiedName, - (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0), - LParenLoc, Args, NumArgs, CommaLocs, - RParenLoc, ADL); - if (!FDecl) - return ExprError(); - - Fn = FixOverloadedFunctionReference(Fn, FDecl); - NDecl = FDecl; - } else { - assert(Fns.size() <= 1 && "overloaded without Overloaded flag"); - if (Fns.empty()) - NDecl = 0; - else { - NDecl = Fns[0]; - } + Expr *NakedFn = Fn->IgnoreParens(); + if (isa<UnresolvedLookupExpr>(NakedFn)) { + UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(NakedFn); + return BuildOverloadedCallExpr(Fn, ULE, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc); } + NamedDecl *NDecl = 0; + if (isa<DeclRefExpr>(NakedFn)) + NDecl = cast<DeclRefExpr>(NakedFn)->getDecl(); + return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc); } -/// BuildCallExpr - Build a call to a resolved expression, i.e. an -/// expression not of \p OverloadTy. The expression should +/// BuildResolvedCallExpr - Build a call to a resolved expression, +/// i.e. an expression not of \p OverloadTy. The expression should /// unary-convert to an expression of function-pointer or /// block-pointer type. /// @@ -3547,8 +3565,9 @@ Action::OwningExprResult Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg InitExpr) { assert((Ty != 0) && "ActOnCompoundLiteral(): missing type"); - //FIXME: Preserve type source info. - QualType literalType = GetTypeFromParser(Ty); + + QualType literalType = GetTypeFromParser(Ty); + // FIXME: put back this assert when initializers are worked out. //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression"); Expr *literalExpr = static_cast<Expr*>(InitExpr.get()); @@ -3564,16 +3583,29 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, literalExpr->getSourceRange().getEnd()))) return ExprError(); - if (CheckInitializerTypes(literalExpr, literalType, LParenLoc, - DeclarationName(), /*FIXME:DirectInit=*/false)) + InitializedEntity Entity + = InitializedEntity::InitializeTemporary(literalType); + InitializationKind Kind + = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc), + /*IsCStyleCast=*/true); + InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1); + OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&literalExpr, 1), + &literalType); + if (Result.isInvalid()) return ExprError(); + InitExpr.release(); + literalExpr = static_cast<Expr*>(Result.get()); bool isFileScope = getCurFunctionOrMethodDecl() == 0; if (isFileScope) { // 6.5.2.5p3 if (CheckForConstantInitializer(literalExpr, literalType)) return ExprError(); } - InitExpr.release(); + + Result.release(); + + // FIXME: Store the TInfo to preserve type information better. return Owned(new (Context) CompoundLiteralExpr(LParenLoc, literalType, literalExpr, isFileScope)); } @@ -3600,7 +3632,9 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context, if (SrcTy->hasPointerRepresentation()) { if (DestTy->hasPointerRepresentation()) - return CastExpr::CK_BitCast; + return DestTy->isObjCObjectPointerType() ? + CastExpr::CK_AnyPointerToObjCPointerCast : + CastExpr::CK_BitCast; if (DestTy->isIntegerType()) return CastExpr::CK_PointerToIntegral; } @@ -4632,7 +4666,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // expression is implicitly converted (C++ 4) to the // cv-unqualified type of the left operand. if (PerformImplicitConversion(rExpr, lhsType.getUnqualifiedType(), - "assigning")) + AA_Assigning)) return Incompatible; return Compatible; } @@ -5226,7 +5260,18 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (getLangOptions().CPlusPlus) { if (LCanPointeeTy == RCanPointeeTy) return ResultTy; - + if (!isRelational && + (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) { + // Valid unless comparison between non-null pointer and function pointer + // This is a gcc extension compatibility comparison. + if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType()) + && !LHSIsNull && !RHSIsNull) { + Diag(Loc, diag::ext_typecheck_comparison_of_fptr_to_void) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); + return ResultTy; + } + } // C++ [expr.rel]p2: // [...] Pointer conversions (4.10) and qualification // conversions (4.4) are performed on pointer operands (or on @@ -5503,7 +5548,7 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] return InvalidOperands(Loc, lex, rex); if (PerformImplicitConversion(lex, Context.BoolTy, LHS, - "passing", /*IgnoreBaseAccess=*/false)) + AA_Passing, /*IgnoreBaseAccess=*/false)) return InvalidOperands(Loc, lex, rex); StandardConversionSequence RHS; @@ -5512,7 +5557,7 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] return InvalidOperands(Loc, lex, rex); if (PerformImplicitConversion(rex, Context.BoolTy, RHS, - "passing", /*IgnoreBaseAccess=*/false)) + AA_Passing, /*IgnoreBaseAccess=*/false)) return InvalidOperands(Loc, lex, rex); // C++ [expr.log.and]p2 @@ -5587,6 +5632,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_NoSetterProperty: Diag = diag::error_nosetter_property_assignment; break; + case Expr::MLV_SubObjCPropertySetting: + Diag = diag::error_no_subobject_property_setting; + break; } SourceRange Assign; @@ -5651,7 +5699,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, } if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType, - RHS, "assigning")) + RHS, AA_Assigning)) return QualType(); // C99 6.5.16p3: The type of an assignment expression is the type of the @@ -5734,7 +5782,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, << ResType << Op->getSourceRange(); } else { Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) - << ResType << Op->getSourceRange(); + << ResType << int(isInc) << Op->getSourceRange(); return QualType(); } // At this point, we know we have a real, complex or pointer type. @@ -6478,28 +6526,12 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, // Get the decl corresponding to this. RecordDecl *RD = RC->getDecl(); if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { - if (!CRD->isPOD() && !DidWarnAboutNonPOD) { - switch (ExprEvalContexts.back().Context ) { - case Unevaluated: - // The argument will never be evaluated, so don't complain. - break; - - case PotentiallyEvaluated: - ExprError(Diag(BuiltinLoc, diag::warn_offsetof_non_pod_type) - << SourceRange(CompPtr[0].LocStart, OC.LocEnd) - << Res->getType()); - DidWarnAboutNonPOD = true; - break; - - case PotentiallyPotentiallyEvaluated: - ExprEvalContexts.back().addDiagnostic(BuiltinLoc, - PDiag(diag::warn_offsetof_non_pod_type) - << SourceRange(CompPtr[0].LocStart, OC.LocEnd) - << Res->getType()); - DidWarnAboutNonPOD = true; - break; - } - } + if (!CRD->isPOD() && !DidWarnAboutNonPOD && + DiagRuntimeBehavior(BuiltinLoc, + PDiag(diag::warn_offsetof_non_pod_type) + << SourceRange(CompPtr[0].LocStart, OC.LocEnd) + << Res->getType())) + DidWarnAboutNonPOD = true; } LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName); @@ -6847,7 +6879,7 @@ MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef, bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, - Expr *SrcExpr, const char *Flavor) { + Expr *SrcExpr, AssignmentAction Action) { // Decode the result (notice that AST's are still created for extensions). bool isInvalid = false; unsigned DiagKind; @@ -6910,7 +6942,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, break; } - Diag(Loc, DiagKind) << DstType << SrcType << Flavor + Diag(Loc, DiagKind) << DstType << SrcType << Action << SrcExpr->getSourceRange() << Hint; return isInvalid; } @@ -7053,7 +7085,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (!Constructor->isUsed()) DefineImplicitDefaultConstructor(Loc, Constructor); } else if (Constructor->isImplicit() && - Constructor->isCopyConstructor(Context, TypeQuals)) { + Constructor->isCopyConstructor(TypeQuals)) { if (!Constructor->isUsed()) DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals); } @@ -7120,6 +7152,41 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { } } +/// \brief Emit a diagnostic that describes an effect on the run-time behavior +/// of the program being compiled. +/// +/// This routine emits the given diagnostic when the code currently being +/// type-checked is "potentially evaluated", meaning that there is a +/// possibility that the code will actually be executable. Code in sizeof() +/// expressions, code used only during overload resolution, etc., are not +/// potentially evaluated. This routine will suppress such diagnostics or, +/// in the absolutely nutty case of potentially potentially evaluated +/// expressions (C++ typeid), queue the diagnostic to potentially emit it +/// later. +/// +/// This routine should be used for all diagnostics that describe the run-time +/// behavior of a program, such as passing a non-POD value through an ellipsis. +/// Failure to do so will likely result in spurious diagnostics or failures +/// during overload resolution or within sizeof/alignof/typeof/typeid. +bool Sema::DiagRuntimeBehavior(SourceLocation Loc, + const PartialDiagnostic &PD) { + switch (ExprEvalContexts.back().Context ) { + case Unevaluated: + // The argument will never be evaluated, so don't complain. + break; + + case PotentiallyEvaluated: + Diag(Loc, PD); + return true; + + case PotentiallyPotentiallyEvaluated: + ExprEvalContexts.back().addDiagnostic(Loc, PD); + break; + } + + return false; +} + bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, CallExpr *CE, FunctionDecl *FD) { if (ReturnType->isVoidType() || !ReturnType->isIncompleteType()) diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 6d991b6..5f723f9 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -31,9 +31,29 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, if (!StdNamespace) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); - if (isType) + if (isType) { + // C++ [expr.typeid]p4: + // The top-level cv-qualifiers of the lvalue expression or the type-id + // that is the operand of typeid are always ignored. // FIXME: Preserve type source info. - TyOrExpr = GetTypeFromParser(TyOrExpr).getAsOpaquePtr(); + // FIXME: Preserve the type before we stripped the cv-qualifiers? + QualType T = GetTypeFromParser(TyOrExpr); + if (T.isNull()) + return ExprError(); + + // C++ [expr.typeid]p4: + // If the type of the type-id is a class type or a reference to a class + // type, the class shall be completely-defined. + QualType CheckT = T; + if (const ReferenceType *RefType = CheckT->getAs<ReferenceType>()) + CheckT = RefType->getPointeeType(); + + if (CheckT->getAs<RecordType>() && + RequireCompleteType(OpLoc, CheckT, diag::err_incomplete_typeid)) + return ExprError(); + + TyOrExpr = T.getUnqualifiedType().getAsOpaquePtr(); + } IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); @@ -45,21 +65,36 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl); if (!isType) { - // C++0x [expr.typeid]p3: - // When typeid is applied to an expression other than an lvalue of a - // polymorphic class type [...] [the] expression is an unevaluated - // operand. - - // FIXME: if the type of the expression is a class type, the class - // shall be completely defined. bool isUnevaluatedOperand = true; Expr *E = static_cast<Expr *>(TyOrExpr); - if (E && !E->isTypeDependent() && E->isLvalue(Context) == Expr::LV_Valid) { + if (E && !E->isTypeDependent()) { QualType T = E->getType(); if (const RecordType *RecordT = T->getAs<RecordType>()) { CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl()); - if (RecordD->isPolymorphic()) + // C++ [expr.typeid]p3: + // When typeid is applied to an expression other than an lvalue of a + // polymorphic class type [...] [the] expression is an unevaluated + // operand. [...] + if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) isUnevaluatedOperand = false; + else { + // C++ [expr.typeid]p3: + // [...] If the type of the expression is a class type, the class + // shall be completely-defined. + if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid)) + return ExprError(); + } + } + + // C++ [expr.typeid]p4: + // [...] If the type of the type-id is a reference to a possibly + // cv-qualified type, the result of the typeid expression refers to a + // std::type_info object representing the cv-unqualified referenced + // type. + if (T.hasQualifiers()) { + ImpCastExprToType(E, T.getUnqualifiedType(), CastExpr::CK_NoOp, + E->isLvalue(Context)); + TyOrExpr = E; } } @@ -102,8 +137,15 @@ Sema::ActOnCXXThrow(SourceLocation OpLoc, ExprArg E) { /// CheckCXXThrowOperand - Validate the operand of a throw. bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // C++ [except.throw]p3: - // [...] adjusting the type from "array of T" or "function returning T" - // to "pointer to T" or "pointer to function returning T", [...] + // A throw-expression initializes a temporary object, called the exception + // object, the type of which is determined by removing any top-level + // cv-qualifiers from the static type of the operand of throw and adjusting + // the type from "array of T" or "function returning T" to "pointer to T" + // or "pointer to function returning T", [...] + if (E->getType().hasQualifiers()) + ImpCastExprToType(E, E->getType().getUnqualifiedType(), CastExpr::CK_NoOp, + E->isLvalue(Context) == Expr::LV_Valid); + DefaultFunctionArrayConversion(E); // If the type of the exception would be an incomplete type or a pointer @@ -425,74 +467,61 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, bool Init = ConstructorLParen.isValid(); // --- Choosing a constructor --- - // C++ 5.3.4p15 - // 1) If T is a POD and there's no initializer (ConstructorLParen is invalid) - // the object is not initialized. If the object, or any part of it, is - // const-qualified, it's an error. - // 2) If T is a POD and there's an empty initializer, the object is value- - // initialized. - // 3) If T is a POD and there's one initializer argument, the object is copy- - // constructed. - // 4) If T is a POD and there's more initializer arguments, it's an error. - // 5) If T is not a POD, the initializer arguments are used as constructor - // arguments. - // - // Or by the C++0x formulation: - // 1) If there's no initializer, the object is default-initialized according - // to C++0x rules. - // 2) Otherwise, the object is direct-initialized. CXXConstructorDecl *Constructor = 0; Expr **ConsArgs = (Expr**)ConstructorArgs.get(); - const RecordType *RT; unsigned NumConsArgs = ConstructorArgs.size(); ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this); - if (AllocType->isDependentType() || - Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) { - // Skip all the checks. - } else if ((RT = AllocType->getAs<RecordType>()) && - !AllocType->isAggregateType()) { - InitializationKind InitKind = InitializationKind::CreateDefault(TypeLoc); - if (NumConsArgs > 0) - InitKind = InitializationKind::CreateDirect(TypeLoc, - PlacementLParen, - PlacementRParen); - Constructor = PerformInitializationByConstructor( - AllocType, move(ConstructorArgs), - TypeLoc, - SourceRange(TypeLoc, ConstructorRParen), - RT->getDecl()->getDeclName(), - InitKind, - ConvertedConstructorArgs); - if (!Constructor) + if (!AllocType->isDependentType() && + !Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) { + // C++0x [expr.new]p15: + // A new-expression that creates an object of type T initializes that + // object as follows: + InitializationKind Kind + // - If the new-initializer is omitted, the object is default- + // initialized (8.5); if no initialization is performed, + // the object has indeterminate value + = !Init? InitializationKind::CreateDefault(TypeLoc) + // - Otherwise, the new-initializer is interpreted according to the + // initialization rules of 8.5 for direct-initialization. + : InitializationKind::CreateDirect(TypeLoc, + ConstructorLParen, + ConstructorRParen); + + InitializedEntity Entity + = InitializedEntity::InitializeNew(StartLoc, AllocType); + InitializationSequence InitSeq(*this, Entity, Kind, ConsArgs, NumConsArgs); + OwningExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, + move(ConstructorArgs)); + if (FullInit.isInvalid()) return ExprError(); - - // Take the converted constructor arguments and use them for the new - // expression. - NumConsArgs = ConvertedConstructorArgs.size(); - ConsArgs = (Expr **)ConvertedConstructorArgs.take(); - } else { - if (!Init) { - // FIXME: Check that no subpart is const. - if (AllocType.isConstQualified()) - return ExprError(Diag(StartLoc, diag::err_new_uninitialized_const) - << TypeRange); - } else if (NumConsArgs == 0) { - // Object is value-initialized. Do nothing. - } else if (NumConsArgs == 1) { - // Object is direct-initialized. - // FIXME: What DeclarationName do we pass in here? - if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc, - DeclarationName() /*AllocType.getAsString()*/, - /*DirectInit=*/true)) - return ExprError(); + + // FullInit is our initializer; walk through it to determine if it's a + // constructor call, which CXXNewExpr handles directly. + if (Expr *FullInitExpr = (Expr *)FullInit.get()) { + if (CXXBindTemporaryExpr *Binder + = dyn_cast<CXXBindTemporaryExpr>(FullInitExpr)) + FullInitExpr = Binder->getSubExpr(); + if (CXXConstructExpr *Construct + = dyn_cast<CXXConstructExpr>(FullInitExpr)) { + Constructor = Construct->getConstructor(); + for (CXXConstructExpr::arg_iterator A = Construct->arg_begin(), + AEnd = Construct->arg_end(); + A != AEnd; ++A) + ConvertedConstructorArgs.push_back(A->Retain()); + } else { + // Take the converted initializer. + ConvertedConstructorArgs.push_back(FullInit.release()); + } } else { - return ExprError(Diag(StartLoc, - diag::err_builtin_direct_init_more_than_one_arg) - << SourceRange(ConstructorLParen, ConstructorRParen)); + // No initialization required. } + + // Take the converted arguments and use them for the new expression. + NumConsArgs = ConvertedConstructorArgs.size(); + ConsArgs = (Expr **)ConvertedConstructorArgs.take(); } - + // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) PlacementArgs.release(); @@ -631,10 +660,9 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // Whatch out for variadic allocator function. unsigned NumArgsInFnDecl = FnDecl->getNumParams(); for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) { - // FIXME: Passing word to diagnostic. if (PerformCopyInitialization(Args[i], FnDecl->getParamDecl(i)->getType(), - "passing")) + AA_Passing)) return true; } Operator = FnDecl; @@ -720,13 +748,14 @@ void Sema::DeclareGlobalNewDelete() { QualType VoidPtr = Context.getPointerType(Context.VoidTy); QualType SizeT = Context.getSizeType(); + bool AssumeSaneOperatorNew = getLangOptions().AssumeSaneOperatorNew; DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_New), - VoidPtr, SizeT); + VoidPtr, SizeT, AssumeSaneOperatorNew); DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_Array_New), - VoidPtr, SizeT); + VoidPtr, SizeT, AssumeSaneOperatorNew); DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_Delete), Context.VoidTy, VoidPtr); @@ -738,7 +767,8 @@ void Sema::DeclareGlobalNewDelete() { /// DeclareGlobalAllocationFunction - Declares a single implicit global /// allocation function if it doesn't already exist. void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, - QualType Return, QualType Argument) { + QualType Return, QualType Argument, + bool AddMallocAttr) { DeclContext *GlobalCtx = Context.getTranslationUnitDecl(); // Check if this function is already declared. @@ -749,7 +779,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, // FIXME: Do we need to check for default arguments here? FunctionDecl *Func = cast<FunctionDecl>(*Alloc); if (Func->getNumParams() == 1 && - Context.getCanonicalType(Func->getParamDecl(0)->getType())==Argument) + Context.getCanonicalType( + Func->getParamDecl(0)->getType().getUnqualifiedType()) == Argument) return; } } @@ -771,6 +802,10 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, FnType, /*TInfo=*/0, FunctionDecl::None, false, true); Alloc->setImplicit(); + + if (AddMallocAttr) + Alloc->addAttr(::new (Context) MallocAttr()); + ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), 0, Argument, /*TInfo=*/0, VarDecl::None, 0); @@ -876,7 +911,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, Operand.release(); if (!PerformImplicitConversion(Ex, ObjectPtrConversions.front()->getConversionType(), - "converting")) { + AA_Converting)) { Operand = Owned(Ex); Type = Ex->getType(); } @@ -1027,16 +1062,16 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { /// resolution works differently in that case. bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, - const char *Flavor, bool AllowExplicit, + AssignmentAction Action, bool AllowExplicit, bool Elidable) { ImplicitConversionSequence ICS; - return PerformImplicitConversion(From, ToType, Flavor, AllowExplicit, + return PerformImplicitConversion(From, ToType, Action, AllowExplicit, Elidable, ICS); } bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, - const char *Flavor, bool AllowExplicit, + AssignmentAction Action, bool AllowExplicit, bool Elidable, ImplicitConversionSequence& ICS) { ICS.ConversionKind = ImplicitConversionSequence::BadConversion; @@ -1054,7 +1089,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, /*ForceRValue=*/false, /*InOverloadResolution=*/false); } - return PerformImplicitConversion(From, ToType, ICS, Flavor); + return PerformImplicitConversion(From, ToType, ICS, Action); } /// BuildCXXDerivedToBaseExpr - This routine generates the suitable AST @@ -1062,8 +1097,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, /// necessary information is passed in ICS. bool Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, - const ImplicitConversionSequence& ICS, - const char *Flavor) { + const ImplicitConversionSequence& ICS) { QualType BaseType = QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr); // Must do additional defined to base conversion. @@ -1095,15 +1129,15 @@ Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, /// expression From to the type ToType using the pre-computed implicit /// conversion sequence ICS. Returns true if there was an error, false /// otherwise. The expression From is replaced with the converted -/// expression. Flavor is the kind of conversion we're performing, +/// expression. Action is the kind of conversion we're performing, /// used in the error message. bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence &ICS, - const char* Flavor, bool IgnoreBaseAccess) { + AssignmentAction Action, bool IgnoreBaseAccess) { switch (ICS.ConversionKind) { case ImplicitConversionSequence::StandardConversion: - if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor, + if (PerformImplicitConversion(From, ToType, ICS.Standard, Action, IgnoreBaseAccess)) return true; break; @@ -1136,7 +1170,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // Whatch out for elipsis conversion. if (!ICS.UserDefined.EllipsisConversion) { if (PerformImplicitConversion(From, BeforeToType, - ICS.UserDefined.Before, "converting", + ICS.UserDefined.Before, AA_Converting, IgnoreBaseAccess)) return true; } @@ -1156,7 +1190,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // there's some nasty stuff involving MaybeBindToTemporary going on here. if (ICS.UserDefined.After.Second == ICK_Derived_To_Base && ICS.UserDefined.After.CopyConstructor) { - return BuildCXXDerivedToBaseExpr(From, CastKind, ICS, Flavor); + return BuildCXXDerivedToBaseExpr(From, CastKind, ICS); } if (ICS.UserDefined.After.CopyConstructor) { @@ -1167,7 +1201,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, } return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, - "converting", IgnoreBaseAccess); + AA_Converting, IgnoreBaseAccess); } case ImplicitConversionSequence::EllipsisConversion: @@ -1191,7 +1225,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, - const char *Flavor, bool IgnoreBaseAccess) { + AssignmentAction Action, bool IgnoreBaseAccess) { // Overall FIXME: we are recomputing too many types here and doing far too // much extra work. What this means is that we need to keep track of more // information that is computed when we try the implicit conversion initially, @@ -1323,7 +1357,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // Diagnose incompatible Objective-C conversions Diag(From->getSourceRange().getBegin(), diag::ext_typecheck_convert_incompatible_pointer) - << From->getType() << ToType << Flavor + << From->getType() << ToType << Action << From->getSourceRange(); } @@ -1595,9 +1629,9 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, case OR_Success: // We found a match. Perform the conversions on the arguments and move on. if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0], - Best->Conversions[0], "converting") || + Best->Conversions[0], Sema::AA_Converting) || Self.PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1], - Best->Conversions[1], "converting")) + Best->Conversions[1], Sema::AA_Converting)) break; return false; @@ -1655,7 +1689,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, /*AllowExplicit=*/false, /*ForceRValue=*/false); } - if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, "converting")) + if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, Sema::AA_Converting)) return true; return false; } @@ -1879,9 +1913,9 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, LPointee = Context.getQualifiedType(LPointee, MergedQuals); QualType Common = Context.getMemberPointerType(LPointee, MoreDerived.getTypePtr()); - if (PerformImplicitConversion(LHS, Common, "converting")) + if (PerformImplicitConversion(LHS, Common, Sema::AA_Converting)) return QualType(); - if (PerformImplicitConversion(RHS, Common, "converting")) + if (PerformImplicitConversion(RHS, Common, Sema::AA_Converting)) return QualType(); return Common; } @@ -2046,13 +2080,13 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { && E2ToC2.ConversionKind != ImplicitConversionSequence::BadConversion; if (ToC1Viable && !ToC2Viable) { - if (!PerformImplicitConversion(E1, Composite1, E1ToC1, "converting") && - !PerformImplicitConversion(E2, Composite1, E2ToC1, "converting")) + if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) && + !PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting)) return Composite1; } if (ToC2Viable && !ToC1Viable) { - if (!PerformImplicitConversion(E1, Composite2, E1ToC2, "converting") && - !PerformImplicitConversion(E2, Composite2, E2ToC2, "converting")) + if (!PerformImplicitConversion(E1, Composite2, E1ToC2, Sema::AA_Converting) && + !PerformImplicitConversion(E2, Composite2, E2ToC2, Sema::AA_Converting)) return Composite2; } return QualType(); @@ -2062,6 +2096,8 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!Context.getLangOptions().CPlusPlus) return Owned(E); + assert(!isa<CXXBindTemporaryExpr>(E) && "Double-bound temporary?"); + const RecordType *RT = E->getType()->getAs<RecordType>(); if (!RT) return Owned(E); @@ -2089,8 +2125,7 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E)); } -Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, - bool ShouldDestroyTemps) { +Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr) { assert(SubExpr && "sub expression can't be null!"); unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries; @@ -2100,8 +2135,31 @@ Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr, &ExprTemporaries[FirstTemporary], - ExprTemporaries.size() - FirstTemporary, - ShouldDestroyTemps); + ExprTemporaries.size() - FirstTemporary); + ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary, + ExprTemporaries.end()); + + return E; +} + +Sema::OwningExprResult +Sema::MaybeCreateCXXExprWithTemporaries(OwningExprResult SubExpr) { + if (SubExpr.isInvalid()) + return ExprError(); + + return Owned(MaybeCreateCXXExprWithTemporaries(SubExpr.takeAs<Expr>())); +} + +FullExpr Sema::CreateFullExpr(Expr *SubExpr) { + unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries; + assert(ExprTemporaries.size() >= FirstTemporary); + + unsigned NumTemporaries = ExprTemporaries.size() - FirstTemporary; + CXXTemporary **Temporaries = + NumTemporaries == 0 ? 0 : &ExprTemporaries[FirstTemporary]; + + FullExpr E = FullExpr::Create(Context, SubExpr, Temporaries, NumTemporaries); + ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary, ExprTemporaries.end()); @@ -2243,9 +2301,7 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { Expr *FullExpr = Arg.takeAs<Expr>(); if (FullExpr) - FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr, - /*ShouldDestroyTemps=*/true); - + FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr); return Owned(FullExpr); } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index b78c10b..2e31e47 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -205,7 +205,7 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, IsError |= DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType, - argExpr, "sending"); + argExpr, AA_Sending); } // Promote additional arguments to variadic methods. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 4518465..3ef5156 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -16,11 +16,13 @@ //===----------------------------------------------------------------------===// #include "SemaInit.h" +#include "Lookup.h" #include "Sema.h" #include "clang/Parse/Designator.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/TypeLoc.h" #include "llvm/Support/ErrorHandling.h" #include <map> using namespace clang; @@ -73,7 +75,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, if (S.getLangOptions().CPlusPlus) { // FIXME: I dislike this error message. A lot. if (S.PerformImplicitConversion(Init, DeclType, - "initializing", DirectInit)) { + Sema::AA_Initializing, DirectInit)) { ImplicitConversionSequence ICS; OverloadCandidateSet CandidateSet; if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined, @@ -81,7 +83,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, true, false, false) != OR_Ambiguous) return S.Diag(Init->getSourceRange().getBegin(), diag::err_typecheck_convert_incompatible) - << DeclType << Init->getType() << "initializing" + << DeclType << Init->getType() << Sema::AA_Initializing << Init->getSourceRange(); S.Diag(Init->getSourceRange().getBegin(), diag::err_typecheck_convert_ambiguous) @@ -95,7 +97,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, Sema::AssignConvertType ConvTy = S.CheckSingleAssignmentConstraints(DeclType, Init); return S.DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType, - InitType, Init, "initializing"); + InitType, Init, Sema::AA_Initializing); } static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) { @@ -134,172 +136,6 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) { Str->setType(DeclT); } -bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, - SourceLocation InitLoc, - DeclarationName InitEntity, bool DirectInit) { - if (DeclType->isDependentType() || - Init->isTypeDependent() || Init->isValueDependent()) { - // We have either a dependent type or a type- or value-dependent - // initializer, so we don't perform any additional checking at - // this point. - - // If the declaration is a non-dependent, incomplete array type - // that has an initializer, then its type will be completed once - // the initializer is instantiated. - if (!DeclType->isDependentType()) { - if (const IncompleteArrayType *ArrayT - = Context.getAsIncompleteArrayType(DeclType)) { - if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { - if (!ILE->isTypeDependent()) { - // Compute the constant array type from the length of the - // initializer list. - // FIXME: This will be wrong if there are designated - // initializations. Good thing they don't exist in C++! - llvm::APInt NumElements(Context.getTypeSize(Context.getSizeType()), - ILE->getNumInits()); - llvm::APInt Zero(Context.getTypeSize(Context.getSizeType()), 0); - if (NumElements == Zero) { - // Sizing an array implicitly to zero is not allowed by ISO C, - // but is supported by GNU. - Diag(ILE->getLocStart(), diag::ext_typecheck_zero_array_size); - } - - DeclType = Context.getConstantArrayType(ArrayT->getElementType(), - NumElements, - ArrayT->getSizeModifier(), - ArrayT->getIndexTypeCVRQualifiers()); - return false; - } - } - - // Make the array type-dependent by making it dependently-sized. - DeclType = Context.getDependentSizedArrayType(ArrayT->getElementType(), - /*NumElts=*/0, - ArrayT->getSizeModifier(), - ArrayT->getIndexTypeCVRQualifiers(), - SourceRange()); - } - } - - return false; - } - - // C++ [dcl.init.ref]p1: - // A variable declared to be a T& or T&&, that is "reference to type T" - // (8.3.2), shall be initialized by an object, or function, of - // type T or by an object that can be converted into a T. - if (DeclType->isReferenceType()) - return CheckReferenceInit(Init, DeclType, InitLoc, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/DirectInit, - /*ForceRValue=*/false); - - // C99 6.7.8p3: The type of the entity to be initialized shall be an array - // of unknown size ("[]") or an object type that is not a variable array type. - if (const VariableArrayType *VAT = Context.getAsVariableArrayType(DeclType)) - return Diag(InitLoc, diag::err_variable_object_no_init) - << VAT->getSizeExpr()->getSourceRange(); - - InitListExpr *InitList = dyn_cast<InitListExpr>(Init); - if (!InitList) { - // FIXME: Handle wide strings - if (Expr *Str = IsStringInit(Init, DeclType, Context)) { - CheckStringInit(Str, DeclType, *this); - return false; - } - - // C++ [dcl.init]p14: - // -- If the destination type is a (possibly cv-qualified) class - // type: - if (getLangOptions().CPlusPlus && DeclType->isRecordType()) { - QualType DeclTypeC = Context.getCanonicalType(DeclType); - QualType InitTypeC = Context.getCanonicalType(Init->getType()); - - // -- If the initialization is direct-initialization, or if it is - // copy-initialization where the cv-unqualified version of the - // source type is the same class as, or a derived class of, the - // class of the destination, constructors are considered. - if ((DeclTypeC.getLocalUnqualifiedType() - == InitTypeC.getLocalUnqualifiedType()) || - IsDerivedFrom(InitTypeC, DeclTypeC)) { - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(DeclType->getAs<RecordType>()->getDecl()); - - // No need to make a CXXConstructExpr if both the ctor and dtor are - // trivial. - if (RD->hasTrivialConstructor() && RD->hasTrivialDestructor()) - return false; - - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - - // FIXME: Poor location information - InitializationKind InitKind - = InitializationKind::CreateCopy(Init->getLocStart(), - SourceLocation()); - if (DirectInit) - InitKind = InitializationKind::CreateDirect(Init->getLocStart(), - SourceLocation(), - SourceLocation()); - CXXConstructorDecl *Constructor - = PerformInitializationByConstructor(DeclType, - MultiExprArg(*this, - (void **)&Init, 1), - InitLoc, Init->getSourceRange(), - InitEntity, InitKind, - ConstructorArgs); - if (!Constructor) - return true; - - OwningExprResult InitResult = - BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), - DeclType, Constructor, - move_arg(ConstructorArgs)); - if (InitResult.isInvalid()) - return true; - - Init = InitResult.takeAs<Expr>(); - return false; - } - - // -- Otherwise (i.e., for the remaining copy-initialization - // cases), user-defined conversion sequences that can - // convert from the source type to the destination type or - // (when a conversion function is used) to a derived class - // thereof are enumerated as described in 13.3.1.4, and the - // best one is chosen through overload resolution - // (13.3). If the conversion cannot be done or is - // ambiguous, the initialization is ill-formed. The - // function selected is called with the initializer - // expression as its argument; if the function is a - // constructor, the call initializes a temporary of the - // destination type. - // FIXME: We're pretending to do copy elision here; return to this when we - // have ASTs for such things. - if (!PerformImplicitConversion(Init, DeclType, "initializing")) - return false; - - if (InitEntity) - return Diag(InitLoc, diag::err_cannot_initialize_decl) - << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid) - << Init->getType() << Init->getSourceRange(); - return Diag(InitLoc, diag::err_cannot_initialize_decl_noname) - << DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid) - << Init->getType() << Init->getSourceRange(); - } - - // C99 6.7.8p16. - if (DeclType->isArrayType()) - return Diag(Init->getLocStart(), diag::err_array_init_list_required) - << Init->getSourceRange(); - - return CheckSingleInitializer(Init, DeclType, DirectInit, *this); - } - - bool hadError = CheckInitList(InitList, DeclType); - Init = InitList; - return hadError; -} - //===----------------------------------------------------------------------===// // Semantic checking for initializer lists. //===----------------------------------------------------------------------===// @@ -399,9 +235,14 @@ class InitListChecker { int numArrayElements(QualType DeclType); int numStructUnionElements(QualType DeclType); - void FillInValueInitializations(InitListExpr *ILE); + void FillInValueInitForField(unsigned Init, FieldDecl *Field, + const InitializedEntity &ParentEntity, + InitListExpr *ILE, bool &RequiresSecondPass); + void FillInValueInitializations(const InitializedEntity &Entity, + InitListExpr *ILE, bool &RequiresSecondPass); public: - InitListChecker(Sema &S, InitListExpr *IL, QualType &T); + InitListChecker(Sema &S, const InitializedEntity &Entity, + InitListExpr *IL, QualType &T); bool HadError() { return hadError; } // @brief Retrieves the fully-structured initializer list used for @@ -410,10 +251,75 @@ public: }; } // end anonymous namespace +void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, + const InitializedEntity &ParentEntity, + InitListExpr *ILE, + bool &RequiresSecondPass) { + SourceLocation Loc = ILE->getSourceRange().getBegin(); + unsigned NumInits = ILE->getNumInits(); + InitializedEntity MemberEntity + = InitializedEntity::InitializeMember(Field, &ParentEntity); + if (Init >= NumInits || !ILE->getInit(Init)) { + // FIXME: We probably don't need to handle references + // specially here, since value-initialization of references is + // handled in InitializationSequence. + if (Field->getType()->isReferenceType()) { + // C++ [dcl.init.aggr]p9: + // If an incomplete or empty initializer-list leaves a + // member of reference type uninitialized, the program is + // ill-formed. + SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized) + << Field->getType() + << ILE->getSyntacticForm()->getSourceRange(); + SemaRef.Diag(Field->getLocation(), + diag::note_uninit_reference_member); + hadError = true; + return; + } + + InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, + true); + InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, 0, 0); + if (!InitSeq) { + InitSeq.Diagnose(SemaRef, MemberEntity, Kind, 0, 0); + hadError = true; + return; + } + + Sema::OwningExprResult MemberInit + = InitSeq.Perform(SemaRef, MemberEntity, Kind, + Sema::MultiExprArg(SemaRef, 0, 0)); + if (MemberInit.isInvalid()) { + hadError = true; + return; + } + + if (hadError) { + // Do nothing + } else if (Init < NumInits) { + ILE->setInit(Init, MemberInit.takeAs<Expr>()); + } else if (InitSeq.getKind() + == InitializationSequence::ConstructorInitialization) { + // Value-initialization requires a constructor call, so + // extend the initializer list to include the constructor + // call and make a note that we'll need to take another pass + // through the initializer list. + ILE->updateInit(Init, MemberInit.takeAs<Expr>()); + RequiresSecondPass = true; + } + } else if (InitListExpr *InnerILE + = dyn_cast<InitListExpr>(ILE->getInit(Init))) + FillInValueInitializations(MemberEntity, InnerILE, + RequiresSecondPass); +} + /// Recursively replaces NULL values within the given initializer list /// with expressions that perform value-initialization of the /// appropriate type. -void InitListChecker::FillInValueInitializations(InitListExpr *ILE) { +void +InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, + InitListExpr *ILE, + bool &RequiresSecondPass) { assert((ILE->getType() != SemaRef.Context.VoidTy) && "Should not have void type"); SourceLocation Loc = ILE->getSourceRange().getBegin(); @@ -421,46 +327,32 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) { Loc = ILE->getSyntacticForm()->getSourceRange().getBegin(); if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) { - unsigned Init = 0, NumInits = ILE->getNumInits(); - for (RecordDecl::field_iterator - Field = RType->getDecl()->field_begin(), - FieldEnd = RType->getDecl()->field_end(); - Field != FieldEnd; ++Field) { - if (Field->isUnnamedBitfield()) - continue; - - if (Init >= NumInits || !ILE->getInit(Init)) { - if (Field->getType()->isReferenceType()) { - // C++ [dcl.init.aggr]p9: - // If an incomplete or empty initializer-list leaves a - // member of reference type uninitialized, the program is - // ill-formed. - SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized) - << Field->getType() - << ILE->getSyntacticForm()->getSourceRange(); - SemaRef.Diag(Field->getLocation(), - diag::note_uninit_reference_member); - hadError = true; + if (RType->getDecl()->isUnion() && + ILE->getInitializedFieldInUnion()) + FillInValueInitForField(0, ILE->getInitializedFieldInUnion(), + Entity, ILE, RequiresSecondPass); + else { + unsigned Init = 0; + for (RecordDecl::field_iterator + Field = RType->getDecl()->field_begin(), + FieldEnd = RType->getDecl()->field_end(); + Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + + if (hadError) return; - } else if (SemaRef.CheckValueInitialization(Field->getType(), Loc)) { - hadError = true; + + FillInValueInitForField(Init, *Field, Entity, ILE, RequiresSecondPass); + if (hadError) return; - } - // FIXME: If value-initialization involves calling a constructor, should - // we make that call explicit in the representation (even when it means - // extending the initializer list)? - if (Init < NumInits && !hadError) - ILE->setInit(Init, - new (SemaRef.Context) ImplicitValueInitExpr(Field->getType())); - } else if (InitListExpr *InnerILE - = dyn_cast<InitListExpr>(ILE->getInit(Init))) - FillInValueInitializations(InnerILE); - ++Init; + ++Init; - // Only look at the first initialization of a union. - if (RType->getDecl()->isUnion()) - break; + // Only look at the first initialization of a union. + if (RType->getDecl()->isUnion()) + break; + } } return; @@ -468,39 +360,71 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) { QualType ElementType; + InitializedEntity ElementEntity = Entity; unsigned NumInits = ILE->getNumInits(); unsigned NumElements = NumInits; if (const ArrayType *AType = SemaRef.Context.getAsArrayType(ILE->getType())) { ElementType = AType->getElementType(); if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType)) NumElements = CAType->getSize().getZExtValue(); + ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, + 0, Entity); } else if (const VectorType *VType = ILE->getType()->getAs<VectorType>()) { ElementType = VType->getElementType(); NumElements = VType->getNumElements(); + ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, + 0, Entity); } else ElementType = ILE->getType(); + for (unsigned Init = 0; Init != NumElements; ++Init) { + if (hadError) + return; + + if (ElementEntity.getKind() == InitializedEntity::EK_ArrayOrVectorElement) + ElementEntity.setElementIndex(Init); + if (Init >= NumInits || !ILE->getInit(Init)) { - if (SemaRef.CheckValueInitialization(ElementType, Loc)) { + InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, + true); + InitializationSequence InitSeq(SemaRef, ElementEntity, Kind, 0, 0); + if (!InitSeq) { + InitSeq.Diagnose(SemaRef, ElementEntity, Kind, 0, 0); hadError = true; return; } - // FIXME: If value-initialization involves calling a constructor, should - // we make that call explicit in the representation (even when it means - // extending the initializer list)? - if (Init < NumInits && !hadError) - ILE->setInit(Init, - new (SemaRef.Context) ImplicitValueInitExpr(ElementType)); + Sema::OwningExprResult ElementInit + = InitSeq.Perform(SemaRef, ElementEntity, Kind, + Sema::MultiExprArg(SemaRef, 0, 0)); + if (ElementInit.isInvalid()) { + hadError = true; + return; + } + + if (hadError) { + // Do nothing + } else if (Init < NumInits) { + ILE->setInit(Init, ElementInit.takeAs<Expr>()); + } else if (InitSeq.getKind() + == InitializationSequence::ConstructorInitialization) { + // Value-initialization requires a constructor call, so + // extend the initializer list to include the constructor + // call and make a note that we'll need to take another pass + // through the initializer list. + ILE->updateInit(Init, ElementInit.takeAs<Expr>()); + RequiresSecondPass = true; + } } else if (InitListExpr *InnerILE - = dyn_cast<InitListExpr>(ILE->getInit(Init))) - FillInValueInitializations(InnerILE); + = dyn_cast<InitListExpr>(ILE->getInit(Init))) + FillInValueInitializations(ElementEntity, InnerILE, RequiresSecondPass); } } -InitListChecker::InitListChecker(Sema &S, InitListExpr *IL, QualType &T) +InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, + InitListExpr *IL, QualType &T) : SemaRef(S) { hadError = false; @@ -511,8 +435,13 @@ InitListChecker::InitListChecker(Sema &S, InitListExpr *IL, QualType &T) CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex, /*TopLevelObject=*/true); - if (!hadError) - FillInValueInitializations(FullyStructuredList); + if (!hadError) { + bool RequiresSecondPass = false; + FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass); + if (RequiresSecondPass && !hadError) + FillInValueInitializations(Entity, FullyStructuredList, + RequiresSecondPass); + } } int InitListChecker::numArrayElements(QualType DeclType) { @@ -743,7 +672,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) { if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS, - "initializing")) + Sema::AA_Initializing)) hadError = true; UpdateStructuredListElement(StructuredList, StructuredIndex, expr); ++Index; @@ -783,7 +712,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, } else { // We cannot initialize this element, so let // PerformCopyInitialization produce the appropriate diagnostic. - SemaRef.PerformCopyInitialization(expr, ElemType, "initializing"); + SemaRef.PerformCopyInitialization(expr, ElemType, Sema::AA_Initializing); hadError = true; ++Index; ++StructuredIndex; @@ -1358,22 +1287,33 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, // may find nothing, or may find a member of an anonymous // struct/union. DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName); + FieldDecl *ReplacementField = 0; if (Lookup.first == Lookup.second) { - // Name lookup didn't find anything. - SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) - << FieldName << CurrentObjectType; - ++Index; - return true; - } else if (!KnownField && isa<FieldDecl>(*Lookup.first) && - cast<RecordDecl>((*Lookup.first)->getDeclContext()) - ->isAnonymousStructOrUnion()) { - // Handle an field designator that refers to a member of an - // anonymous struct or union. - ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, - cast<FieldDecl>(*Lookup.first), - Field, FieldIndex); - D = DIE->getDesignator(DesigIdx); - } else { + // Name lookup didn't find anything. Determine whether this + // was a typo for another field name. + LookupResult R(SemaRef, FieldName, D->getFieldLoc(), + Sema::LookupMemberName); + if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl()) && + (ReplacementField = R.getAsSingle<FieldDecl>()) && + ReplacementField->getDeclContext()->getLookupContext() + ->Equals(RT->getDecl())) { + SemaRef.Diag(D->getFieldLoc(), + diag::err_field_designator_unknown_suggest) + << FieldName << CurrentObjectType << R.getLookupName() + << CodeModificationHint::CreateReplacement(D->getFieldLoc(), + R.getLookupName().getAsString()); + } else { + SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) + << FieldName << CurrentObjectType; + ++Index; + return true; + } + } else if (!KnownField) { + // Determine whether we found a field at all. + ReplacementField = dyn_cast<FieldDecl>(*Lookup.first); + } + + if (!ReplacementField) { // Name lookup found something, but it wasn't a field. SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield) << FieldName; @@ -1382,6 +1322,32 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, ++Index; return true; } + + if (!KnownField && + cast<RecordDecl>((ReplacementField)->getDeclContext()) + ->isAnonymousStructOrUnion()) { + // Handle an field designator that refers to a member of an + // anonymous struct or union. + ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, + ReplacementField, + Field, FieldIndex); + D = DIE->getDesignator(DesigIdx); + } else if (!KnownField) { + // The replacement field comes from typo correction; find it + // in the list of fields. + FieldIndex = 0; + Field = RT->getDecl()->field_begin(); + for (; Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + + if (ReplacementField == *Field || + Field->getIdentifier() == ReplacementField->getIdentifier()) + break; + + ++FieldIndex; + } + } } else if (!KnownField && cast<RecordDecl>((*Field)->getDeclContext()) ->isAnonymousStructOrUnion()) { @@ -1844,101 +1810,27 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, return Owned(DIE); } -bool Sema::CheckInitList(InitListExpr *&InitList, QualType &DeclType) { - InitListChecker CheckInitList(*this, InitList, DeclType); +bool Sema::CheckInitList(const InitializedEntity &Entity, + InitListExpr *&InitList, QualType &DeclType) { + InitListChecker CheckInitList(*this, Entity, InitList, DeclType); if (!CheckInitList.HadError()) InitList = CheckInitList.getFullyStructuredList(); return CheckInitList.HadError(); } -/// \brief Diagnose any semantic errors with value-initialization of -/// the given type. -/// -/// Value-initialization effectively zero-initializes any types -/// without user-declared constructors, and calls the default -/// constructor for a for any type that has a user-declared -/// constructor (C++ [dcl.init]p5). Value-initialization can fail when -/// a type with a user-declared constructor does not have an -/// accessible, non-deleted default constructor. In C, everything can -/// be value-initialized, which corresponds to C's notion of -/// initializing objects with static storage duration when no -/// initializer is provided for that object. -/// -/// \returns true if there was an error, false otherwise. -bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) { - // C++ [dcl.init]p5: - // - // To value-initialize an object of type T means: - - // -- if T is an array type, then each element is value-initialized; - if (const ArrayType *AT = Context.getAsArrayType(Type)) - return CheckValueInitialization(AT->getElementType(), Loc); - - if (const RecordType *RT = Type->getAs<RecordType>()) { - if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { - // -- if T is a class type (clause 9) with a user-declared - // constructor (12.1), then the default constructor for T is - // called (and the initialization is ill-formed if T has no - // accessible default constructor); - if (ClassDecl->hasUserDeclaredConstructor()) { - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - - // FIXME: Poor location information - CXXConstructorDecl *Constructor - = PerformInitializationByConstructor(Type, - MultiExprArg(*this, 0, 0), - Loc, SourceRange(Loc), - DeclarationName(), - InitializationKind::CreateValue(Loc, Loc, Loc), - ConstructorArgs); - if (!Constructor) - return true; - - OwningExprResult Init - = BuildCXXConstructExpr(Loc, Type, Constructor, - move_arg(ConstructorArgs)); - if (Init.isInvalid()) - return true; - - // FIXME: Actually perform the value-initialization! - return false; - } - } - } - - if (Type->isReferenceType()) { - // C++ [dcl.init]p5: - // [...] A program that calls for default-initialization or - // value-initialization of an entity of reference type is - // ill-formed. [...] - // FIXME: Once we have code that goes through this path, add an actual - // diagnostic :) - } - - return false; -} - //===----------------------------------------------------------------------===// // Initialization entity //===----------------------------------------------------------------------===// -void InitializedEntity::InitDeclLoc() { - assert((Kind == EK_Variable || Kind == EK_Parameter || Kind == EK_Member) && - "InitDeclLoc cannot be used with non-declaration entities."); - - if (TypeSourceInfo *DI = VariableOrMember->getTypeSourceInfo()) { - TL = DI->getTypeLoc(); - return; - } - - // FIXME: Once we've gone through the effort to create the fake - // TypeSourceInfo, should we cache it in the declaration? - // (If not, we "leak" it). - TypeSourceInfo *DI = VariableOrMember->getASTContext() - .CreateTypeSourceInfo(VariableOrMember->getType()); - DI->getTypeLoc().initialize(VariableOrMember->getLocation()); - TL = DI->getTypeLoc(); +InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, + const InitializedEntity &Parent) + : Kind(EK_ArrayOrVectorElement), Parent(&Parent), Index(Index) +{ + if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) + Type = AT->getElementType(); + else + Type = Parent.getType()->getAs<VectorType>()->getElementType(); } InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, @@ -1947,13 +1839,54 @@ InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, InitializedEntity Result; Result.Kind = EK_Base; Result.Base = Base; - // FIXME: CXXBaseSpecifier should store a TypeLoc. - TypeSourceInfo *DI = Context.CreateTypeSourceInfo(Base->getType()); - DI->getTypeLoc().initialize(Base->getSourceRange().getBegin()); - Result.TL = DI->getTypeLoc(); + Result.Type = Base->getType(); return Result; } +DeclarationName InitializedEntity::getName() const { + switch (getKind()) { + case EK_Parameter: + if (!VariableOrMember) + return DeclarationName(); + // Fall through + + case EK_Variable: + case EK_Member: + return VariableOrMember->getDeclName(); + + case EK_Result: + case EK_Exception: + case EK_New: + case EK_Temporary: + case EK_Base: + case EK_ArrayOrVectorElement: + return DeclarationName(); + } + + // Silence GCC warning + return DeclarationName(); +} + +DeclaratorDecl *InitializedEntity::getDecl() const { + switch (getKind()) { + case EK_Variable: + case EK_Parameter: + case EK_Member: + return VariableOrMember; + + case EK_Result: + case EK_Exception: + case EK_New: + case EK_Temporary: + case EK_Base: + case EK_ArrayOrVectorElement: + return 0; + } + + // Silence GCC warning + return 0; +} + //===----------------------------------------------------------------------===// // Initialization sequence //===----------------------------------------------------------------------===// @@ -1971,6 +1904,8 @@ void InitializationSequence::Step::Destroy() { case SK_ListInitialization: case SK_ConstructorInitialization: case SK_ZeroInitialization: + case SK_CAssignment: + case SK_StringInit: break; case SK_ConversionSequence: @@ -2056,6 +1991,20 @@ void InitializationSequence::AddZeroInitializationStep(QualType T) { Steps.push_back(S); } +void InitializationSequence::AddCAssignmentStep(QualType T) { + Step S; + S.Kind = SK_CAssignment; + S.Type = T; + Steps.push_back(S); +} + +void InitializationSequence::AddStringInitStep(QualType T) { + Step S; + S.Kind = SK_StringInit; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::SetOverloadFailure(FailureKind Failure, OverloadingResult Result) { SequenceKind = FailedSequence; @@ -2081,7 +2030,7 @@ static void TryListInitialization(Sema &S, // force us to perform more checking here. Sequence.setSequenceKind(InitializationSequence::ListInitialization); - QualType DestType = Entity.getType().getType(); + QualType DestType = Entity.getType(); // C++ [dcl.init]p13: // If T is a scalar type, then a declaration of the form @@ -2125,7 +2074,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, Expr *Initializer, bool AllowRValues, InitializationSequence &Sequence) { - QualType DestType = Entity.getType().getType(); + QualType DestType = Entity.getType(); QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); QualType T1 = cv1T1.getUnqualifiedType(); QualType cv2T2 = Initializer->getType(); @@ -2273,7 +2222,7 @@ static void TryReferenceInitialization(Sema &S, InitializationSequence &Sequence) { Sequence.setSequenceKind(InitializationSequence::ReferenceBinding); - QualType DestType = Entity.getType().getType(); + QualType DestType = Entity.getType(); QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); QualType T1 = cv1T1.getUnqualifiedType(); QualType cv2T2 = Initializer->getType(); @@ -2437,7 +2386,12 @@ static void TryReferenceInitialization(Sema &S, // this into an overloading ambiguity diagnostic. However, we need // to keep that set as an OverloadCandidateSet rather than as some // other kind of set. - Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed); + if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + else + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed); return; } @@ -2463,7 +2417,8 @@ static void TryStringLiteralInitialization(Sema &S, const InitializationKind &Kind, Expr *Initializer, InitializationSequence &Sequence) { - // FIXME: Implement! + Sequence.setSequenceKind(InitializationSequence::StringInit); + Sequence.AddStringInitStep(Entity.getType()); } /// \brief Attempt initialization by constructor (C++ [dcl.init]), which @@ -2475,7 +2430,10 @@ static void TryConstructorInitialization(Sema &S, Expr **Args, unsigned NumArgs, QualType DestType, InitializationSequence &Sequence) { - Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization); + if (Kind.getKind() == InitializationKind::IK_Copy) + Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion); + else + Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization); // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. @@ -2512,7 +2470,7 @@ static void TryConstructorInitialization(Sema &S, Constructor = cast<CXXConstructorDecl>(*Con); if (!Constructor->isInvalidDecl() && - Constructor->isConvertingConstructor(AllowExplicit)) { + (AllowExplicit || !Constructor->isExplicit())) { if (ConstructorTmpl) S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, Args, NumArgs, CandidateSet); @@ -2535,9 +2493,13 @@ static void TryConstructorInitialization(Sema &S, // Add the constructor initialization step. Any cv-qualification conversion is // subsumed by the initialization. - Sequence.AddConstructorInitializationStep( + if (Kind.getKind() == InitializationKind::IK_Copy) { + Sequence.AddUserConversionStep(Best->Function, DestType); + } else { + Sequence.AddConstructorInitializationStep( cast<CXXConstructorDecl>(Best->Function), - DestType); + DestType); + } } /// \brief Attempt value initialization (C++ [dcl.init]p7). @@ -2548,7 +2510,7 @@ static void TryValueInitialization(Sema &S, // C++ [dcl.init]p5: // // To value-initialize an object of type T means: - QualType T = Entity.getType().getType(); + QualType T = Entity.getType(); // -- if T is an array type, then each element is value-initialized; while (const ArrayType *AT = S.Context.getAsArrayType(T)) @@ -2566,15 +2528,58 @@ static void TryValueInitialization(Sema &S, if (ClassDecl->hasUserDeclaredConstructor()) return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); - // FIXME: non-union class type w/ non-trivial default constructor gets - // zero-initialized, then constructor gets called. + // -- if T is a (possibly cv-qualified) non-union class type + // without a user-provided constructor, then the object is + // zero-initialized and, if T’s implicitly-declared default + // constructor is non-trivial, that constructor is called. + if ((ClassDecl->getTagKind() == TagDecl::TK_class || + ClassDecl->getTagKind() == TagDecl::TK_struct) && + !ClassDecl->hasTrivialConstructor()) { + Sequence.AddZeroInitializationStep(Entity.getType()); + return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); + } } } - Sequence.AddZeroInitializationStep(Entity.getType().getType()); + Sequence.AddZeroInitializationStep(Entity.getType()); Sequence.setSequenceKind(InitializationSequence::ZeroInitialization); } +/// \brief Attempt default initialization (C++ [dcl.init]p6). +static void TryDefaultInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitializationSequence &Sequence) { + assert(Kind.getKind() == InitializationKind::IK_Default); + + // C++ [dcl.init]p6: + // To default-initialize an object of type T means: + // - if T is an array type, each element is default-initialized; + QualType DestType = Entity.getType(); + while (const ArrayType *Array = S.Context.getAsArrayType(DestType)) + DestType = Array->getElementType(); + + // - if T is a (possibly cv-qualified) class type (Clause 9), the default + // constructor for T is called (and the initialization is ill-formed if + // T has no accessible default constructor); + if (DestType->isRecordType()) { + // FIXME: If a program calls for the default initialization of an object of + // a const-qualified type T, T shall be a class type with a user-provided + // default constructor. + return TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType, + Sequence); + } + + // - otherwise, no initialization is performed. + Sequence.setSequenceKind(InitializationSequence::NoInitialization); + + // If a program calls for the default initialization of an object of + // a const-qualified type T, T shall be a class type with a user-provided + // default constructor. + if (DestType.isConstQualified()) + Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); +} + /// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]), /// which enumerates all conversion functions and performs overload resolution /// to select the best. @@ -2585,7 +2590,7 @@ static void TryUserDefinedConversion(Sema &S, InitializationSequence &Sequence) { Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion); - QualType DestType = Entity.getType().getType(); + QualType DestType = Entity.getType(); assert(!DestType->isReferenceType() && "References are handled elsewhere"); QualType SourceType = Initializer->getType(); assert((DestType->isRecordType() || SourceType->isRecordType()) && @@ -2632,43 +2637,49 @@ static void TryUserDefinedConversion(Sema &S, } } } - + + SourceLocation DeclLoc = Initializer->getLocStart(); + if (const RecordType *SourceRecordType = SourceType->getAs<RecordType>()) { // The type we're converting from is a class type, enumerate its conversion // functions. - CXXRecordDecl *SourceRecordDecl - = cast<CXXRecordDecl>(SourceRecordType->getDecl()); - - const UnresolvedSet *Conversions - = SourceRecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), - E = Conversions->end(); - I != E; ++I) { - NamedDecl *D = *I; - CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); - if (isa<UsingShadowDecl>(D)) - D = cast<UsingShadowDecl>(D)->getTargetDecl(); - - FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D); - CXXConversionDecl *Conv; - if (ConvTemplate) - Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); - else - Conv = cast<CXXConversionDecl>(*I); + + // We can only enumerate the conversion functions for a complete type; if + // the type isn't complete, simply skip this step. + if (!S.RequireCompleteType(DeclLoc, SourceType, 0)) { + CXXRecordDecl *SourceRecordDecl + = cast<CXXRecordDecl>(SourceRecordType->getDecl()); - if (AllowExplicit || !Conv->isExplicit()) { + const UnresolvedSet *Conversions + = SourceRecordDecl->getVisibleConversionFunctions(); + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); + I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D); + CXXConversionDecl *Conv; if (ConvTemplate) - S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer, - DestType, CandidateSet); + Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); else - S.AddConversionCandidate(Conv, ActingDC, Initializer, DestType, - CandidateSet); + Conv = cast<CXXConversionDecl>(*I); + + if (AllowExplicit || !Conv->isExplicit()) { + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, + Initializer, DestType, + CandidateSet); + else + S.AddConversionCandidate(Conv, ActingDC, Initializer, DestType, + CandidateSet); + } } } } - SourceLocation DeclLoc = Initializer->getLocStart(); - // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; if (OverloadingResult Result @@ -2711,7 +2722,7 @@ static void TryImplicitConversion(Sema &S, Expr *Initializer, InitializationSequence &Sequence) { ImplicitConversionSequence ICS - = S.TryImplicitConversion(Initializer, Entity.getType().getType(), + = S.TryImplicitConversion(Initializer, Entity.getType(), /*SuppressUserConversions=*/true, /*AllowExplicit=*/false, /*ForceRValue=*/false, @@ -2723,7 +2734,7 @@ static void TryImplicitConversion(Sema &S, return; } - Sequence.AddConversionSequenceStep(ICS, Entity.getType().getType()); + Sequence.AddConversionSequenceStep(ICS, Entity.getType()); } InitializationSequence::InitializationSequence(Sema &S, @@ -2739,7 +2750,7 @@ InitializationSequence::InitializationSequence(Sema &S, // type is the type of the initializer expression. The source type is not // defined when the initializer is a braced-init-list or when it is a // parenthesized list of expressions. - QualType DestType = Entity.getType().getType(); + QualType DestType = Entity.getType(); if (DestType->isDependentType() || Expr::hasAnyTypeDependentArguments(Args, NumArgs)) { @@ -2749,7 +2760,7 @@ InitializationSequence::InitializationSequence(Sema &S, QualType SourceType; Expr *Initializer = 0; - if (Kind.getKind() == InitializationKind::IK_Copy) { + if (NumArgs == 1) { Initializer = Args[0]; if (!isa<InitListExpr>(Initializer)) SourceType = Initializer->getType(); @@ -2785,11 +2796,18 @@ InitializationSequence::InitializationSequence(Sema &S, } // - If the initializer is (), the object is value-initialized. - if (Kind.getKind() == InitializationKind::IK_Value) { + if (Kind.getKind() == InitializationKind::IK_Value || + (Kind.getKind() == InitializationKind::IK_Direct && NumArgs == 0)) { TryValueInitialization(S, Entity, Kind, *this); return; } + // Handle default initialization. + if (Kind.getKind() == InitializationKind::IK_Default){ + TryDefaultInitialization(S, Entity, Kind, *this); + return; + } + // - Otherwise, if the destination type is an array, the program is // ill-formed. if (const ArrayType *AT = Context.getAsArrayType(DestType)) { @@ -2800,6 +2818,13 @@ InitializationSequence::InitializationSequence(Sema &S, return; } + + // Handle initialization in C + if (!S.getLangOptions().CPlusPlus) { + setSequenceKind(CAssignment); + AddCAssignmentStep(DestType); + return; + } // - If the destination type is a (possibly cv-qualified) class type: if (DestType->isRecordType()) { @@ -2812,7 +2837,7 @@ InitializationSequence::InitializationSequence(Sema &S, (Context.hasSameUnqualifiedType(SourceType, DestType) || S.IsDerivedFrom(SourceType, DestType)))) TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, - Entity.getType().getType(), *this); + Entity.getType(), *this); // - Otherwise (i.e., for the remaining copy-initialization cases), // user-defined conversion sequences that can convert from the source // type to the destination type or (when a conversion function is @@ -2824,9 +2849,15 @@ InitializationSequence::InitializationSequence(Sema &S, return; } + if (NumArgs > 1) { + SetFailed(FK_TooManyInitsForScalar); + return; + } + assert(NumArgs == 1 && "Zero-argument case handled above"); + // - Otherwise, if the source type is a (possibly cv-qualified) class // type, conversion functions are considered. - if (SourceType->isRecordType()) { + if (!SourceType.isNull() && SourceType->isRecordType()) { TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); return; } @@ -2836,6 +2867,7 @@ InitializationSequence::InitializationSequence(Sema &S, // conversions (Clause 4) will be used, if necessary, to convert the // initializer expression to the cv-unqualified version of the // destination type; no user-defined conversions are considered. + setSequenceKind(StandardConversion); TryImplicitConversion(S, Entity, Kind, Initializer, *this); } @@ -2849,6 +2881,158 @@ InitializationSequence::~InitializationSequence() { //===----------------------------------------------------------------------===// // Perform initialization //===----------------------------------------------------------------------===// +static Sema::AssignmentAction +getAssignmentAction(const InitializedEntity &Entity) { + switch(Entity.getKind()) { + case InitializedEntity::EK_Variable: + case InitializedEntity::EK_New: + return Sema::AA_Initializing; + + case InitializedEntity::EK_Parameter: + // FIXME: Can we tell when we're sending vs. passing? + return Sema::AA_Passing; + + case InitializedEntity::EK_Result: + return Sema::AA_Returning; + + case InitializedEntity::EK_Exception: + case InitializedEntity::EK_Base: + llvm_unreachable("No assignment action for C++-specific initialization"); + break; + + case InitializedEntity::EK_Temporary: + // FIXME: Can we tell apart casting vs. converting? + return Sema::AA_Casting; + + case InitializedEntity::EK_Member: + case InitializedEntity::EK_ArrayOrVectorElement: + return Sema::AA_Initializing; + } + + return Sema::AA_Converting; +} + +static bool shouldBindAsTemporary(const InitializedEntity &Entity, + bool IsCopy) { + switch (Entity.getKind()) { + case InitializedEntity::EK_Result: + case InitializedEntity::EK_Exception: + return !IsCopy; + + case InitializedEntity::EK_New: + case InitializedEntity::EK_Variable: + case InitializedEntity::EK_Base: + case InitializedEntity::EK_Member: + case InitializedEntity::EK_ArrayOrVectorElement: + return false; + + case InitializedEntity::EK_Parameter: + case InitializedEntity::EK_Temporary: + return true; + } + + llvm_unreachable("missed an InitializedEntity kind?"); +} + +/// \brief If we need to perform an additional copy of the initialized object +/// for this kind of entity (e.g., the result of a function or an object being +/// thrown), make the copy. +static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Sema::OwningExprResult CurInit) { + SourceLocation Loc; + + switch (Entity.getKind()) { + case InitializedEntity::EK_Result: + if (Entity.getType()->isReferenceType()) + return move(CurInit); + Loc = Entity.getReturnLoc(); + break; + + case InitializedEntity::EK_Exception: + Loc = Entity.getThrowLoc(); + break; + + case InitializedEntity::EK_Variable: + if (Entity.getType()->isReferenceType() || + Kind.getKind() != InitializationKind::IK_Copy) + return move(CurInit); + Loc = Entity.getDecl()->getLocation(); + break; + + case InitializedEntity::EK_Parameter: + // FIXME: Do we need this initialization for a parameter? + return move(CurInit); + + case InitializedEntity::EK_New: + case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_Base: + case InitializedEntity::EK_Member: + case InitializedEntity::EK_ArrayOrVectorElement: + // We don't need to copy for any of these initialized entities. + return move(CurInit); + } + + Expr *CurInitExpr = (Expr *)CurInit.get(); + CXXRecordDecl *Class = 0; + if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>()) + Class = cast<CXXRecordDecl>(Record->getDecl()); + if (!Class) + return move(CurInit); + + // Perform overload resolution using the class's copy constructors. + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( + S.Context.getCanonicalType(S.Context.getTypeDeclType(Class))); + DeclContext::lookup_iterator Con, ConEnd; + OverloadCandidateSet CandidateSet; + for (llvm::tie(Con, ConEnd) = Class->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(*Con); + if (!Constructor || Constructor->isInvalidDecl() || + !Constructor->isCopyConstructor()) + continue; + + S.AddOverloadCandidate(Constructor, &CurInitExpr, 1, CandidateSet); + } + + OverloadCandidateSet::iterator Best; + switch (S.BestViableFunction(CandidateSet, Loc, Best)) { + case OR_Success: + break; + + case OR_No_Viable_Function: + S.Diag(Loc, diag::err_temp_copy_no_viable) + << (int)Entity.getKind() << CurInitExpr->getType() + << CurInitExpr->getSourceRange(); + S.PrintOverloadCandidates(CandidateSet, false); + return S.ExprError(); + + case OR_Ambiguous: + S.Diag(Loc, diag::err_temp_copy_ambiguous) + << (int)Entity.getKind() << CurInitExpr->getType() + << CurInitExpr->getSourceRange(); + S.PrintOverloadCandidates(CandidateSet, true); + return S.ExprError(); + + case OR_Deleted: + S.Diag(Loc, diag::err_temp_copy_deleted) + << (int)Entity.getKind() << CurInitExpr->getType() + << CurInitExpr->getSourceRange(); + S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) + << Best->Function->isDeleted(); + return S.ExprError(); + } + + CurInit.release(); + return S.BuildCXXConstructExpr(Loc, CurInitExpr->getType(), + cast<CXXConstructorDecl>(Best->Function), + /*Elidable=*/true, + Sema::MultiExprArg(S, + (void**)&CurInitExpr, 1)); +} Action::OwningExprResult InitializationSequence::Perform(Sema &S, @@ -2866,9 +3050,9 @@ InitializationSequence::Perform(Sema &S, // If the declaration is a non-dependent, incomplete array type // that has an initializer, then its type will be completed once // the initializer is instantiated. - if (ResultType && !Entity.getType().getType()->isDependentType() && + if (ResultType && !Entity.getType()->isDependentType() && Args.size() == 1) { - QualType DeclType = Entity.getType().getType(); + QualType DeclType = Entity.getType(); if (const IncompleteArrayType *ArrayT = S.Context.getAsIncompleteArrayType(DeclType)) { // FIXME: We don't currently have the ability to accurately @@ -2880,11 +3064,15 @@ InitializationSequence::Perform(Sema &S, // bound. if (isa<InitListExpr>((Expr *)Args.get()[0])) { SourceRange Brackets; + // Scavange the location of the brackets from the entity, if we can. - if (isa<IncompleteArrayTypeLoc>(Entity.getType())) { - IncompleteArrayTypeLoc ArrayLoc - = cast<IncompleteArrayTypeLoc>(Entity.getType()); - Brackets = ArrayLoc.getBracketsRange(); + if (DeclaratorDecl *DD = Entity.getDecl()) { + if (TypeSourceInfo *TInfo = DD->getTypeSourceInfo()) { + TypeLoc TL = TInfo->getTypeLoc(); + if (IncompleteArrayTypeLoc *ArrayLoc + = dyn_cast<IncompleteArrayTypeLoc>(&TL)) + Brackets = ArrayLoc->getBracketsRange(); + } } *ResultType @@ -2898,7 +3086,7 @@ InitializationSequence::Perform(Sema &S, } } - if (Kind.getKind() == InitializationKind::IK_Copy) + if (Kind.getKind() == InitializationKind::IK_Copy || Kind.isExplicitCast()) return Sema::OwningExprResult(S, Args.release()[0]); unsigned NumArgs = Args.size(); @@ -2909,34 +3097,58 @@ InitializationSequence::Perform(Sema &S, SourceLocation())); } - QualType DestType = Entity.getType().getType().getNonReferenceType(); + if (SequenceKind == NoInitialization) + return S.Owned((Expr *)0); + + QualType DestType = Entity.getType().getNonReferenceType(); + // FIXME: Ugly hack around the fact that Entity.getType() is not + // the same as Entity.getDecl()->getType() in cases involving type merging, + // and we want latter when it makes sense. if (ResultType) - *ResultType = Entity.getType().getType(); - - Sema::OwningExprResult CurInit(S); - // For copy initialization and any other initialization forms that - // only have a single initializer, we start with the (only) - // initializer we have. - // FIXME: DPG is not happy about this. There's confusion regarding whether - // we're supposed to start the conversion from the solitary initializer or - // from the set of arguments. - if (Kind.getKind() == InitializationKind::IK_Copy || - SequenceKind != ConstructorInitialization) { + *ResultType = Entity.getDecl() ? Entity.getDecl()->getType() : + Entity.getType(); + + Sema::OwningExprResult CurInit = S.Owned((Expr *)0); + + assert(!Steps.empty() && "Cannot have an empty initialization sequence"); + + // For initialization steps that start with a single initializer, + // grab the only argument out the Args and place it into the "current" + // initializer. + switch (Steps.front().Kind) { + case SK_ResolveAddressOfOverloadedFunction: + case SK_CastDerivedToBaseRValue: + case SK_CastDerivedToBaseLValue: + case SK_BindReference: + case SK_BindReferenceToTemporary: + case SK_UserConversion: + case SK_QualificationConversionLValue: + case SK_QualificationConversionRValue: + case SK_ConversionSequence: + case SK_ListInitialization: + case SK_CAssignment: + case SK_StringInit: assert(Args.size() == 1); - CurInit = Sema::OwningExprResult(S, Args.release()[0]); + CurInit = Sema::OwningExprResult(S, ((Expr **)(Args.get()))[0]->Retain()); if (CurInit.isInvalid()) return S.ExprError(); + break; + + case SK_ConstructorInitialization: + case SK_ZeroInitialization: + break; } // Walk through the computed steps for the initialization sequence, // performing the specified conversions along the way. + bool ConstructorInitRequiresZeroInit = false; for (step_iterator Step = step_begin(), StepEnd = step_end(); Step != StepEnd; ++Step) { if (CurInit.isInvalid()) return S.ExprError(); Expr *CurInitExpr = (Expr *)CurInit.get(); - QualType SourceType = CurInitExpr->getType(); + QualType SourceType = CurInitExpr? CurInitExpr->getType() : QualType(); switch (Step->Kind) { case SK_ResolveAddressOfOverloadedFunction: @@ -2969,7 +3181,7 @@ InitializationSequence::Perform(Sema &S, if (FieldDecl *BitField = CurInitExpr->getBitField()) { // References cannot bind to bit fields (C++ [dcl.init.ref]p5). S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield) - << Entity.getType().getType().isVolatileQualified() + << Entity.getType().isVolatileQualified() << BitField->getDeclName() << CurInitExpr->getSourceRange(); S.Diag(BitField->getLocation(), diag::note_bitfield_decl); @@ -2996,6 +3208,7 @@ InitializationSequence::Perform(Sema &S, // We have a user-defined conversion that invokes either a constructor // or a conversion function. CastExpr::CastKind CastKind = CastExpr::CK_Unknown; + bool IsCopy = false; if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Step->Function)) { // Build a call to the selected constructor. @@ -3019,10 +3232,14 @@ InitializationSequence::Perform(Sema &S, return S.ExprError(); CastKind = CastExpr::CK_ConstructorConversion; + QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); + if (S.Context.hasSameUnqualifiedType(SourceType, Class) || + S.IsDerivedFrom(SourceType, Class)) + IsCopy = true; } else { // Build a call to the conversion function. CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Step->Function); - + // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because // we don't want to turn off access control here for c-style casts. @@ -3041,12 +3258,17 @@ InitializationSequence::Perform(Sema &S, CastKind = CastExpr::CK_UserDefinedConversion; } - CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + if (shouldBindAsTemporary(Entity, IsCopy)) + CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + CurInitExpr = CurInit.takeAs<Expr>(); CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(), CastKind, CurInitExpr, - false)); + false)); + + if (!IsCopy) + CurInit = CopyIfRequiredForEntity(S, Entity, Kind, move(CurInit)); break; } @@ -3061,7 +3283,7 @@ InitializationSequence::Perform(Sema &S, break; case SK_ConversionSequence: - if (S.PerformImplicitConversion(CurInitExpr, Step->Type, "converting", + if (S.PerformImplicitConversion(CurInitExpr, Step->Type, Sema::AA_Converting, false, false, *Step->ICS)) return S.ExprError(); @@ -3072,7 +3294,7 @@ InitializationSequence::Perform(Sema &S, case SK_ListInitialization: { InitListExpr *InitList = cast<InitListExpr>(CurInitExpr); QualType Ty = Step->Type; - if (S.CheckInitList(InitList, ResultType? *ResultType : Ty)) + if (S.CheckInitList(Entity, InitList, ResultType? *ResultType : Ty)) return S.ExprError(); CurInit.release(); @@ -3095,22 +3317,68 @@ InitializationSequence::Perform(Sema &S, return S.ExprError(); // Build the an expression that constructs a temporary. - CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, - move_arg(ConstructorArgs)); + CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + Constructor, + move_arg(ConstructorArgs), + ConstructorInitRequiresZeroInit); if (CurInit.isInvalid()) return S.ExprError(); - - CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + + bool Elidable + = cast<CXXConstructExpr>((Expr *)CurInit.get())->isElidable(); + if (shouldBindAsTemporary(Entity, Elidable)) + CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + + if (!Elidable) + CurInit = CopyIfRequiredForEntity(S, Entity, Kind, move(CurInit)); break; } case SK_ZeroInitialization: { - if (Kind.getKind() == InitializationKind::IK_Value) + step_iterator NextStep = Step; + ++NextStep; + if (NextStep != StepEnd && + NextStep->Kind == SK_ConstructorInitialization) { + // The need for zero-initialization is recorded directly into + // the call to the object's constructor within the next step. + ConstructorInitRequiresZeroInit = true; + } else if (Kind.getKind() == InitializationKind::IK_Value && + S.getLangOptions().CPlusPlus && + !Kind.isImplicitValueInit()) { CurInit = S.Owned(new (S.Context) CXXZeroInitValueExpr(Step->Type, Kind.getRange().getBegin(), Kind.getRange().getEnd())); - else + } else { CurInit = S.Owned(new (S.Context) ImplicitValueInitExpr(Step->Type)); + } + break; + } + + case SK_CAssignment: { + QualType SourceType = CurInitExpr->getType(); + Sema::AssignConvertType ConvTy = + S.CheckSingleAssignmentConstraints(Step->Type, CurInitExpr); + + // If this is a call, allow conversion to a transparent union. + if (ConvTy != Sema::Compatible && + Entity.getKind() == InitializedEntity::EK_Parameter && + S.CheckTransparentUnionArgumentConstraints(Step->Type, CurInitExpr) + == Sema::Compatible) + ConvTy = Sema::Compatible; + + if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(), + Step->Type, SourceType, + CurInitExpr, getAssignmentAction(Entity))) + return S.ExprError(); + + CurInit.release(); + CurInit = S.Owned(CurInitExpr); + break; + } + + case SK_StringInit: { + QualType Ty = Step->Type; + CheckStringInit(CurInitExpr, ResultType ? *ResultType : Ty, S); break; } } @@ -3129,7 +3397,7 @@ bool InitializationSequence::Diagnose(Sema &S, if (SequenceKind != FailedSequence) return false; - QualType DestType = Entity.getType().getType(); + QualType DestType = Entity.getType(); switch (Failure) { case FK_TooManyInitsForReference: S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits) @@ -3152,9 +3420,15 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_UserConversionOverloadFailed: switch (FailedOverloadResult) { case OR_Ambiguous: - S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition) - << Args[0]->getType() << DestType.getNonReferenceType() - << Args[0]->getSourceRange(); + if (Failure == FK_UserConversionOverloadFailed) + S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition) + << Args[0]->getType() << DestType + << Args[0]->getSourceRange(); + else + S.Diag(Kind.getLocation(), diag::err_ref_init_ambiguous) + << DestType << Args[0]->getType() + << Args[0]->getSourceRange(); + S.PrintOverloadCandidates(FailedCandidateSet, true); break; @@ -3220,7 +3494,8 @@ bool InitializationSequence::Diagnose(Sema &S, break; case FK_ConversionFailed: - S.Diag(Kind.getLocation(), diag::err_cannot_initialize_decl_noname) + S.Diag(Kind.getLocation(), diag::err_init_conversion_failed) + << (int)Entity.getKind() << DestType << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid) << Args[0]->getType() @@ -3228,12 +3503,16 @@ bool InitializationSequence::Diagnose(Sema &S, break; case FK_TooManyInitsForScalar: { - InitListExpr *InitList = cast<InitListExpr>(Args[0]); + SourceRange R; + + if (InitListExpr *InitList = dyn_cast<InitListExpr>(Args[0])) + R = SourceRange(InitList->getInit(1)->getLocStart(), + InitList->getLocEnd()); + else + R = SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); S.Diag(Kind.getLocation(), diag::err_excess_initializers) - << /*scalar=*/2 - << SourceRange(InitList->getInit(1)->getLocStart(), - InitList->getLocEnd()); + << /*scalar=*/2 << R; break; } @@ -3290,7 +3569,36 @@ bool InitializationSequence::Diagnose(Sema &S, } break; } + + case FK_DefaultInitOfConst: + S.Diag(Kind.getLocation(), diag::err_default_init_const) + << DestType; + break; } return true; } + +//===----------------------------------------------------------------------===// +// Initialization helper functions +//===----------------------------------------------------------------------===// +Sema::OwningExprResult +Sema::PerformCopyInitialization(const InitializedEntity &Entity, + SourceLocation EqualLoc, + OwningExprResult Init) { + if (Init.isInvalid()) + return ExprError(); + + Expr *InitE = (Expr *)Init.get(); + assert(InitE && "No initialization expression?"); + + if (EqualLoc.isInvalid()) + EqualLoc = InitE->getLocStart(); + + InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(), + EqualLoc); + InitializationSequence Seq(*this, Entity, Kind, &InitE, 1); + Init.release(); + return Seq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&InitE, 1)); +} diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 2d4b01f..5eb819a 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -14,7 +14,7 @@ #define LLVM_CLANG_SEMA_INIT_H #include "SemaOverload.h" -#include "clang/AST/TypeLoc.h" +#include "clang/AST/Type.h" #include "clang/Parse/Action.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/PointerIntPair.h" @@ -47,72 +47,79 @@ public: /// \brief The entity being initialized is an exception object that /// is being thrown. EK_Exception, + /// \brief The entity being initialized is an object (or array of + /// objects) allocated via new. + EK_New, /// \brief The entity being initialized is a temporary object. EK_Temporary, /// \brief The entity being initialized is a base member subobject. EK_Base, /// \brief The entity being initialized is a non-static data member /// subobject. - EK_Member + EK_Member, + /// \brief The entity being initialized is an element of an array + /// or vector. + EK_ArrayOrVectorElement }; private: /// \brief The kind of entity being initialized. EntityKind Kind; - /// \brief The type of the object or reference being initialized along with - /// its location information. - TypeLoc TL; + /// \brief If non-NULL, the parent entity in which this + /// initialization occurs. + const InitializedEntity *Parent; + + /// \brief The type of the object or reference being initialized. + QualType Type; union { /// \brief When Kind == EK_Variable, EK_Parameter, or EK_Member, /// the VarDecl, ParmVarDecl, or FieldDecl, respectively. DeclaratorDecl *VariableOrMember; - /// \brief When Kind == EK_Result or EK_Exception, the location of the - /// 'return' or 'throw' keyword, respectively. When Kind == EK_Temporary, - /// the location where the temporary is being created. + /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the + /// location of the 'return', 'throw', or 'new' keyword, + /// respectively. When Kind == EK_Temporary, the location where + /// the temporary is being created. unsigned Location; /// \brief When Kind == EK_Base, the base specifier that provides the /// base class. CXXBaseSpecifier *Base; + + /// \brief When Kind = EK_ArrayOrVectorElement, the index of the + /// array or vector element being initialized. + unsigned Index; }; InitializedEntity() { } /// \brief Create the initialization entity for a variable. InitializedEntity(VarDecl *Var) - : Kind(EK_Variable), - VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Var)) - { - InitDeclLoc(); - } + : Kind(EK_Variable), Parent(0), Type(Var->getType()), + VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Var)) { } /// \brief Create the initialization entity for a parameter. InitializedEntity(ParmVarDecl *Parm) - : Kind(EK_Parameter), - VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Parm)) - { - InitDeclLoc(); - } + : Kind(EK_Parameter), Parent(0), Type(Parm->getType().getUnqualifiedType()), + VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Parm)) { } - /// \brief Create the initialization entity for the result of a function, - /// throwing an object, or performing an explicit cast. - InitializedEntity(EntityKind Kind, SourceLocation Loc, TypeLoc TL) - : Kind(Kind), TL(TL), Location(Loc.getRawEncoding()) { } + /// \brief Create the initialization entity for the result of a + /// function, throwing an object, performing an explicit cast, or + /// initializing a parameter for which there is no declaration. + InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type) + : Kind(Kind), Parent(0), Type(Type), Location(Loc.getRawEncoding()) { } /// \brief Create the initialization entity for a member subobject. - InitializedEntity(FieldDecl *Member) - : Kind(EK_Member), - VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Member)) - { - InitDeclLoc(); - } - - /// \brief Initialize type-location information from a declaration. - void InitDeclLoc(); + InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent) + : Kind(EK_Member), Parent(Parent), Type(Member->getType()), + VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Member)) { } + /// \brief Create the initialization entity for an array element. + InitializedEntity(ASTContext &Context, unsigned Index, + const InitializedEntity &Parent); + public: /// \brief Create the initialization entity for a variable. static InitializedEntity InitializeVariable(VarDecl *Var) { @@ -124,38 +131,69 @@ public: return InitializedEntity(Parm); } + /// \brief Create the initialization entity for a parameter that is + /// only known by its type. + static InitializedEntity InitializeParameter(QualType Type) { + return InitializedEntity(EK_Parameter, SourceLocation(), Type); + } + /// \brief Create the initialization entity for the result of a function. static InitializedEntity InitializeResult(SourceLocation ReturnLoc, - TypeLoc TL) { - return InitializedEntity(EK_Result, ReturnLoc, TL); + QualType Type) { + return InitializedEntity(EK_Result, ReturnLoc, Type); } /// \brief Create the initialization entity for an exception object. static InitializedEntity InitializeException(SourceLocation ThrowLoc, - TypeLoc TL) { - return InitializedEntity(EK_Exception, ThrowLoc, TL); + QualType Type) { + return InitializedEntity(EK_Exception, ThrowLoc, Type); + } + + /// \brief Create the initialization entity for an object allocated via new. + static InitializedEntity InitializeNew(SourceLocation NewLoc, QualType Type) { + return InitializedEntity(EK_New, NewLoc, Type); } /// \brief Create the initialization entity for a temporary. - static InitializedEntity InitializeTemporary(EntityKind Kind, TypeLoc TL) { - return InitializedEntity(Kind, SourceLocation(), TL); + static InitializedEntity InitializeTemporary(QualType Type) { + return InitializedEntity(EK_Temporary, SourceLocation(), Type); } /// \brief Create the initialization entity for a base class subobject. static InitializedEntity InitializeBase(ASTContext &Context, CXXBaseSpecifier *Base); - /// \brief Create the initialize entity for a member subobject. - static InitializedEntity InitializeMember(FieldDecl *Member) { - return InitializedEntity(Member); + /// \brief Create the initialization entity for a member subobject. + static InitializedEntity InitializeMember(FieldDecl *Member, + const InitializedEntity *Parent = 0) { + return InitializedEntity(Member, Parent); } + /// \brief Create the initialization entity for an array element. + static InitializedEntity InitializeElement(ASTContext &Context, + unsigned Index, + const InitializedEntity &Parent) { + return InitializedEntity(Context, Index, Parent); + } + /// \brief Determine the kind of initialization. EntityKind getKind() const { return Kind; } + /// \brief Retrieve the parent of the entity being initialized, when + /// the initialization itself is occuring within the context of a + /// larger initialization. + const InitializedEntity *getParent() const { return Parent; } + /// \brief Retrieve type being initialized. - TypeLoc getType() const { return TL; } + QualType getType() const { return Type; } + /// \brief Retrieve the name of the entity being initialized. + DeclarationName getName() const; + + /// \brief Retrieve the variable, parameter, or field being + /// initialized. + DeclaratorDecl *getDecl() const; + /// \brief Determine the location of the 'return' keyword when initializing /// the result of a function call. SourceLocation getReturnLoc() const { @@ -169,6 +207,13 @@ public: assert(getKind() == EK_Exception && "No 'throw' location!"); return SourceLocation::getFromRawEncoding(Location); } + + /// \brief If this is already the initializer for an array or vector + /// element, sets the element index. + void setElementIndex(unsigned Index) { + assert(getKind() == EK_ArrayOrVectorElement); + this->Index = Index; + } }; /// \brief Describes the kind of initialization being performed, along with @@ -191,6 +236,7 @@ private: SIK_Copy = IK_Copy, ///< Copy initialization SIK_Default = IK_Default, ///< Default initialization SIK_Value = IK_Value, ///< Value initialization + SIK_ImplicitValue, ///< Implicit value initialization SIK_DirectCast, ///< Direct initialization due to a cast /// \brief Direct initialization due to a C-style or functional cast. SIK_DirectCStyleOrFunctionalCast @@ -242,15 +288,19 @@ public: /// \brief Create a value initialization. static InitializationKind CreateValue(SourceLocation InitLoc, SourceLocation LParenLoc, - SourceLocation RParenLoc) { - return InitializationKind(SIK_Value, InitLoc, LParenLoc, RParenLoc); + SourceLocation RParenLoc, + bool isImplicit = false) { + return InitializationKind(isImplicit? SIK_ImplicitValue : SIK_Value, + InitLoc, LParenLoc, RParenLoc); } /// \brief Determine the initialization kind. InitKind getKind() const { - if (Kind > SIK_Value) + if (Kind > SIK_ImplicitValue) return IK_Direct; - + if (Kind == SIK_ImplicitValue) + return IK_Value; + return (InitKind)Kind; } @@ -263,7 +313,12 @@ public: bool isCStyleOrFunctionalCast() const { return Kind == SIK_DirectCStyleOrFunctionalCast; } - + + /// \brief Determine whether this initialization is an implicit + /// value-initialization, e.g., as occurs during aggregate + /// initialization. + bool isImplicitValueInit() const { return Kind == SIK_ImplicitValue; } + /// \brief Retrieve the location at which initialization is occurring. SourceLocation getLocation() const { return Locations[0]; } @@ -319,7 +374,19 @@ public: ListInitialization, /// \brief Zero-initialization. - ZeroInitialization + ZeroInitialization, + + /// \brief No initialization required. + NoInitialization, + + /// \brief Standard conversion sequence. + StandardConversion, + + /// \brief C conversion sequence. + CAssignment, + + /// \brief String initialization + StringInit }; /// \brief Describes the kind of a particular step in an initialization @@ -350,7 +417,11 @@ public: /// \brief Perform initialization via a constructor. SK_ConstructorInitialization, /// \brief Zero-initialize the object - SK_ZeroInitialization + SK_ZeroInitialization, + /// \brief C assignment + SK_CAssignment, + /// \brief Initialization by string + SK_StringInit }; /// \brief A single step in the initialization sequence. @@ -420,7 +491,9 @@ public: /// \brief Overloading for a user-defined conversion failed. FK_UserConversionOverloadFailed, /// \brief Overloaded for initialization by constructor failed. - FK_ConstructorOverloadFailed + FK_ConstructorOverloadFailed, + /// \brief Default-initialization of a 'const' object. + FK_DefaultInitOfConst }; private: @@ -551,6 +624,16 @@ public: /// \brief Add a zero-initialization step. void AddZeroInitializationStep(QualType T); + /// \brief Add a C assignment step. + // + // FIXME: It isn't clear whether this should ever be needed; + // ideally, we would handle everything needed in C in the common + // path. However, that isn't the case yet. + void AddCAssignmentStep(QualType T); + + /// \brief Add a string init step. + void AddStringInitStep(QualType T); + /// \brief Note that this initialization sequence failed. void SetFailed(FailureKind Failure) { SequenceKind = FailedSequence; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 724e2fc..1419ceb 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -27,6 +27,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ErrorHandling.h" +#include <list> #include <set> #include <vector> #include <iterator> @@ -192,23 +193,83 @@ namespace { }; } +static bool IsAcceptableIDNS(NamedDecl *D, unsigned IDNS) { + return D->isInIdentifierNamespace(IDNS); +} + +static bool IsAcceptableOperatorName(NamedDecl *D, unsigned IDNS) { + return D->isInIdentifierNamespace(IDNS) && + !D->getDeclContext()->isRecord(); +} + +static bool IsAcceptableNestedNameSpecifierName(NamedDecl *D, unsigned IDNS) { + // This lookup ignores everything that isn't a type. + + // This is a fast check for the far most common case. + if (D->isInIdentifierNamespace(Decl::IDNS_Tag)) + return true; + + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + + return isa<TypeDecl>(D); +} + +static bool IsAcceptableNamespaceName(NamedDecl *D, unsigned IDNS) { + // We don't need to look through using decls here because + // using decls aren't allowed to name namespaces. + + return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D); +} + +/// Gets the default result filter for the given lookup. +static inline +LookupResult::ResultFilter getResultFilter(Sema::LookupNameKind NameKind) { + switch (NameKind) { + case Sema::LookupOrdinaryName: + case Sema::LookupTagName: + case Sema::LookupMemberName: + case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping + case Sema::LookupUsingDeclName: + case Sema::LookupObjCProtocolName: + case Sema::LookupObjCImplementationName: + return &IsAcceptableIDNS; + + case Sema::LookupOperatorName: + return &IsAcceptableOperatorName; + + case Sema::LookupNestedNameSpecifierName: + return &IsAcceptableNestedNameSpecifierName; + + case Sema::LookupNamespaceName: + return &IsAcceptableNamespaceName; + } + + llvm_unreachable("unkknown lookup kind"); + return 0; +} + // Retrieve the set of identifier namespaces that correspond to a // specific kind of name lookup. -inline unsigned -getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, - bool CPlusPlus) { +static inline unsigned getIDNS(Sema::LookupNameKind NameKind, + bool CPlusPlus, + bool Redeclaration) { unsigned IDNS = 0; switch (NameKind) { case Sema::LookupOrdinaryName: case Sema::LookupOperatorName: case Sema::LookupRedeclarationWithLinkage: IDNS = Decl::IDNS_Ordinary; - if (CPlusPlus) + if (CPlusPlus) { IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member; + if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend; + } break; case Sema::LookupTagName: IDNS = Decl::IDNS_Tag; + if (CPlusPlus && Redeclaration) + IDNS |= Decl::IDNS_TagFriend; break; case Sema::LookupMemberName: @@ -238,6 +299,13 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, return IDNS; } +void LookupResult::configure() { + IDNS = getIDNS(LookupKind, + SemaRef.getLangOptions().CPlusPlus, + isForRedeclaration()); + IsAcceptableFn = getResultFilter(LookupKind); +} + // Necessary because CXXBasePaths is not complete in Sema.h void LookupResult::deletePaths(CXXBasePaths *Paths) { delete Paths; @@ -377,8 +445,7 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) { DeclContext::lookup_const_iterator I, E; for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) - if (Sema::isAcceptableLookupResult(*I, R.getLookupKind(), - R.getIdentifierNamespace())) + if (R.isAcceptableDecl(*I)) R.addDecl(*I), Found = true; return Found; @@ -424,19 +491,7 @@ static DeclContext *findOuterContext(Scope *S) { } bool Sema::CppLookupName(LookupResult &R, Scope *S) { - assert(getLangOptions().CPlusPlus && - "Can perform only C++ lookup"); - LookupNameKind NameKind = R.getLookupKind(); - unsigned IDNS - = getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true); - - // If we're testing for redeclarations, also look in the friend namespaces. - if (R.isForRedeclaration()) { - if (IDNS & Decl::IDNS_Tag) IDNS |= Decl::IDNS_TagFriend; - if (IDNS & Decl::IDNS_Ordinary) IDNS |= Decl::IDNS_OrdinaryFriend; - } - - R.setIdentifierNamespace(IDNS); + assert(getLangOptions().CPlusPlus && "Can perform only C++ lookup"); DeclarationName Name = R.getLookupName(); @@ -467,7 +522,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // Check whether the IdResolver has anything in this scope. bool Found = false; for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { - if (isAcceptableLookupResult(*I, NameKind, IDNS)) { + if (R.isAcceptableDecl(*I)) { Found = true; R.addDecl(*I); } @@ -531,7 +586,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // Check whether the IdResolver has anything in this scope. bool Found = false; for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { - if (isAcceptableLookupResult(*I, NameKind, IDNS)) { + if (R.isAcceptableDecl(*I)) { // We found something. Look for anything else in our scope // with this same name and in an acceptable identifier // namespace, so that we can construct an overload set if we @@ -597,47 +652,18 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { if (!getLangOptions().CPlusPlus) { // Unqualified name lookup in C/Objective-C is purely lexical, so // search in the declarations attached to the name. - unsigned IDNS = 0; - switch (NameKind) { - case Sema::LookupOrdinaryName: - IDNS = Decl::IDNS_Ordinary; - break; - case Sema::LookupTagName: - IDNS = Decl::IDNS_Tag; - break; - - case Sema::LookupMemberName: - IDNS = Decl::IDNS_Member; - break; - - case Sema::LookupOperatorName: - case Sema::LookupNestedNameSpecifierName: - case Sema::LookupNamespaceName: - case Sema::LookupUsingDeclName: - assert(false && "C does not perform these kinds of name lookup"); - break; - - case Sema::LookupRedeclarationWithLinkage: + if (NameKind == Sema::LookupRedeclarationWithLinkage) { // Find the nearest non-transparent declaration scope. while (!(S->getFlags() & Scope::DeclScope) || (S->getEntity() && static_cast<DeclContext *>(S->getEntity()) ->isTransparentContext())) S = S->getParent(); - IDNS = Decl::IDNS_Ordinary; - break; - - case Sema::LookupObjCProtocolName: - IDNS = Decl::IDNS_ObjCProtocol; - break; - - case Sema::LookupObjCImplementationName: - IDNS = Decl::IDNS_ObjCImplementation; - break; - } + unsigned IDNS = R.getIdentifierNamespace(); + // Scan up the scope chain looking for a decl that matches this // identifier that is in the appropriate namespace. This search // should not take long, as shadowing of names is uncommon, and @@ -864,17 +890,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) { if (!R.getLookupName()) return false; - // If we're performing qualified name lookup (e.g., lookup into a - // struct), find fields as part of ordinary name lookup. - LookupNameKind NameKind = R.getLookupKind(); - unsigned IDNS - = getIdentifierNamespacesFromLookupNameKind(NameKind, - getLangOptions().CPlusPlus); - if (NameKind == LookupOrdinaryName) - IDNS |= Decl::IDNS_Member; - - R.setIdentifierNamespace(IDNS); - // Make sure that the declaration context is complete. assert((!isa<TagDecl>(LookupCtx) || LookupCtx->isDependentContext() || @@ -1514,15 +1529,12 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Functions.begin(), E = Functions.end(); I != E; ++I) { - FunctionDecl *FDecl = dyn_cast<FunctionDecl>(*I); - if (!FDecl) - FDecl = cast<FunctionTemplateDecl>(*I)->getTemplatedDecl(); + // Look through any using declarations to find the underlying function. + NamedDecl *Fn = (*I)->getUnderlyingDecl(); - // Add the namespace in which this function was defined. Note - // that, if this is a member function, we do *not* consider the - // enclosing namespace of its class. - DeclContext *Ctx = FDecl->getDeclContext(); - CollectNamespace(AssociatedNamespaces, Ctx); + FunctionDecl *FDecl = dyn_cast<FunctionDecl>(Fn); + if (!FDecl) + FDecl = cast<FunctionTemplateDecl>(Fn)->getTemplatedDecl(); // Add the classes and namespaces associated with the parameter // types and return type of this function. @@ -1693,3 +1705,509 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, } } } + +//---------------------------------------------------------------------------- +// Search for all visible declarations. +//---------------------------------------------------------------------------- +VisibleDeclConsumer::~VisibleDeclConsumer() { } + +namespace { + +class ShadowContextRAII; + +class VisibleDeclsRecord { +public: + /// \brief An entry in the shadow map, which is optimized to store a + /// single declaration (the common case) but can also store a list + /// of declarations. + class ShadowMapEntry { + typedef llvm::SmallVector<NamedDecl *, 4> DeclVector; + + /// \brief Contains either the solitary NamedDecl * or a vector + /// of declarations. + llvm::PointerUnion<NamedDecl *, DeclVector*> DeclOrVector; + + public: + ShadowMapEntry() : DeclOrVector() { } + + void Add(NamedDecl *ND); + void Destroy(); + + // Iteration. + typedef NamedDecl **iterator; + iterator begin(); + iterator end(); + }; + +private: + /// \brief A mapping from declaration names to the declarations that have + /// this name within a particular scope. + typedef llvm::DenseMap<DeclarationName, ShadowMapEntry> ShadowMap; + + /// \brief A list of shadow maps, which is used to model name hiding. + std::list<ShadowMap> ShadowMaps; + + /// \brief The declaration contexts we have already visited. + llvm::SmallPtrSet<DeclContext *, 8> VisitedContexts; + + friend class ShadowContextRAII; + +public: + /// \brief Determine whether we have already visited this context + /// (and, if not, note that we are going to visit that context now). + bool visitedContext(DeclContext *Ctx) { + return !VisitedContexts.insert(Ctx); + } + + /// \brief Determine whether the given declaration is hidden in the + /// current scope. + /// + /// \returns the declaration that hides the given declaration, or + /// NULL if no such declaration exists. + NamedDecl *checkHidden(NamedDecl *ND); + + /// \brief Add a declaration to the current shadow map. + void add(NamedDecl *ND) { ShadowMaps.back()[ND->getDeclName()].Add(ND); } +}; + +/// \brief RAII object that records when we've entered a shadow context. +class ShadowContextRAII { + VisibleDeclsRecord &Visible; + + typedef VisibleDeclsRecord::ShadowMap ShadowMap; + +public: + ShadowContextRAII(VisibleDeclsRecord &Visible) : Visible(Visible) { + Visible.ShadowMaps.push_back(ShadowMap()); + } + + ~ShadowContextRAII() { + for (ShadowMap::iterator E = Visible.ShadowMaps.back().begin(), + EEnd = Visible.ShadowMaps.back().end(); + E != EEnd; + ++E) + E->second.Destroy(); + + Visible.ShadowMaps.pop_back(); + } +}; + +} // end anonymous namespace + +void VisibleDeclsRecord::ShadowMapEntry::Add(NamedDecl *ND) { + if (DeclOrVector.isNull()) { + // 0 - > 1 elements: just set the single element information. + DeclOrVector = ND; + return; + } + + if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) { + // 1 -> 2 elements: create the vector of results and push in the + // existing declaration. + DeclVector *Vec = new DeclVector; + Vec->push_back(PrevND); + DeclOrVector = Vec; + } + + // Add the new element to the end of the vector. + DeclOrVector.get<DeclVector*>()->push_back(ND); +} + +void VisibleDeclsRecord::ShadowMapEntry::Destroy() { + if (DeclVector *Vec = DeclOrVector.dyn_cast<DeclVector *>()) { + delete Vec; + DeclOrVector = ((NamedDecl *)0); + } +} + +VisibleDeclsRecord::ShadowMapEntry::iterator +VisibleDeclsRecord::ShadowMapEntry::begin() { + if (DeclOrVector.isNull()) + return 0; + + if (DeclOrVector.dyn_cast<NamedDecl *>()) + return &reinterpret_cast<NamedDecl*&>(DeclOrVector); + + return DeclOrVector.get<DeclVector *>()->begin(); +} + +VisibleDeclsRecord::ShadowMapEntry::iterator +VisibleDeclsRecord::ShadowMapEntry::end() { + if (DeclOrVector.isNull()) + return 0; + + if (DeclOrVector.dyn_cast<NamedDecl *>()) + return &reinterpret_cast<NamedDecl*&>(DeclOrVector) + 1; + + return DeclOrVector.get<DeclVector *>()->end(); +} + +NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { + unsigned IDNS = ND->getIdentifierNamespace(); + std::list<ShadowMap>::reverse_iterator SM = ShadowMaps.rbegin(); + for (std::list<ShadowMap>::reverse_iterator SMEnd = ShadowMaps.rend(); + SM != SMEnd; ++SM) { + ShadowMap::iterator Pos = SM->find(ND->getDeclName()); + if (Pos == SM->end()) + continue; + + for (ShadowMapEntry::iterator I = Pos->second.begin(), + IEnd = Pos->second.end(); + I != IEnd; ++I) { + // A tag declaration does not hide a non-tag declaration. + if ((*I)->getIdentifierNamespace() == Decl::IDNS_Tag && + (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | + Decl::IDNS_ObjCProtocol))) + continue; + + // Protocols are in distinct namespaces from everything else. + if ((((*I)->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) + || (IDNS & Decl::IDNS_ObjCProtocol)) && + (*I)->getIdentifierNamespace() != IDNS) + continue; + + // We've found a declaration that hides this one. + return *I; + } + } + + return 0; +} + +static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, + bool QualifiedNameLookup, + VisibleDeclConsumer &Consumer, + VisibleDeclsRecord &Visited) { + // Make sure we don't visit the same context twice. + if (Visited.visitedContext(Ctx->getPrimaryContext())) + return; + + // Enumerate all of the results in this context. + for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; + CurCtx = CurCtx->getNextContext()) { + for (DeclContext::decl_iterator D = CurCtx->decls_begin(), + DEnd = CurCtx->decls_end(); + D != DEnd; ++D) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) + if (Result.isAcceptableDecl(ND)) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND)); + Visited.add(ND); + } + + // Visit transparent contexts inside this context. + if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) { + if (InnerCtx->isTransparentContext()) + LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup, + Consumer, Visited); + } + } + } + + // Traverse using directives for qualified name lookup. + if (QualifiedNameLookup) { + ShadowContextRAII Shadow(Visited); + DeclContext::udir_iterator I, E; + for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) { + LookupVisibleDecls((*I)->getNominatedNamespace(), Result, + QualifiedNameLookup, Consumer, Visited); + } + } + + // Traverse the contexts of inherited classes. + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { + for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), + BEnd = Record->bases_end(); + B != BEnd; ++B) { + QualType BaseType = B->getType(); + + // Don't look into dependent bases, because name lookup can't look + // there anyway. + if (BaseType->isDependentType()) + continue; + + const RecordType *Record = BaseType->getAs<RecordType>(); + if (!Record) + continue; + + // FIXME: It would be nice to be able to determine whether referencing + // a particular member would be ambiguous. For example, given + // + // struct A { int member; }; + // struct B { int member; }; + // struct C : A, B { }; + // + // void f(C *c) { c->### } + // + // accessing 'member' would result in an ambiguity. However, we + // could be smart enough to qualify the member with the base + // class, e.g., + // + // c->B::member + // + // or + // + // c->A::member + + // Find results in this base class (and its bases). + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup, + Consumer, Visited); + } + } + + // FIXME: Look into base classes in Objective-C! +} + +static void LookupVisibleDecls(Scope *S, LookupResult &Result, + UnqualUsingDirectiveSet &UDirs, + VisibleDeclConsumer &Consumer, + VisibleDeclsRecord &Visited) { + if (!S) + return; + + DeclContext *Entity = 0; + if (S->getEntity() && + !((DeclContext *)S->getEntity())->isFunctionOrMethod()) { + // Look into this scope's declaration context, along with any of its + // parent lookup contexts (e.g., enclosing classes), up to the point + // where we hit the context stored in the next outer scope. + Entity = (DeclContext *)S->getEntity(); + DeclContext *OuterCtx = findOuterContext(S); + + for (DeclContext *Ctx = Entity; Ctx && Ctx->getPrimaryContext() != OuterCtx; + Ctx = Ctx->getLookupParent()) { + if (Ctx->isFunctionOrMethod()) + continue; + + LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, + Consumer, Visited); + } + } else if (!S->getParent()) { + // Look into the translation unit scope. We walk through the translation + // unit's declaration context, because the Scope itself won't have all of + // the declarations if we loaded a precompiled header. + // FIXME: We would like the translation unit's Scope object to point to the + // translation unit, so we don't need this special "if" branch. However, + // doing so would force the normal C++ name-lookup code to look into the + // translation unit decl when the IdentifierInfo chains would suffice. + // Once we fix that problem (which is part of a more general "don't look + // in DeclContexts unless we have to" optimization), we can eliminate the + // TranslationUnit parameter entirely. + Entity = Result.getSema().Context.getTranslationUnitDecl(); + LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, + Consumer, Visited); + } else { + // Walk through the declarations in this Scope. + for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) { + if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get()))) + if (Result.isAcceptableDecl(ND)) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND)); + Visited.add(ND); + } + } + } + + if (Entity) { + // Lookup visible declarations in any namespaces found by using + // directives. + UnqualUsingDirectiveSet::const_iterator UI, UEnd; + llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity); + for (; UI != UEnd; ++UI) + LookupVisibleDecls(const_cast<DeclContext *>(UI->getNominatedNamespace()), + Result, /*QualifiedNameLookup=*/false, Consumer, + Visited); + } + + // Lookup names in the parent scope. + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(S->getParent(), Result, UDirs, Consumer, Visited); +} + +void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, + VisibleDeclConsumer &Consumer) { + // Determine the set of using directives available during + // unqualified name lookup. + Scope *Initial = S; + UnqualUsingDirectiveSet UDirs; + if (getLangOptions().CPlusPlus) { + // Find the first namespace or translation-unit scope. + while (S && !isNamespaceOrTranslationUnitScope(S)) + S = S->getParent(); + + UDirs.visitScopeChain(Initial, S); + } + UDirs.done(); + + // Look for visible declarations. + LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); + VisibleDeclsRecord Visited; + ShadowContextRAII Shadow(Visited); + ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited); +} + +void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, + VisibleDeclConsumer &Consumer) { + LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); + VisibleDeclsRecord Visited; + ShadowContextRAII Shadow(Visited); + ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, Consumer, + Visited); +} + +//---------------------------------------------------------------------------- +// Typo correction +//---------------------------------------------------------------------------- + +namespace { +class TypoCorrectionConsumer : public VisibleDeclConsumer { + /// \brief The name written that is a typo in the source. + llvm::StringRef Typo; + + /// \brief The results found that have the smallest edit distance + /// found (so far) with the typo name. + llvm::SmallVector<NamedDecl *, 4> BestResults; + + /// \brief The best edit distance found so far. + unsigned BestEditDistance; + +public: + explicit TypoCorrectionConsumer(IdentifierInfo *Typo) + : Typo(Typo->getName()) { } + + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding); + + typedef llvm::SmallVector<NamedDecl *, 4>::const_iterator iterator; + iterator begin() const { return BestResults.begin(); } + iterator end() const { return BestResults.end(); } + bool empty() const { return BestResults.empty(); } + + unsigned getBestEditDistance() const { return BestEditDistance; } +}; + +} + +void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) { + // Don't consider hidden names for typo correction. + if (Hiding) + return; + + // Only consider entities with identifiers for names, ignoring + // special names (constructors, overloaded operators, selectors, + // etc.). + IdentifierInfo *Name = ND->getIdentifier(); + if (!Name) + return; + + // Compute the edit distance between the typo and the name of this + // entity. If this edit distance is not worse than the best edit + // distance we've seen so far, add it to the list of results. + unsigned ED = Typo.edit_distance(Name->getName()); + if (!BestResults.empty()) { + if (ED < BestEditDistance) { + // This result is better than any we've seen before; clear out + // the previous results. + BestResults.clear(); + BestEditDistance = ED; + } else if (ED > BestEditDistance) { + // This result is worse than the best results we've seen so far; + // ignore it. + return; + } + } else + BestEditDistance = ED; + + BestResults.push_back(ND); +} + +/// \brief Try to "correct" a typo in the source code by finding +/// visible declarations whose names are similar to the name that was +/// present in the source code. +/// +/// \param Res the \c LookupResult structure that contains the name +/// that was present in the source code along with the name-lookup +/// criteria used to search for the name. On success, this structure +/// will contain the results of name lookup. +/// +/// \param S the scope in which name lookup occurs. +/// +/// \param SS the nested-name-specifier that precedes the name we're +/// looking for, if present. +/// +/// \param MemberContext if non-NULL, the context in which to look for +/// a member access expression. +/// +/// \param EnteringContext whether we're entering the context described by +/// the nested-name-specifier SS. +/// +/// \returns true if the typo was corrected, in which case the \p Res +/// structure will contain the results of name lookup for the +/// corrected name. Otherwise, returns false. +bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, + DeclContext *MemberContext, bool EnteringContext) { + // We only attempt to correct typos for identifiers. + IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); + if (!Typo) + return false; + + // If the scope specifier itself was invalid, don't try to correct + // typos. + if (SS && SS->isInvalid()) + return false; + + // Never try to correct typos during template deduction or + // instantiation. + if (!ActiveTemplateInstantiations.empty()) + return false; + + TypoCorrectionConsumer Consumer(Typo); + if (MemberContext) + LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer); + else if (SS && SS->isSet()) { + DeclContext *DC = computeDeclContext(*SS, EnteringContext); + if (!DC) + return false; + + LookupVisibleDecls(DC, Res.getLookupKind(), Consumer); + } else { + LookupVisibleDecls(S, Res.getLookupKind(), Consumer); + } + + if (Consumer.empty()) + return false; + + // Only allow a single, closest name in the result set (it's okay to + // have overloads of that name, though). + TypoCorrectionConsumer::iterator I = Consumer.begin(); + DeclarationName BestName = (*I)->getDeclName(); + ++I; + for(TypoCorrectionConsumer::iterator IEnd = Consumer.end(); I != IEnd; ++I) { + if (BestName != (*I)->getDeclName()) + return false; + } + + // BestName is the closest viable name to what the user + // typed. However, to make sure that we don't pick something that's + // way off, make sure that the user typed at least 3 characters for + // each correction. + unsigned ED = Consumer.getBestEditDistance(); + if (ED == 0 || (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3) + return false; + + // Perform name lookup again with the name we chose, and declare + // success if we found something that was not ambiguous. + Res.clear(); + Res.setLookupName(BestName); + if (MemberContext) + LookupQualifiedName(Res, MemberContext); + else + LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, + EnteringContext); + + if (Res.isAmbiguous()) { + Res.suppressDiagnostics(); + return false; + } + + return Res.getResultKind() != LookupResult::NotFound; +} diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 561cfdb..5892081 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -13,6 +13,7 @@ #include "Sema.h" #include "Lookup.h" +#include "SemaInit.h" #include "clang/Basic/Diagnostic.h" #include "clang/Lex/Preprocessor.h" #include "clang/AST/ASTContext.h" @@ -88,7 +89,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { /// GetImplicitConversionName - Return the name of this kind of /// implicit conversion. const char* GetImplicitConversionName(ImplicitConversionKind Kind) { - static const char* Name[(int)ICK_Num_Conversion_Kinds] = { + static const char* const Name[(int)ICK_Num_Conversion_Kinds] = { "No conversion", "Lvalue-to-rvalue", "Array-to-pointer", @@ -451,7 +452,8 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, QualType FromCanon = Context.getCanonicalType(From->getType().getUnqualifiedType()); QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); - if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) { + if (Constructor->isCopyConstructor() && + (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon))) { // Turn this into a "standard" conversion sequence, so that it // gets ranked with standard conversion sequences. ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; @@ -915,6 +917,25 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr, Quals)); } +/// BuildSimilarlyQualifiedObjCObjectPointerType - In a pointer conversion from +/// the FromType, which is an objective-c pointer, to ToType, which may or may +/// not have the right set of qualifiers. +static QualType +BuildSimilarlyQualifiedObjCObjectPointerType(QualType FromType, + QualType ToType, + ASTContext &Context) { + QualType CanonFromType = Context.getCanonicalType(FromType); + QualType CanonToType = Context.getCanonicalType(ToType); + Qualifiers Quals = CanonFromType.getQualifiers(); + + // Exact qualifier match -> return the pointer type we're converting to. + if (CanonToType.getLocalQualifiers() == Quals) + return ToType; + + // Just build a canonical type that has the right qualifiers. + return Context.getQualifiedType(CanonToType.getLocalUnqualifiedType(), Quals); +} + static bool isNullPointerConstantForConversion(Expr *Expr, bool InOverloadResolution, ASTContext &Context) { @@ -992,13 +1013,20 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, return true; } - // Beyond this point, both types need to be pointers. + // Beyond this point, both types need to be pointers + // , including objective-c pointers. + QualType ToPointeeType = ToTypePtr->getPointeeType(); + if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType()) { + ConvertedType = BuildSimilarlyQualifiedObjCObjectPointerType(FromType, + ToType, Context); + return true; + + } const PointerType *FromTypePtr = FromType->getAs<PointerType>(); if (!FromTypePtr) return false; QualType FromPointeeType = FromTypePtr->getPointeeType(); - QualType ToPointeeType = ToTypePtr->getPointeeType(); // An rvalue of type "pointer to cv T," where T is an object type, // can be converted to an rvalue of type "pointer to cv void" (C++ @@ -1774,7 +1802,16 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); T1 = Context.getCanonicalType(T1); T2 = Context.getCanonicalType(T2); - if (Context.hasSameUnqualifiedType(T1, T2)) { + Qualifiers T1Quals, T2Quals; + QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals); + QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals); + if (UnqualT1 == UnqualT2) { + // If the type is an array type, promote the element qualifiers to the type + // for comparison. + if (isa<ArrayType>(T1) && T1Quals) + T1 = Context.getQualifiedType(UnqualT1, T1Quals); + if (isa<ArrayType>(T2) && T2Quals) + T2 = Context.getQualifiedType(UnqualT2, T2Quals); if (T2.isMoreQualifiedThan(T1)) return ImplicitConversionSequence::Better; else if (T1.isMoreQualifiedThan(T2)) @@ -1807,12 +1844,22 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); T1 = Context.getCanonicalType(T1); T2 = Context.getCanonicalType(T2); + Qualifiers T1Quals, T2Quals; + QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals); + QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals); // If the types are the same, we won't learn anything by unwrapped // them. - if (Context.hasSameUnqualifiedType(T1, T2)) + if (UnqualT1 == UnqualT2) return ImplicitConversionSequence::Indistinguishable; + // If the type is an array type, promote the element qualifiers to the type + // for comparison. + if (isa<ArrayType>(T1) && T1Quals) + T1 = Context.getQualifiedType(UnqualT1, T1Quals); + if (isa<ArrayType>(T2) && T2Quals) + T2 = Context.getQualifiedType(UnqualT2, T2Quals); + ImplicitConversionSequence::CompareKind Result = ImplicitConversionSequence::Indistinguishable; while (UnwrapSimilarPointerTypes(T1, T2)) { @@ -2080,7 +2127,7 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType, /// be true when the copy may be elided (C++ 12.8p15). Overload resolution works /// differently in C++0x for this case. bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, - const char* Flavor, bool Elidable) { + AssignmentAction Action, bool Elidable) { if (!getLangOptions().CPlusPlus) { // In C, argument passing is the same as performing an assignment. QualType FromType = From->getType(); @@ -2092,7 +2139,7 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, ConvTy = Compatible; return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType, - FromType, From, Flavor); + FromType, From, Action); } if (ToType->isReferenceType()) @@ -2102,13 +2149,13 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, /*AllowExplicit=*/false, /*ForceRValue=*/false); - if (!PerformImplicitConversion(From, ToType, Flavor, + if (!PerformImplicitConversion(From, ToType, Action, /*AllowExplicit=*/false, Elidable)) return false; if (!DiagnoseMultipleUserDefinedConversion(From, ToType)) return Diag(From->getSourceRange().getBegin(), diag::err_typecheck_convert_incompatible) - << ToType << From->getType() << Flavor << From->getSourceRange(); + << ToType << From->getType() << Action << From->getSourceRange(); return true; } @@ -2229,7 +2276,7 @@ ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) { /// of the expression From to bool (C++0x [conv]p3). bool Sema::PerformContextuallyConvertToBool(Expr *&From) { ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From); - if (!PerformImplicitConversion(From, Context.BoolTy, ICS, "converting")) + if (!PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting)) return false; if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy)) @@ -2622,7 +2669,14 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, Args, NumArgs, Specialization, Info)) { // FIXME: Record what happened with template argument deduction, so // that we can give the user a beautiful diagnostic. - (void)Result; + (void) Result; + + CandidateSet.push_back(OverloadCandidate()); + OverloadCandidate &Candidate = CandidateSet.back(); + Candidate.Function = FunctionTemplate->getTemplatedDecl(); + Candidate.Viable = false; + Candidate.IsSurrogate = false; + Candidate.IgnoreObjectArgument = false; return; } @@ -4430,6 +4484,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool FoundNonTemplateFunction = false; for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) { + // Look through any using declarations to find the underlying function. + NamedDecl *Fn = (*I)->getUnderlyingDecl(); + // C++ [over.over]p3: // Non-member functions and static member functions match // targets of type "pointer-to-function" or "reference-to-function." @@ -4438,7 +4495,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // Note that according to DR 247, the containing class does not matter. if (FunctionTemplateDecl *FunctionTemplate - = dyn_cast<FunctionTemplateDecl>(*I)) { + = dyn_cast<FunctionTemplateDecl>(Fn)) { if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl())) { // Skip non-static function templates when converting to pointer, and @@ -4475,7 +4532,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, continue; } - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*I)) { + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) { // Skip non-static functions when converting to pointer, and static // when converting to member pointer. if (Method->isStatic() == IsMember) @@ -4487,7 +4544,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } else if (IsMember) continue; - if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*I)) { + if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) { QualType ResultTy; if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) || IsNoReturnConversion(Context, FunDecl->getType(), FunctionType, @@ -4558,6 +4615,93 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, return 0; } +/// \brief Given an expression that refers to an overloaded function, try to +/// resolve that overloaded function expression down to a single function. +/// +/// This routine can only resolve template-ids that refer to a single function +/// template, where that template-id refers to a single template whose template +/// arguments are either provided by the template-id or have defaults, +/// as described in C++0x [temp.arg.explicit]p3. +FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { + // C++ [over.over]p1: + // [...] [Note: any redundant set of parentheses surrounding the + // overloaded function name is ignored (5.1). ] + Expr *OvlExpr = From->IgnoreParens(); + + // C++ [over.over]p1: + // [...] The overloaded function name can be preceded by the & + // operator. + if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) { + if (UnOp->getOpcode() == UnaryOperator::AddrOf) + OvlExpr = UnOp->getSubExpr()->IgnoreParens(); + } + + bool HasExplicitTemplateArgs = false; + TemplateArgumentListInfo ExplicitTemplateArgs; + + llvm::SmallVector<NamedDecl*,8> Fns; + + // Look into the overloaded expression. + if (UnresolvedLookupExpr *UL + = dyn_cast<UnresolvedLookupExpr>(OvlExpr)) { + Fns.append(UL->decls_begin(), UL->decls_end()); + if (UL->hasExplicitTemplateArgs()) { + HasExplicitTemplateArgs = true; + UL->copyTemplateArgumentsInto(ExplicitTemplateArgs); + } + } else if (UnresolvedMemberExpr *ME + = dyn_cast<UnresolvedMemberExpr>(OvlExpr)) { + Fns.append(ME->decls_begin(), ME->decls_end()); + if (ME->hasExplicitTemplateArgs()) { + HasExplicitTemplateArgs = true; + ME->copyTemplateArgumentsInto(ExplicitTemplateArgs); + } + } + + // If we didn't actually find any template-ids, we're done. + if (Fns.empty() || !HasExplicitTemplateArgs) + return 0; + + // Look through all of the overloaded functions, searching for one + // whose type matches exactly. + FunctionDecl *Matched = 0; + for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(), + E = Fns.end(); I != E; ++I) { + // C++0x [temp.arg.explicit]p3: + // [...] In contexts where deduction is done and fails, or in contexts + // where deduction is not done, if a template argument list is + // specified and it, along with any default template arguments, + // identifies a single function template specialization, then the + // template-id is an lvalue for the function template specialization. + FunctionTemplateDecl *FunctionTemplate = cast<FunctionTemplateDecl>(*I); + + // C++ [over.over]p2: + // If the name is a function template, template argument deduction is + // done (14.8.2.2), and if the argument deduction succeeds, the + // resulting template argument list is used to generate a single + // function template specialization, which is added to the set of + // overloaded functions considered. + // FIXME: We don't really want to build the specialization here, do we? + FunctionDecl *Specialization = 0; + TemplateDeductionInfo Info(Context); + if (TemplateDeductionResult Result + = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs, + Specialization, Info)) { + // FIXME: make a note of the failed deduction for diagnostics. + (void)Result; + continue; + } + + // Multiple matches; we can't resolve to a single declaration. + if (Matched) + return 0; + + Matched = Specialization; + } + + return Matched; +} + /// \brief Add a single candidate to the overload set. static void AddOverloadedCallCandidate(Sema &S, NamedDecl *Callee, @@ -4589,10 +4733,7 @@ static void AddOverloadedCallCandidate(Sema &S, /// \brief Add the overload candidates named by callee and/or found by argument /// dependent lookup to the given overload set. -void Sema::AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*> &Fns, - DeclarationName &UnqualifiedName, - bool ArgumentDependentLookup, - const TemplateArgumentListInfo *ExplicitTemplateArgs, +void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, bool PartialOverloading) { @@ -4615,28 +4756,99 @@ void Sema::AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*> &Fns, // // then Y is empty. - if (ArgumentDependentLookup) { - for (unsigned I = 0; I < Fns.size(); ++I) { - assert(!Fns[I]->getDeclContext()->isRecord()); - assert(isa<UsingShadowDecl>(Fns[I]) || - !Fns[I]->getDeclContext()->isFunctionOrMethod()); - assert(Fns[I]->getUnderlyingDecl()->isFunctionOrFunctionTemplate()); + if (ULE->requiresADL()) { + for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(), + E = ULE->decls_end(); I != E; ++I) { + assert(!(*I)->getDeclContext()->isRecord()); + assert(isa<UsingShadowDecl>(*I) || + !(*I)->getDeclContext()->isFunctionOrMethod()); + assert((*I)->getUnderlyingDecl()->isFunctionOrFunctionTemplate()); } } #endif - for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(), - E = Fns.end(); I != E; ++I) + // It would be nice to avoid this copy. + TemplateArgumentListInfo TABuffer; + const TemplateArgumentListInfo *ExplicitTemplateArgs = 0; + if (ULE->hasExplicitTemplateArgs()) { + ULE->copyTemplateArgumentsInto(TABuffer); + ExplicitTemplateArgs = &TABuffer; + } + + for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(), + E = ULE->decls_end(); I != E; ++I) AddOverloadedCallCandidate(*this, *I, ExplicitTemplateArgs, Args, NumArgs, CandidateSet, PartialOverloading); - if (ArgumentDependentLookup) - AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs, + if (ULE->requiresADL()) + AddArgumentDependentLookupCandidates(ULE->getName(), Args, NumArgs, ExplicitTemplateArgs, CandidateSet, PartialOverloading); } + +static Sema::OwningExprResult Destroy(Sema &SemaRef, Expr *Fn, + Expr **Args, unsigned NumArgs) { + Fn->Destroy(SemaRef.Context); + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) + Args[Arg]->Destroy(SemaRef.Context); + return SemaRef.ExprError(); +} + +/// Attempts to recover from a call where no functions were found. +/// +/// Returns true if new candidates were found. +static Sema::OwningExprResult +BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn, + UnresolvedLookupExpr *ULE, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + + CXXScopeSpec SS; + if (ULE->getQualifier()) { + SS.setScopeRep(ULE->getQualifier()); + SS.setRange(ULE->getQualifierRange()); + } + + TemplateArgumentListInfo TABuffer; + const TemplateArgumentListInfo *ExplicitTemplateArgs = 0; + if (ULE->hasExplicitTemplateArgs()) { + ULE->copyTemplateArgumentsInto(TABuffer); + ExplicitTemplateArgs = &TABuffer; + } + + LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), + Sema::LookupOrdinaryName); + if (SemaRef.DiagnoseEmptyLookup(/*Scope=*/0, SS, R)) + return Destroy(SemaRef, Fn, Args, NumArgs); + + assert(!R.empty() && "lookup results empty despite recovery"); + + // Build an implicit member call if appropriate. Just drop the + // casts and such from the call, we don't really care. + Sema::OwningExprResult NewFn = SemaRef.ExprError(); + if ((*R.begin())->isCXXClassMember()) + NewFn = SemaRef.BuildPossibleImplicitMemberExpr(SS, R, ExplicitTemplateArgs); + else if (ExplicitTemplateArgs) + NewFn = SemaRef.BuildTemplateIdExpr(SS, R, false, *ExplicitTemplateArgs); + else + NewFn = SemaRef.BuildDeclarationNameExpr(SS, R, false); + + if (NewFn.isInvalid()) + return Destroy(SemaRef, Fn, Args, NumArgs); + + Fn->Destroy(SemaRef.Context); + + // This shouldn't cause an infinite loop because we're giving it + // an expression with non-empty lookup results, which should never + // end up here. + return SemaRef.ActOnCallExpr(/*Scope*/ 0, move(NewFn), LParenLoc, + Sema::MultiExprArg(SemaRef, (void**) Args, NumArgs), + CommaLocs, RParenLoc); +} /// ResolveOverloadedCallFn - Given the call expression that calls Fn /// (which eventually refers to the declaration Func) and the call @@ -4645,44 +4857,68 @@ void Sema::AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*> &Fns, /// the function declaration produced by overload /// resolution. Otherwise, emits diagnostics, deletes all of the /// arguments and Fn, and returns NULL. -FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, - llvm::SmallVectorImpl<NamedDecl*> &Fns, - DeclarationName UnqualifiedName, - const TemplateArgumentListInfo *ExplicitTemplateArgs, - SourceLocation LParenLoc, - Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc, - bool ArgumentDependentLookup) { +Sema::OwningExprResult +Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { +#ifndef NDEBUG + if (ULE->requiresADL()) { + // To do ADL, we must have found an unqualified name. + assert(!ULE->getQualifier() && "qualified name with ADL"); + + // We don't perform ADL for implicit declarations of builtins. + // Verify that this was correctly set up. + FunctionDecl *F; + if (ULE->decls_begin() + 1 == ULE->decls_end() && + (F = dyn_cast<FunctionDecl>(*ULE->decls_begin())) && + F->getBuiltinID() && F->isImplicit()) + assert(0 && "performing ADL for builtin"); + + // We don't perform ADL in C. + assert(getLangOptions().CPlusPlus && "ADL enabled in C"); + } +#endif + OverloadCandidateSet CandidateSet; - // Add the functions denoted by Callee to the set of candidate - // functions. - AddOverloadedCallCandidates(Fns, UnqualifiedName, ArgumentDependentLookup, - ExplicitTemplateArgs, Args, NumArgs, - CandidateSet); + // Add the functions denoted by the callee to the set of candidate + // functions, including those from argument-dependent lookup. + AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet); + + // If we found nothing, try to recover. + // AddRecoveryCallCandidates diagnoses the error itself, so we just + // bailout out if it fails. + if (CandidateSet.empty()) + return BuildRecoveryCallExpr(*this, Fn, ULE, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc); + OverloadCandidateSet::iterator Best; switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) { - case OR_Success: - return Best->Function; + case OR_Success: { + FunctionDecl *FDecl = Best->Function; + Fn = FixOverloadedFunctionReference(Fn, FDecl); + return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); + } case OR_No_Viable_Function: Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_no_viable_function_in_call) - << UnqualifiedName << Fn->getSourceRange(); + << ULE->getName() << Fn->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); break; case OR_Ambiguous: Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call) - << UnqualifiedName << Fn->getSourceRange(); + << ULE->getName() << Fn->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); break; case OR_Deleted: Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_deleted_call) << Best->Function->isDeleted() - << UnqualifiedName + << ULE->getName() << Fn->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); break; @@ -4693,7 +4929,7 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, Fn->Destroy(Context); for (unsigned Arg = 0; Arg < NumArgs; ++Arg) Args[Arg]->Destroy(Context); - return 0; + return ExprError(); } static bool IsOverloaded(const Sema::FunctionSet &Functions) { @@ -4787,10 +5023,16 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, return ExprError(); } else { // Convert the arguments. - if (PerformCopyInitialization(Input, - FnDecl->getParamDecl(0)->getType(), - "passing")) + OwningExprResult InputInit + = PerformCopyInitialization(InitializedEntity::InitializeParameter( + FnDecl->getParamDecl(0)), + SourceLocation(), + move(input)); + if (InputInit.isInvalid()) return ExprError(); + + input = move(InputInit); + Input = (Expr *)input.get(); } // Determine the result type @@ -4817,7 +5059,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, // break out so that we will build the appropriate built-in // operator node. if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0], - Best->Conversions[0], "passing")) + Best->Conversions[0], AA_Passing)) return ExprError(); break; @@ -4954,17 +5196,40 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { - if (PerformObjectArgumentInitialization(Args[0], Method) || - PerformCopyInitialization(Args[1], FnDecl->getParamDecl(0)->getType(), - "passing")) + OwningExprResult Arg1 + = PerformCopyInitialization( + InitializedEntity::InitializeParameter( + FnDecl->getParamDecl(0)), + SourceLocation(), + Owned(Args[1])); + if (Arg1.isInvalid()) + return ExprError(); + + if (PerformObjectArgumentInitialization(Args[0], Method)) return ExprError(); + + Args[1] = RHS = Arg1.takeAs<Expr>(); } else { // Convert the arguments. - if (PerformCopyInitialization(Args[0], FnDecl->getParamDecl(0)->getType(), - "passing") || - PerformCopyInitialization(Args[1], FnDecl->getParamDecl(1)->getType(), - "passing")) + OwningExprResult Arg0 + = PerformCopyInitialization( + InitializedEntity::InitializeParameter( + FnDecl->getParamDecl(0)), + SourceLocation(), + Owned(Args[0])); + if (Arg0.isInvalid()) + return ExprError(); + + OwningExprResult Arg1 + = PerformCopyInitialization( + InitializedEntity::InitializeParameter( + FnDecl->getParamDecl(1)), + SourceLocation(), + Owned(Args[1])); + if (Arg1.isInvalid()) return ExprError(); + Args[0] = LHS = Arg0.takeAs<Expr>(); + Args[1] = RHS = Arg1.takeAs<Expr>(); } // Determine the result type @@ -4992,9 +5257,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // break out so that we will build the appropriate built-in // operator node. if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0], - Best->Conversions[0], "passing") || + Best->Conversions[0], AA_Passing) || PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1], - Best->Conversions[1], "passing")) + Best->Conversions[1], AA_Passing)) return ExprError(); break; @@ -5106,7 +5371,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, if (PerformObjectArgumentInitialization(Args[0], Method) || PerformCopyInitialization(Args[1], FnDecl->getParamDecl(0)->getType(), - "passing")) + AA_Passing)) return ExprError(); // Determine the result type @@ -5136,9 +5401,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // break out so that we will build the appropriate built-in // operator node. if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0], - Best->Conversions[0], "passing") || + Best->Conversions[0], AA_Passing) || PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1], - Best->Conversions[1], "passing")) + Best->Conversions[1], AA_Passing)) return ExprError(); break; @@ -5522,7 +5787,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Pass the argument. QualType ProtoArgType = Proto->getArgType(i); - IsError |= PerformCopyInitialization(Arg, ProtoArgType, "passing"); + IsError |= PerformCopyInitialization(Arg, ProtoArgType, AA_Passing); } else { OwningExprResult DefArg = BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i)); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index de67a5f..b8928c3 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -95,7 +96,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { // If the callee has attribute pure, const, or warn_unused_result, warn with // a more specific message to make it clear what is happening. - if (const FunctionDecl *FD = CE->getDirectCallee()) { + if (const Decl *FD = CE->getCalleeDecl()) { if (FD->getAttr<WarnUnusedResultAttr>()) { Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; return; @@ -902,7 +903,7 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, AssignConvertType ConvTy = CheckSingleAssignmentConstraints(Context.VoidPtrTy, E); if (DiagnoseAssignmentResult(ConvTy, StarLoc, Context.VoidPtrTy, ETy, - E, "passing")) + E, AA_Passing)) return StmtError(); } return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E)); @@ -977,7 +978,6 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { // we have a non-void block with an expression, continue checking - QualType RetValType = RetValExp->getType(); // C99 6.8.6.4p3(136): The return statement is not an assignment. The // overlap restriction of subclause 6.5.16.1 does not apply to the case of @@ -986,7 +986,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. // FIXME: Leaks RetValExp. - if (PerformCopyInitialization(RetValExp, FnRetType, "returning")) + if (PerformCopyInitialization(RetValExp, FnRetType, AA_Returning)) return StmtError(); if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); @@ -1053,7 +1053,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { << RetValExp->getSourceRange(); } - RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true); + RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); } return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); } @@ -1092,21 +1092,28 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { bool Elidable = getLangOptions().CPlusPlus0x ? IsReturnCopyElidable(Context, FnRetType, RetValExp) : false; + // FIXME: Elidable + (void)Elidable; // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. - // FIXME: Leaks RetValExp on error. - if (PerformCopyInitialization(RetValExp, FnRetType, "returning", Elidable)){ - // We should still clean up our temporaries, even when we're failing! - RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true); + OwningExprResult Res = PerformCopyInitialization( + InitializedEntity::InitializeResult(ReturnLoc, + FnRetType), + SourceLocation(), + Owned(RetValExp)); + if (Res.isInvalid()) { + // FIXME: Cleanup temporaries here, anyway? return StmtError(); } - - if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + + RetValExp = Res.takeAs<Expr>(); + if (RetValExp) + CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } if (RetValExp) - RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true); + RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index ac1b1ec..8c6aa6a 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -102,7 +102,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); - LookupResult R(*this, TName, SourceLocation(), LookupOrdinaryName); + LookupResult R(*this, TName, Name.getSourceRange().getBegin(), + LookupOrdinaryName); R.suppressDiagnostics(); LookupTemplateName(R, S, SS, ObjectType, EnteringContext); if (R.empty()) @@ -202,6 +203,29 @@ void Sema::LookupTemplateName(LookupResult &Found, assert(!Found.isAmbiguous() && "Cannot handle template name-lookup ambiguities"); + if (Found.empty()) { + // If we did not find any names, attempt to correct any typos. + DeclarationName Name = Found.getLookupName(); + if (CorrectTypo(Found, S, &SS, LookupCtx)) { + FilterAcceptableTemplateNames(Context, Found); + if (!Found.empty() && isa<TemplateDecl>(*Found.begin())) { + if (LookupCtx) + Diag(Found.getNameLoc(), diag::err_no_member_template_suggest) + << Name << LookupCtx << Found.getLookupName() << SS.getRange() + << CodeModificationHint::CreateReplacement(Found.getNameLoc(), + Found.getLookupName().getAsString()); + else + Diag(Found.getNameLoc(), diag::err_no_template_suggest) + << Name << Found.getLookupName() + << CodeModificationHint::CreateReplacement(Found.getNameLoc(), + Found.getLookupName().getAsString()); + } else + Found.clear(); + } else { + Found.clear(); + } + } + FilterAcceptableTemplateNames(Context, Found); if (Found.empty()) return; @@ -691,7 +715,27 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (Previous.begin() != Previous.end()) PrevDecl = *Previous.begin(); - if (PrevDecl && TUK == TUK_Friend) { + // If there is a previous declaration with the same name, check + // whether this is a valid redeclaration. + ClassTemplateDecl *PrevClassTemplate + = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl); + + // We may have found the injected-class-name of a class template, + // class template partial specialization, or class template specialization. + // In these cases, grab the template that is being defined or specialized. + if (!PrevClassTemplate && PrevDecl && isa<CXXRecordDecl>(PrevDecl) && + cast<CXXRecordDecl>(PrevDecl)->isInjectedClassName()) { + PrevDecl = cast<CXXRecordDecl>(PrevDecl->getDeclContext()); + PrevClassTemplate + = cast<CXXRecordDecl>(PrevDecl)->getDescribedClassTemplate(); + if (!PrevClassTemplate && isa<ClassTemplateSpecializationDecl>(PrevDecl)) { + PrevClassTemplate + = cast<ClassTemplateSpecializationDecl>(PrevDecl) + ->getSpecializedTemplate(); + } + } + + if (TUK == TUK_Friend) { // C++ [namespace.memdef]p3: // [...] When looking for a prior declaration of a class or a function // declared as a friend, and when the name of the friend class or @@ -700,15 +744,16 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, DeclContext *OutermostContext = CurContext; while (!OutermostContext->isFileContext()) OutermostContext = OutermostContext->getLookupParent(); - - if (OutermostContext->Equals(PrevDecl->getDeclContext()) || - OutermostContext->Encloses(PrevDecl->getDeclContext())) { + + if (PrevDecl && + (OutermostContext->Equals(PrevDecl->getDeclContext()) || + OutermostContext->Encloses(PrevDecl->getDeclContext()))) { SemanticContext = PrevDecl->getDeclContext(); } else { // Declarations in outer scopes don't matter. However, the outermost // context we computed is the semantic context for our new // declaration. - PrevDecl = 0; + PrevDecl = PrevClassTemplate = 0; SemanticContext = OutermostContext; } @@ -717,30 +762,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // class template to the template in scope, because that would perform // checking of the template parameter lists that can't be performed // until the outer context is instantiated. - PrevDecl = 0; + PrevDecl = PrevClassTemplate = 0; } } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S)) - PrevDecl = 0; - - // If there is a previous declaration with the same name, check - // whether this is a valid redeclaration. - ClassTemplateDecl *PrevClassTemplate - = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl); - - // We may have found the injected-class-name of a class template, - // class template partial specialization, or class template specialization. - // In these cases, grab the template that is being defined or specialized. - if (!PrevClassTemplate && PrevDecl && isa<CXXRecordDecl>(PrevDecl) && - cast<CXXRecordDecl>(PrevDecl)->isInjectedClassName()) { - PrevDecl = cast<CXXRecordDecl>(PrevDecl->getDeclContext()); - PrevClassTemplate - = cast<CXXRecordDecl>(PrevDecl)->getDescribedClassTemplate(); - if (!PrevClassTemplate && isa<ClassTemplateSpecializationDecl>(PrevDecl)) { - PrevClassTemplate - = cast<ClassTemplateSpecializationDecl>(PrevDecl) - ->getSpecializedTemplate(); - } - } + PrevDecl = PrevClassTemplate = 0; if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. @@ -2188,6 +2213,9 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR; Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here); return true; + } else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) { + SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange(); + return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR; } return false; @@ -2484,7 +2512,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // Check that we don't overflow the template parameter type. unsigned AllowedBits = Context.getTypeSize(IntegerType); - if (Value.getActiveBits() > AllowedBits) { + unsigned RequiredBits; + if (IntegerType->isUnsignedIntegerType()) + RequiredBits = Value.getActiveBits(); + else if (Value.isUnsigned()) + RequiredBits = Value.getActiveBits() + 1; + else + RequiredBits = Value.getMinSignedBits(); + if (RequiredBits > AllowedBits) { Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_too_large) << Value.toString(10) << Param->getType() diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index b4754db..21f7996 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -337,58 +337,6 @@ DeduceTemplateArguments(ASTContext &Context, return Sema::TDK_Success; } -/// \brief Returns a completely-unqualified array type, capturing the -/// qualifiers in Quals. -/// -/// \param Context the AST context in which the array type was built. -/// -/// \param T a canonical type that may be an array type. -/// -/// \param Quals will receive the full set of qualifiers that were -/// applied to the element type of the array. -/// -/// \returns if \p T is an array type, the completely unqualified array type -/// that corresponds to T. Otherwise, returns T. -static QualType getUnqualifiedArrayType(ASTContext &Context, QualType T, - Qualifiers &Quals) { - assert(T.isCanonical() && "Only operates on canonical types"); - if (!isa<ArrayType>(T)) { - Quals = T.getLocalQualifiers(); - return T.getLocalUnqualifiedType(); - } - - assert(!T.hasQualifiers() && "canonical array type has qualifiers!"); - - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) { - QualType Elt = getUnqualifiedArrayType(Context, CAT->getElementType(), - Quals); - if (Elt == CAT->getElementType()) - return T; - - return Context.getConstantArrayType(Elt, CAT->getSize(), - CAT->getSizeModifier(), 0); - } - - if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(T)) { - QualType Elt = getUnqualifiedArrayType(Context, IAT->getElementType(), - Quals); - if (Elt == IAT->getElementType()) - return T; - - return Context.getIncompleteArrayType(Elt, IAT->getSizeModifier(), 0); - } - - const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T); - QualType Elt = getUnqualifiedArrayType(Context, DSAT->getElementType(), - Quals); - if (Elt == DSAT->getElementType()) - return T; - - return Context.getDependentSizedArrayType(Elt, DSAT->getSizeExpr()->Retain(), - DSAT->getSizeModifier(), 0, - SourceRange()); -} - /// \brief Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// @@ -427,9 +375,11 @@ DeduceTemplateArguments(ASTContext &Context, // referred to by the reference) can be more cv-qualified than the // transformed A. if (TDF & TDF_ParamWithReferenceType) { - Qualifiers Quals = Param.getQualifiers(); - Quals.setCVRQualifiers(Quals.getCVRQualifiers() & Arg.getCVRQualifiers()); - Param = Context.getQualifiedType(Param.getUnqualifiedType(), Quals); + Qualifiers Quals; + QualType UnqualParam = Context.getUnqualifiedArrayType(Param, Quals); + Quals.setCVRQualifiers(Quals.getCVRQualifiers() & + Arg.getCVRQualifiersThroughArrayTypes()); + Param = Context.getQualifiedType(UnqualParam, Quals); } // If the parameter type is not dependent, there is nothing to deduce. @@ -459,7 +409,7 @@ DeduceTemplateArguments(ASTContext &Context, // FIXME: address spaces, ObjC GC qualifiers if (isa<ArrayType>(Arg)) { Qualifiers Quals; - Arg = getUnqualifiedArrayType(Context, Arg, Quals); + Arg = Context.getUnqualifiedArrayType(Arg, Quals); if (Quals) { Arg = Context.getQualifiedType(Arg, Quals); RecanonicalizeArg = true; @@ -476,7 +426,7 @@ DeduceTemplateArguments(ASTContext &Context, } assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0"); - + assert(Arg != Context.OverloadTy && "Unresolved overloaded function"); QualType DeducedType = Arg; DeducedType.removeCVRQualifiers(Param.getCVRQualifiers()); if (RecanonicalizeArg) @@ -1506,15 +1456,39 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, ParamType->getAs<PointerType>()->getPointeeType()))) TDF |= TDF_DerivedClass; + // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function + // pointer parameters. + + if (Context.hasSameUnqualifiedType(ArgType, Context.OverloadTy)) { + // We know that template argument deduction will fail if the argument is + // still an overloaded function. Check whether we can resolve this + // argument as a single function template specialization per + // C++ [temp.arg.explicit]p3. + FunctionDecl *ExplicitSpec + = ResolveSingleFunctionTemplateSpecialization(Args[I]); + Expr *ResolvedArg = 0; + if (ExplicitSpec) + ResolvedArg = FixOverloadedFunctionReference(Args[I], ExplicitSpec); + if (!ExplicitSpec || !ResolvedArg) { + // Template argument deduction fails if we can't resolve the overloaded + // function. + return TDK_FailedOverloadResolution; + } + + // Get the type of the resolved argument. + ArgType = ResolvedArg->getType(); + if (ArgType->isPointerType() || ArgType->isMemberPointerType()) + TDF |= TDF_IgnoreQualifiers; + + ResolvedArg->Destroy(Context); + } + if (TemplateDeductionResult Result = ::DeduceTemplateArguments(Context, TemplateParams, ParamType, ArgType, Info, Deduced, TDF)) return Result; - // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function - // pointer parameters. - // FIXME: we need to check that the deduced A is the same as A, // modulo the various allowed differences. } @@ -1524,24 +1498,19 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, } /// \brief Deduce template arguments when taking the address of a function -/// template (C++ [temp.deduct.funcaddr]) or matching a +/// template (C++ [temp.deduct.funcaddr]) or matching a specialization to +/// a template. /// /// \param FunctionTemplate the function template for which we are performing /// template argument deduction. /// -/// \param HasExplicitTemplateArgs whether any template arguments were -/// explicitly specified. -/// -/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, -/// the explicitly-specified template arguments. -/// -/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, -/// the number of explicitly-specified template arguments in -/// @p ExplicitTemplateArguments. This value may be zero. +/// \param ExplicitTemplateArguments the explicitly-specified template +/// arguments. /// /// \param ArgFunctionType the function type that will be used as the /// "argument" type (A) when performing template argument deduction from the -/// function template's function type. +/// function template's function type. This type may be NULL, if there is no +/// argument type to compare against, in C++0x [temp.arg.explicit]p3. /// /// \param Specialization if template argument deduction was successful, /// this will be set to the function template specialization produced by @@ -1578,14 +1547,16 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // Trap any errors that might occur. SFINAETrap Trap(*this); - // Deduce template arguments from the function type. - Deduced.resize(TemplateParams->size()); - if (TemplateDeductionResult Result - = ::DeduceTemplateArguments(Context, TemplateParams, - FunctionType, ArgFunctionType, Info, - Deduced, 0)) - return Result; - + if (!ArgFunctionType.isNull()) { + // Deduce template arguments from the function type. + Deduced.resize(TemplateParams->size()); + if (TemplateDeductionResult Result + = ::DeduceTemplateArguments(Context, TemplateParams, + FunctionType, ArgFunctionType, Info, + Deduced, 0)) + return Result; + } + return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, Specialization, Info); } @@ -1694,6 +1665,32 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, return Result; } +/// \brief Deduce template arguments for a function template when there is +/// nothing to deduce against (C++0x [temp.arg.explicit]p3). +/// +/// \param FunctionTemplate the function template for which we are performing +/// template argument deduction. +/// +/// \param ExplicitTemplateArguments the explicitly-specified template +/// arguments. +/// +/// \param Specialization if template argument deduction was successful, +/// this will be set to the function template specialization produced by +/// template argument deduction. +/// +/// \param Info the argument will be updated to provide additional information +/// about template argument deduction. +/// +/// \returns the result of template argument deduction. +Sema::TemplateDeductionResult +Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + const TemplateArgumentListInfo *ExplicitTemplateArgs, + FunctionDecl *&Specialization, + TemplateDeductionInfo &Info) { + return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, + QualType(), Specialization, Info); +} + /// \brief Stores the result of comparing the qualifiers of two types. enum DeductionQualifierComparison { NeitherMoreQualified = 0, @@ -2354,7 +2351,6 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, // None of these types have any template parameters in them. case Type::Builtin: - case Type::FixedWidthInt: case Type::VariableArray: case Type::FunctionNoProto: case Type::Record: diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index dddb93c8..d974f89 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -554,7 +554,6 @@ namespace { Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E); Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E); - Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E); /// \brief Transforms a template type parameter type by performing @@ -785,7 +784,9 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( assert(!cast<FunctionDecl>(E->getParam()->getDeclContext())-> getDescribedFunctionTemplate() && "Default arg expressions are never formed in dependent cases."); - return SemaRef.Owned(E->Retain()); + return SemaRef.BuildCXXDefaultArgExpr(E->getUsedLocation(), + cast<FunctionDecl>(E->getParam()->getDeclContext()), + E->getParam()); } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8d74bd7..e909c4f 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -145,6 +145,11 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { if (Invalid) Typedef->setInvalidDecl(); + if (TypedefDecl *Prev = D->getPreviousDeclaration()) { + NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(Prev, TemplateArgs); + Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev)); + } + Owner->addDecl(Typedef); return Typedef; @@ -396,7 +401,16 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { // FIXME: We have a problem here, because the nested call to Visit(ND) // will inject the thing that the friend references into the current // owner, which is wrong. - Decl *NewND = Visit(ND); + Decl *NewND; + + // Hack to make this work almost well pending a rewrite. + if (ND->getDeclContext()->isRecord()) + NewND = SemaRef.FindInstantiatedDecl(ND, TemplateArgs); + else if (D->wasSpecialization()) { + // Totally egregious hack to work around PR5866 + return 0; + } else + NewND = Visit(ND); if (!NewND) return 0; FU = cast<NamedDecl>(NewND); @@ -645,6 +659,12 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { CXXRecordDecl *PrevDecl = 0; if (D->isInjectedClassName()) PrevDecl = cast<CXXRecordDecl>(Owner); + else if (D->getPreviousDeclaration()) { + NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getPreviousDeclaration(), + TemplateArgs); + if (!Prev) return 0; + PrevDecl = cast<CXXRecordDecl>(Prev); + } CXXRecordDecl *Record = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner, @@ -675,7 +695,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { /// 1) instantiating function templates /// 2) substituting friend declarations /// FIXME: preserve function definitions in case #2 - Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, +Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, TemplateParameterList *TemplateParams) { // Check whether there is already a function template specialization for // this declaration. @@ -1149,6 +1169,8 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { if (NewUD->isInvalidDecl()) return NewUD; + bool isFunctionScope = Owner->isFunctionOrMethod(); + // Process the shadow decls. for (UsingDecl::shadow_iterator I = D->shadow_begin(), E = D->shadow_end(); I != E; ++I) { @@ -1164,6 +1186,9 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { UsingShadowDecl *InstShadow = SemaRef.BuildUsingShadowDecl(/*Scope*/ 0, NewUD, InstTarget); SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstShadow, Shadow); + + if (isFunctionScope) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(Shadow, InstShadow); } return NewUD; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 37f19f2..ed30229 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -308,7 +308,11 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ Expr *E = static_cast<Expr *>(DS.getTypeRep()); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. - Result = Context.getTypeOfExprType(E); + Result = TheSema.BuildTypeofExprType(E); + if (Result.isNull()) { + Result = Context.IntTy; + TheDeclarator.setInvalidType(true); + } break; } case DeclSpec::TST_decltype: { @@ -1826,14 +1830,41 @@ QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) { } QualType Sema::BuildTypeofExprType(Expr *E) { + if (E->getType() == Context.OverloadTy) { + // C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a + // function template specialization wherever deduction cannot occur. + if (FunctionDecl *Specialization + = ResolveSingleFunctionTemplateSpecialization(E)) { + E = FixOverloadedFunctionReference(E, Specialization); + if (!E) + return QualType(); + } else { + Diag(E->getLocStart(), + diag::err_cannot_determine_declared_type_of_overloaded_function) + << false << E->getSourceRange(); + return QualType(); + } + } + return Context.getTypeOfExprType(E); } QualType Sema::BuildDecltypeType(Expr *E) { if (E->getType() == Context.OverloadTy) { - Diag(E->getLocStart(), - diag::err_cannot_determine_declared_type_of_overloaded_function); - return QualType(); + // C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a + // function template specialization wherever deduction cannot occur. + if (FunctionDecl *Specialization + = ResolveSingleFunctionTemplateSpecialization(E)) { + E = FixOverloadedFunctionReference(E, Specialization); + if (!E) + return QualType(); + } else { + Diag(E->getLocStart(), + diag::err_cannot_determine_declared_type_of_overloaded_function) + << true << E->getSourceRange(); + return QualType(); + } } + return Context.getDecltypeType(E); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index fd19987..208c885 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -956,8 +956,12 @@ public: // We have a reference to an unnamed field. assert(!Qualifier && "Can't have an unnamed field with a qualifier!"); + Expr *BaseExpr = Base.takeAs<Expr>(); + if (getSema().PerformObjectMemberConversion(BaseExpr, Member)) + return getSema().ExprError(); + MemberExpr *ME = - new (getSema().Context) MemberExpr(Base.takeAs<Expr>(), isArrow, + new (getSema().Context) MemberExpr(BaseExpr, isArrow, Member, MemberLoc, cast<FieldDecl>(Member)->getType()); return getSema().Owned(ME); @@ -1358,8 +1362,10 @@ public: /// By default, builds a new default-argument expression, which does not /// require any semantic analysis. Subclasses may override this routine to /// provide different behavior. - OwningExprResult RebuildCXXDefaultArgExpr(ParmVarDecl *Param) { - return getSema().Owned(CXXDefaultArgExpr::Create(getSema().Context, Param)); + OwningExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, + ParmVarDecl *Param) { + return getSema().Owned(CXXDefaultArgExpr::Create(getSema().Context, Loc, + Param)); } /// \brief Build a new C++ zero-initialization expression. @@ -1655,7 +1661,7 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) { if (E.isInvalid()) return getSema().StmtError(); - return getSema().ActOnExprStmt(getSema().FullExpr(E)); + return getSema().ActOnExprStmt(getSema().MakeFullExpr(E)); } } @@ -2128,13 +2134,6 @@ QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, } template<typename Derived> -QualType -TreeTransform<Derived>::TransformFixedWidthIntType(TypeLocBuilder &TLB, - FixedWidthIntTypeLoc T) { - return TransformTypeSpecType(TLB, T); -} - -template<typename Derived> QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB, ComplexTypeLoc T) { // FIXME: recurse? @@ -3067,7 +3066,7 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { return SemaRef.StmtError(); } - Sema::FullExprArg FullCond(getSema().FullExpr(Cond)); + Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond)); // Transform the "then" branch. OwningStmtResult Then = getDerived().TransformStmt(S->getThen()); @@ -3110,7 +3109,7 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) { return SemaRef.StmtError(); } - Sema::FullExprArg FullCond(getSema().FullExpr(Cond)); + Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond)); // Rebuild the switch statement. OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(FullCond, @@ -3147,7 +3146,7 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { return SemaRef.StmtError(); } - Sema::FullExprArg FullCond(getSema().FullExpr(Cond)); + Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond)); // Transform the body OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); @@ -3229,9 +3228,9 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) { return SemaRef.Owned(S->Retain()); return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(), - move(Init), getSema().FullExpr(Cond), + move(Init), getSema().MakeFullExpr(Cond), ConditionVar, - getSema().FullExpr(Inc), + getSema().MakeFullExpr(Inc), S->getRParenLoc(), move(Body)); } @@ -3688,8 +3687,13 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { Base.get() == E->getBase() && Qualifier == E->getQualifier() && Member == E->getMemberDecl() && - !E->hasExplicitTemplateArgumentList()) + !E->hasExplicitTemplateArgumentList()) { + + // Mark it referenced in the new context regardless. + // FIXME: this is a bit instantiation-specific. + SemaRef.MarkDeclarationReferenced(E->getMemberLoc(), Member); return SemaRef.Owned(E->Retain()); + } TemplateArgumentListInfo TransArgs; if (E->hasExplicitTemplateArgumentList()) { @@ -4411,7 +4415,7 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { Param == E->getParam()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCXXDefaultArgExpr(Param); + return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param); } template<typename Derived> @@ -4476,6 +4480,31 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { !ArgumentChanged) return SemaRef.Owned(E->Retain()); + if (!ArraySize.get()) { + // If no array size was specified, but the new expression was + // instantiated with an array type (e.g., "new T" where T is + // instantiated with "int[4]"), extract the outer bound from the + // array type as our array size. We do this with constant and + // dependently-sized array types. + const ArrayType *ArrayT = SemaRef.Context.getAsArrayType(AllocType); + if (!ArrayT) { + // Do nothing + } else if (const ConstantArrayType *ConsArrayT + = dyn_cast<ConstantArrayType>(ArrayT)) { + ArraySize + = SemaRef.Owned(new (SemaRef.Context) IntegerLiteral( + ConsArrayT->getSize(), + SemaRef.Context.getSizeType(), + /*FIXME:*/E->getLocStart())); + AllocType = ConsArrayT->getElementType(); + } else if (const DependentSizedArrayType *DepArrayT + = dyn_cast<DependentSizedArrayType>(ArrayT)) { + if (DepArrayT->getSizeExpr()) { + ArraySize = SemaRef.Owned(DepArrayT->getSizeExpr()->Retain()); + AllocType = DepArrayT->getElementType(); + } + } + } return getDerived().RebuildCXXNewExpr(E->getLocStart(), E->isGlobalNew(), /*FIXME:*/E->getLocStart(), @@ -4725,38 +4754,24 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { /// \brief Transform a C++ temporary-binding expression. /// -/// The transformation of a temporary-binding expression always attempts to -/// bind a new temporary variable to its subexpression, even if the -/// subexpression itself did not change, because the temporary variable itself -/// must be unique. +/// Since CXXBindTemporaryExpr nodes are implicitly generated, we just +/// transform the subexpression and return that. template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); - if (SubExpr.isInvalid()) - return SemaRef.ExprError(); - - return SemaRef.MaybeBindToTemporary(SubExpr.takeAs<Expr>()); + return getDerived().TransformExpr(E->getSubExpr()); } /// \brief Transform a C++ expression that contains temporaries that should /// be destroyed after the expression is evaluated. /// -/// The transformation of a full expression always attempts to build a new -/// CXXExprWithTemporaries expression, even if the -/// subexpression itself did not change, because it will need to capture the -/// the new temporary variables introduced in the subexpression. +/// Since CXXExprWithTemporaries nodes are implicitly generated, we +/// just transform the subexpression and return that. template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXExprWithTemporaries( - CXXExprWithTemporaries *E) { - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); - if (SubExpr.isInvalid()) - return SemaRef.ExprError(); - - return SemaRef.Owned( - SemaRef.MaybeCreateCXXExprWithTemporaries(SubExpr.takeAs<Expr>(), - E->shouldDestroyTemporaries())); + CXXExprWithTemporaries *E) { + return getDerived().TransformExpr(E->getSubExpr()); } template<typename Derived> @@ -5233,9 +5248,6 @@ TreeTransform<Derived>::RebuildArrayType(QualType ElementType, break; } - if (SizeType.isNull()) - SizeType = SemaRef.Context.getFixedWidthIntType(Size->getBitWidth(), false); - IntegerLiteral ArraySize(*Size, SizeType, /*FIXME*/BracketsRange.getBegin()); return SemaRef.BuildArrayType(ElementType, SizeMod, &ArraySize, IndexTypeQuals, BracketsRange, |