diff options
author | Eli Bendersky <eliben@chromium.org> | 2013-07-15 16:08:08 -0700 |
---|---|---|
committer | Eli Bendersky <eliben@chromium.org> | 2013-07-15 16:08:08 -0700 |
commit | e789858899a7b36caf11b371a97411a1582a482b (patch) | |
tree | e8c28b178b32010f73b477b3c65b5ff74437530c /lib | |
parent | 99a5501f5ae5b75017dfc386d4abf648234e85df (diff) | |
parent | 20c7d45a4da9f58ad805ad1d37f92fe7dc232ec8 (diff) |
Merge commit '20c7d45a4da9f58ad805ad1d37f92fe7dc232ec8'
Conflicts:
lib/CodeGen/ItaniumCXXABI.cpp
Diffstat (limited to 'lib')
287 files changed, 22787 insertions, 9408 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp index 72f35205ca..a6d48762fe 100644 --- a/lib/ARCMigrate/ARCMT.cpp +++ b/lib/ARCMigrate/ARCMT.cpp @@ -140,12 +140,6 @@ public: // Non-ARC warnings are ignored. Diags.setLastDiagnosticIgnored(); } - - DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { - // Just drop any diagnostics that come from cloned consumers; they'll - // have different source managers anyway. - return new IgnoringDiagConsumer(); - } }; } // end anonymous namespace @@ -482,7 +476,7 @@ public: : ARCMTMacroLocs(ARCMTMacroLocs) { } virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD, - SourceRange Range) { + SourceRange Range, const MacroArgs *Args) { if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); } diff --git a/lib/ARCMigrate/TransAPIUses.cpp b/lib/ARCMigrate/TransAPIUses.cpp index 2305b6defd..a0994a6b45 100644 --- a/lib/ARCMigrate/TransAPIUses.cpp +++ b/lib/ARCMigrate/TransAPIUses.cpp @@ -91,12 +91,12 @@ public: E->getSelector() == zoneSel && Pass.TA.hasDiagnostic(diag::err_unavailable, diag::err_unavailable_message, - E->getInstanceReceiver()->getExprLoc())) { + E->getSelectorLoc(0))) { // Calling -zone is meaningless in ARC, change it to nil. Transaction Trans(Pass.TA); Pass.TA.clearDiagnostic(diag::err_unavailable, diag::err_unavailable_message, - E->getInstanceReceiver()->getExprLoc()); + E->getSelectorLoc(0)); Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx)); } return true; diff --git a/lib/ARCMigrate/TransProtectedScope.cpp b/lib/ARCMigrate/TransProtectedScope.cpp index b8b25f2594..237aa42877 100644 --- a/lib/ARCMigrate/TransProtectedScope.cpp +++ b/lib/ARCMigrate/TransProtectedScope.cpp @@ -109,7 +109,12 @@ public: SourceRange BodyRange = BodyCtx.getTopStmt()->getSourceRange(); const CapturedDiagList &DiagList = Pass.getDiags(); - CapturedDiagList::iterator I = DiagList.begin(), E = DiagList.end(); + // Copy the diagnostics so we don't have to worry about invaliding iterators + // from the diagnostic list. + SmallVector<StoredDiagnostic, 16> StoredDiags; + StoredDiags.append(DiagList.begin(), DiagList.end()); + SmallVectorImpl<StoredDiagnostic>::iterator + I = StoredDiags.begin(), E = StoredDiags.end(); while (I != E) { if (I->getID() == diag::err_switch_into_protected_scope && isInRange(I->getLocation(), BodyRange)) { @@ -120,8 +125,9 @@ public: } } - void handleProtectedScopeError(CapturedDiagList::iterator &DiagI, - CapturedDiagList::iterator DiagE) { + void handleProtectedScopeError( + SmallVectorImpl<StoredDiagnostic>::iterator &DiagI, + SmallVectorImpl<StoredDiagnostic>::iterator DiagE){ Transaction Trans(Pass.TA); assert(DiagI->getID() == diag::err_switch_into_protected_scope); SourceLocation ErrLoc = DiagI->getLocation(); diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp index 0c8d155446..446a284a28 100644 --- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp +++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp @@ -118,7 +118,7 @@ public: return true; case ObjCMessageExpr::SuperInstance: { Transaction Trans(Pass.TA); - clearDiagnostics(E->getSuperLoc()); + clearDiagnostics(E->getSelectorLoc(0)); if (tryRemoving(E)) return true; Pass.TA.replace(E->getSourceRange(), "self"); @@ -132,7 +132,7 @@ public: if (!rec) return true; Transaction Trans(Pass.TA); - clearDiagnostics(rec->getExprLoc()); + clearDiagnostics(E->getSelectorLoc(0)); ObjCMessageExpr *Msg = E; Expr *RecContainer = Msg; diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h index cb7d1535c6..e20fe5927f 100644 --- a/lib/ARCMigrate/Transforms.h +++ b/lib/ARCMigrate/Transforms.h @@ -169,7 +169,7 @@ bool isPlusOne(const Expr *E); /// source location will be invalid. SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx); -/// \brief \arg Loc is the end of a statement range. This returns the location +/// \brief 'Loc' is the end of a statement range. This returns the location /// of the semicolon following the statement. /// If no semicolon is found or the location is inside a macro, the returned /// source location will be invalid. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index b55a926e32..176aec53a2 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -97,7 +97,12 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return NULL; } - + if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { + // When tag declaration (but not definition!) is part of the + // decl-specifier-seq of some other declaration, it doesn't get comment + if (TD->isEmbeddedInDeclarator() && !TD->isCompleteDefinition()) + return NULL; + } // TODO: handle comments for function parameters properly. if (isa<ParmVarDecl>(D)) return NULL; @@ -141,7 +146,9 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { // When searching for comments during parsing, the comment we are looking // for is usually among the last two comments we parsed -- check them // first. - RawComment CommentAtDeclLoc(SourceMgr, SourceRange(DeclLoc)); + RawComment CommentAtDeclLoc( + SourceMgr, SourceRange(DeclLoc), false, + LangOpts.CommentOpts.ParseAllComments); BeforeThanCompare<RawComment> Compare(SourceMgr); ArrayRef<RawComment *>::iterator MaybeBeforeDecl = RawComments.end() - 1; bool Found = Compare(*MaybeBeforeDecl, &CommentAtDeclLoc); @@ -435,7 +442,7 @@ comments::FullComment *ASTContext::getCommentForDecl( if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP)) return cloneFullComment(FC, D); } - else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + else if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { // Attach any tag type's documentation to its typedef if latter // does not have one of its own. QualType QT = TD->getUnderlyingType(); @@ -444,6 +451,53 @@ comments::FullComment *ASTContext::getCommentForDecl( if (comments::FullComment *FC = getCommentForDecl(TD, PP)) return cloneFullComment(FC, D); } + else if (const ObjCInterfaceDecl *IC = dyn_cast<ObjCInterfaceDecl>(D)) { + while (IC->getSuperClass()) { + IC = IC->getSuperClass(); + if (comments::FullComment *FC = getCommentForDecl(IC, PP)) + return cloneFullComment(FC, D); + } + } + else if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) { + if (const ObjCInterfaceDecl *IC = CD->getClassInterface()) + if (comments::FullComment *FC = getCommentForDecl(IC, PP)) + return cloneFullComment(FC, D); + } + else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + if (!(RD = RD->getDefinition())) + return NULL; + // Check non-virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = + RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual() || (I->getAccessSpecifier() != AS_public)) + continue; + QualType Ty = I->getType(); + if (Ty.isNull()) + continue; + if (const CXXRecordDecl *NonVirtualBase = Ty->getAsCXXRecordDecl()) { + if (!(NonVirtualBase= NonVirtualBase->getDefinition())) + continue; + + if (comments::FullComment *FC = getCommentForDecl((NonVirtualBase), PP)) + return cloneFullComment(FC, D); + } + } + // Check virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = + RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) { + if (I->getAccessSpecifier() != AS_public) + continue; + QualType Ty = I->getType(); + if (Ty.isNull()) + continue; + if (const CXXRecordDecl *VirtualBase = Ty->getAsCXXRecordDecl()) { + if (!(VirtualBase= VirtualBase->getDefinition())) + continue; + if (comments::FullComment *FC = getCommentForDecl((VirtualBase), PP)) + return cloneFullComment(FC, D); + } + } + } return NULL; } @@ -1125,8 +1179,8 @@ void ASTContext::getOverriddenMethods( assert(D); if (const CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) { - Overridden.append(CXXMethod->begin_overridden_methods(), - CXXMethod->end_overridden_methods()); + Overridden.append(overridden_methods_begin(CXXMethod), + overridden_methods_end(CXXMethod)); return; } @@ -1229,6 +1283,10 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { T = getBaseElementType(arrayType); } Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->hasGlobalStorage()) + Align = std::max(Align, getTargetInfo().getMinGlobalAlign()); + } } // Fields can be subject to extra alignment constraints, like if @@ -1496,10 +1554,7 @@ ASTContext::getTypeInfoImpl(const Type *T) const { } case Type::MemberPointer: { const MemberPointerType *MPT = cast<MemberPointerType>(T); - std::pair<uint64_t, unsigned> PtrDiffInfo = - getTypeInfo(getPointerDiffType()); - Width = PtrDiffInfo.first * ABI->getMemberPointerSize(MPT); - Align = PtrDiffInfo.second; + llvm::tie(Width, Align) = ABI->getMemberPointerWidthAndAlign(MPT); break; } case Type::Complex: { @@ -1546,7 +1601,8 @@ ASTContext::getTypeInfoImpl(const Type *T) const { case Type::Auto: { const AutoType *A = cast<AutoType>(T); - assert(A->isDeduced() && "Cannot request the size of a dependent type"); + assert(!A->getDeducedType().isNull() && + "cannot request the size of an undeduced or dependent auto type"); return getTypeInfo(A->getDeducedType().getTypePtr()); } @@ -1673,6 +1729,18 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { return ABIAlign; } +/// getAlignOfGlobalVar - Return the alignment in bits that should be given +/// to a global variable of the specified type. +unsigned ASTContext::getAlignOfGlobalVar(QualType T) const { + return std::max(getTypeAlign(T), getTargetInfo().getMinGlobalAlign()); +} + +/// getAlignOfGlobalVarInChars - Return the alignment in characters that +/// should be given to a global variable of the specified type. +CharUnits ASTContext::getAlignOfGlobalVarInChars(QualType T) const { + return toCharUnitsFromBits(getAlignOfGlobalVar(T)); +} + /// DeepCollectObjCIvars - /// This routine first collects all declared, but not synthesized, ivars in /// super class and then collects all ivars, including those synthesized for @@ -1983,6 +2051,16 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T, return cast<FunctionType>(Result.getTypePtr()); } +void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD, + QualType ResultType) { + // FIXME: Need to inform serialization code about this! + for (FD = FD->getMostRecentDecl(); FD; FD = FD->getPreviousDecl()) { + const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + FD->setType(getFunctionType(ResultType, FPT->getArgTypes(), EPI)); + } +} + /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType ASTContext::getComplexType(QualType T) const { @@ -3511,18 +3589,24 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType, return QualType(Ty, 0); } -/// getAutoType - We only unique auto types after they've been deduced. -QualType ASTContext::getAutoType(QualType DeducedType) const { +/// getAutoType - Return the uniqued reference to the 'auto' type which has been +/// deduced to the given type, or to the canonical undeduced 'auto' type, or the +/// canonical deduced-but-dependent 'auto' type. +QualType ASTContext::getAutoType(QualType DeducedType, bool IsDecltypeAuto, + bool IsDependent) const { + if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent) + return getAutoDeductType(); + + // Look in the folding set for an existing type. void *InsertPos = 0; - if (!DeducedType.isNull()) { - // Look in the folding set for an existing type. - llvm::FoldingSetNodeID ID; - AutoType::Profile(ID, DeducedType); - if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(AT, 0); - } + llvm::FoldingSetNodeID ID; + AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent); + if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(AT, 0); - AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType); + AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType, + IsDecltypeAuto, + IsDependent); Types.push_back(AT); if (InsertPos) AutoTypes.InsertNode(AT, InsertPos); @@ -3560,8 +3644,10 @@ QualType ASTContext::getAtomicType(QualType T) const { /// getAutoDeductType - Get type pattern for deducing against 'auto'. QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) - AutoDeductTy = getAutoType(QualType()); - assert(!AutoDeductTy.isNull() && "can't build 'auto' pattern"); + AutoDeductTy = QualType( + new (*this, TypeAlignment) AutoType(QualType(), /*decltype(auto)*/false, + /*dependent*/false), + 0); return AutoDeductTy; } @@ -4191,7 +4277,7 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { if (E->isTypeDependent() || E->isValueDependent()) return QualType(); - FieldDecl *Field = E->getBitField(); + FieldDecl *Field = E->getSourceBitField(); // FIXME: conditional bit-fields? if (!Field) return QualType(); @@ -5334,6 +5420,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // FIXME. We should do a better job than gcc. return; + case Type::Auto: + // We could see an undeduced auto type here during error recovery. + // Just ignore it. + return; + #define ABSTRACT_TYPE(KIND, BASE) #define TYPE(KIND, BASE) #define DEPENDENT_TYPE(KIND, BASE) \ @@ -5889,6 +5980,80 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) { return VaListTypeDecl; } +static TypedefDecl * +CreateSystemZBuiltinVaListDecl(const ASTContext *Context) { + // typedef struct __va_list_tag { + RecordDecl *VaListTagDecl; + VaListTagDecl = CreateRecordDecl(*Context, TTK_Struct, + Context->getTranslationUnitDecl(), + &Context->Idents.get("__va_list_tag")); + VaListTagDecl->startDefinition(); + + const size_t NumFields = 4; + QualType FieldTypes[NumFields]; + const char *FieldNames[NumFields]; + + // long __gpr; + FieldTypes[0] = Context->LongTy; + FieldNames[0] = "__gpr"; + + // long __fpr; + FieldTypes[1] = Context->LongTy; + FieldNames[1] = "__fpr"; + + // void *__overflow_arg_area; + FieldTypes[2] = Context->getPointerType(Context->VoidTy); + FieldNames[2] = "__overflow_arg_area"; + + // void *__reg_save_area; + FieldTypes[3] = Context->getPointerType(Context->VoidTy); + FieldNames[3] = "__reg_save_area"; + + // Create fields + for (unsigned i = 0; i < NumFields; ++i) { + FieldDecl *Field = FieldDecl::Create(const_cast<ASTContext &>(*Context), + VaListTagDecl, + SourceLocation(), + SourceLocation(), + &Context->Idents.get(FieldNames[i]), + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, + ICIS_NoInit); + Field->setAccess(AS_public); + VaListTagDecl->addDecl(Field); + } + VaListTagDecl->completeDefinition(); + QualType VaListTagType = Context->getRecordType(VaListTagDecl); + Context->VaListTagTy = VaListTagType; + + // } __va_list_tag; + TypedefDecl *VaListTagTypedefDecl + = TypedefDecl::Create(const_cast<ASTContext &>(*Context), + Context->getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Context->Idents.get("__va_list_tag"), + Context->getTrivialTypeSourceInfo(VaListTagType)); + QualType VaListTagTypedefType = + Context->getTypedefType(VaListTagTypedefDecl); + + // typedef __va_list_tag __builtin_va_list[1]; + llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1); + QualType VaListTagArrayType + = Context->getConstantArrayType(VaListTagTypedefType, + Size, ArrayType::Normal,0); + TypeSourceInfo *TInfo + = Context->getTrivialTypeSourceInfo(VaListTagArrayType); + TypedefDecl *VaListTypedefDecl + = TypedefDecl::Create(const_cast<ASTContext &>(*Context), + Context->getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Context->Idents.get("__builtin_va_list"), + TInfo); + + return VaListTypedefDecl; +} + static TypedefDecl *CreateVaListDecl(const ASTContext *Context, TargetInfo::BuiltinVaListKind Kind) { switch (Kind) { @@ -5906,6 +6071,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context, return CreatePNaClABIBuiltinVaListDecl(Context); case TargetInfo::AAPCSABIBuiltinVaList: return CreateAAPCSABIBuiltinVaListDecl(Context); + case TargetInfo::SystemZBuiltinVaList: + return CreateSystemZBuiltinVaListDecl(Context); } llvm_unreachable("Unhandled __builtin_va_list type kind"); @@ -6844,6 +7011,27 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, return getFunctionNoProtoType(retType, einfo); } +/// Given that we have an enum type and a non-enum type, try to merge them. +static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET, + QualType other, bool isBlockReturnType) { + // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, + // a signed integer type, or an unsigned integer type. + // Compatibility is based on the underlying type, not the promotion + // type. + QualType underlyingType = ET->getDecl()->getIntegerType(); + if (underlyingType.isNull()) return QualType(); + if (Context.hasSameType(underlyingType, other)) + return other; + + // In block return types, we're more permissive and accept any + // integral type of the same size. + if (isBlockReturnType && other->isIntegerType() && + Context.getTypeSize(underlyingType) == Context.getTypeSize(other)) + return other; + + return QualType(); +} + QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, bool Unqualified, bool BlockReturnType) { @@ -6925,19 +7113,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, // If the canonical type classes don't match. if (LHSClass != RHSClass) { - // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, - // a signed integer type, or an unsigned integer type. - // Compatibility is based on the underlying type, not the promotion - // type. + // Note that we only have special rules for turning block enum + // returns into block int returns, not vice-versa. if (const EnumType* ETy = LHS->getAs<EnumType>()) { - QualType TINT = ETy->getDecl()->getIntegerType(); - if (!TINT.isNull() && hasSameType(TINT, RHSCan.getUnqualifiedType())) - return RHS; + return mergeEnumWithInteger(*this, ETy, RHS, false); } if (const EnumType* ETy = RHS->getAs<EnumType>()) { - QualType TINT = ETy->getDecl()->getIntegerType(); - if (!TINT.isNull() && hasSameType(TINT, LHSCan.getUnqualifiedType())) - return LHS; + return mergeEnumWithInteger(*this, ETy, LHS, BlockReturnType); } // allow block pointer type to match an 'id' type. if (OfBlockPointer && !BlockReturnType) { @@ -6960,6 +7142,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, #include "clang/AST/TypeNodes.def" llvm_unreachable("Non-canonical and dependent types shouldn't get here"); + case Type::Auto: case Type::LValueReference: case Type::RValueReference: case Type::MemberPointer: @@ -7661,7 +7844,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (!VD->isFileVarDecl()) return false; - } else if (!isa<FunctionDecl>(D)) + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // We never need to emit an uninstantiated function template. + if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) + return false; + } else + return false; + + // If this is a member of a class template, we do not need to emit it. + if (D->getDeclContext()->isDependentContext()) return false; // Weak references don't produce any output by themselves. diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index d67423ed3d..1ed65e476c 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -403,10 +403,31 @@ class TemplateDiff { /// DiffTree - A tree representation the differences between two types. class DiffTree { + public: + /// DiffKind - The difference in a DiffNode and which fields are used. + enum DiffKind { + /// Incomplete or invalid node. + Invalid, + /// Another level of templates, uses TemplateDecl and Qualifiers + Template, + /// Type difference, uses QualType + Type, + /// Expression difference, uses Expr + Expression, + /// Template argument difference, uses TemplateDecl + TemplateTemplate, + /// Integer difference, uses APSInt and Expr + Integer, + /// Declaration difference, uses ValueDecl + Declaration + }; + private: /// DiffNode - The root node stores the original type. Each child node /// stores template arguments of their parents. For templated types, the /// template decl is also stored. struct DiffNode { + DiffKind Kind; + /// NextNode - The index of the next sibling node or 0. unsigned NextNode; @@ -445,7 +466,7 @@ class TemplateDiff { bool Same; DiffNode(unsigned ParentNode = 0) - : NextNode(0), ChildNode(0), ParentNode(ParentNode), + : Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode), FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0), IsValidFromInt(false), IsValidToInt(false), FromValueDecl(0), ToValueDecl(0), FromDefault(false), ToDefault(false), Same(false) { } @@ -521,6 +542,11 @@ class TemplateDiff { FlatTree[CurrentNode].ToDefault = ToDefault; } + /// SetKind - Sets the current node's type. + void SetKind(DiffKind Kind) { + FlatTree[CurrentNode].Kind = Kind; + } + /// Up - Changes the node to the parent of the current node. void Up() { CurrentNode = FlatTree[CurrentNode].ParentNode; @@ -560,44 +586,6 @@ class TemplateDiff { ReadNode = FlatTree[ReadNode].ParentNode; } - /// NodeIsTemplate - Returns true if a template decl is set, and types are - /// set. - bool NodeIsTemplate() { - return (FlatTree[ReadNode].FromTD && - !FlatTree[ReadNode].ToType.isNull()) || - (FlatTree[ReadNode].ToTD && !FlatTree[ReadNode].ToType.isNull()); - } - - /// NodeIsQualType - Returns true if a Qualtype is set. - bool NodeIsQualType() { - return !FlatTree[ReadNode].FromType.isNull() || - !FlatTree[ReadNode].ToType.isNull(); - } - - /// NodeIsExpr - Returns true if an expr is set. - bool NodeIsExpr() { - return FlatTree[ReadNode].FromExpr || FlatTree[ReadNode].ToExpr; - } - - /// NodeIsTemplateTemplate - Returns true if the argument is a template - /// template type. - bool NodeIsTemplateTemplate() { - return FlatTree[ReadNode].FromType.isNull() && - FlatTree[ReadNode].ToType.isNull() && - (FlatTree[ReadNode].FromTD || FlatTree[ReadNode].ToTD); - } - - /// NodeIsAPSInt - Returns true if the arugments are stored in APSInt's. - bool NodeIsAPSInt() { - return FlatTree[ReadNode].IsValidFromInt || - FlatTree[ReadNode].IsValidToInt; - } - - /// NodeIsDecl - Returns true if the arguments are stored as Decl's. - bool NodeIsValueDecl() { - return FlatTree[ReadNode].FromValueDecl || FlatTree[ReadNode].ToValueDecl; - } - /// GetNode - Gets the FromType and ToType. void GetNode(QualType &FromType, QualType &ToType) { FromType = FlatTree[ReadNode].FromType; @@ -679,9 +667,12 @@ class TemplateDiff { /// Empty - Returns true if the tree has no information. bool Empty() { - return !FlatTree[0].FromTD && !FlatTree[0].ToTD && - !FlatTree[0].FromExpr && !FlatTree[0].ToExpr && - FlatTree[0].FromType.isNull() && FlatTree[0].ToType.isNull(); + return GetKind() == Invalid; + } + + /// GetKind - Returns the current node's type. + DiffKind GetKind() { + return FlatTree[ReadNode].Kind; } }; @@ -698,6 +689,10 @@ class TemplateDiff { /// traverse over. const TemplateSpecializationType *TST; + /// DesugarTST - desugared template specialization used to extract + /// default argument information + const TemplateSpecializationType *DesugarTST; + /// Index - the index of the template argument in TST. unsigned Index; @@ -710,8 +705,10 @@ class TemplateDiff { /// TSTiterator - Constructs an iterator and sets it to the first template /// argument. - TSTiterator(const TemplateSpecializationType *TST) - : TST(TST), Index(0), CurrentTA(0), EndTA(0) { + TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST) + : TST(TST), + DesugarTST(GetTemplateSpecializationType(Context, TST->desugar())), + Index(0), CurrentTA(0), EndTA(0) { if (isEnd()) return; // Set to first template argument. If not a parameter pack, done. @@ -732,12 +729,17 @@ class TemplateDiff { /// isEnd - Returns true if the iterator is one past the end. bool isEnd() const { - return Index == TST->getNumArgs(); + return Index >= TST->getNumArgs(); } /// &operator++ - Increment the iterator to the next template argument. TSTiterator &operator++() { - assert(!isEnd() && "Iterator incremented past end of arguments."); + // After the end, Index should be the default argument position in + // DesugarTST, if it exists. + if (isEnd()) { + ++Index; + return *this; + } // If in a parameter pack, advance in the parameter pack. if (CurrentTA != EndTA) { @@ -778,6 +780,11 @@ class TemplateDiff { pointer operator->() const { return &operator*(); } + + /// getDesugar - Returns the deduced template argument from DesguarTST + reference getDesugar() const { + return DesugarTST->getArg(Index); + } }; // These functions build up the template diff tree, including functions to @@ -804,7 +811,7 @@ class TemplateDiff { TemplateName(CTSD->getSpecializedTemplate()), CTSD->getTemplateArgs().data(), CTSD->getTemplateArgs().size(), - Ty.getCanonicalType()); + Ty.getLocalUnqualifiedType().getCanonicalType()); return Ty->getAs<TemplateSpecializationType>(); } @@ -817,7 +824,7 @@ class TemplateDiff { TemplateParameterList *Params = FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); unsigned TotalArgs = 0; - for (TSTiterator FromIter(FromTST), ToIter(ToTST); + for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST); !FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) { Tree.AddNode(); @@ -831,11 +838,12 @@ class TemplateDiff { if (TemplateTypeParmDecl *DefaultTTPD = dyn_cast<TemplateTypeParmDecl>(ParamND)) { QualType FromType, ToType; - GetType(FromIter, DefaultTTPD, FromType); - GetType(ToIter, DefaultTTPD, ToType); + FromType = GetType(FromIter, DefaultTTPD); + ToType = GetType(ToIter, DefaultTTPD); Tree.SetNode(FromType, ToType); Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(), ToIter.isEnd() && !ToType.isNull()); + Tree.SetKind(DiffTree::Type); if (!FromType.isNull() && !ToType.isNull()) { if (Context.hasSameType(FromType, ToType)) { Tree.SetSame(true); @@ -854,6 +862,7 @@ class TemplateDiff { Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(), ToArgTST->getTemplateName().getAsTemplateDecl()); Tree.SetNode(FromQual, ToQual); + Tree.SetKind(DiffTree::Template); DiffTemplate(FromArgTST, ToArgTST); } } @@ -863,7 +872,7 @@ class TemplateDiff { // Handle Expressions if (NonTypeTemplateParmDecl *DefaultNTTPD = dyn_cast<NonTypeTemplateParmDecl>(ParamND)) { - Expr *FromExpr, *ToExpr; + Expr *FromExpr = 0, *ToExpr = 0; llvm::APSInt FromInt, ToInt; ValueDecl *FromValueDecl = 0, *ToValueDecl = 0; unsigned ParamWidth = 128; // Safe default @@ -889,47 +898,57 @@ class TemplateDiff { else if (HasFromValueDecl) FromValueDecl = FromIter->getAsDecl(); else - GetExpr(FromIter, DefaultNTTPD, FromExpr); + FromExpr = GetExpr(FromIter, DefaultNTTPD); if (HasToInt) ToInt = ToIter->getAsIntegral(); else if (HasToValueDecl) ToValueDecl = ToIter->getAsDecl(); else - GetExpr(ToIter, DefaultNTTPD, ToExpr); + ToExpr = GetExpr(ToIter, DefaultNTTPD); if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) { Tree.SetNode(FromExpr, ToExpr); - Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr)); Tree.SetDefault(FromIter.isEnd() && FromExpr, ToIter.isEnd() && ToExpr); + if (DefaultNTTPD->getType()->isIntegralOrEnumerationType()) { + if (FromExpr) + FromInt = GetInt(FromIter, FromExpr); + if (ToExpr) + ToInt = GetInt(ToIter, ToExpr); + Tree.SetNode(FromInt, ToInt, FromExpr, ToExpr); + Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt)); + Tree.SetKind(DiffTree::Integer); + } else { + Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr)); + Tree.SetKind(DiffTree::Expression); + } } else if (HasFromInt || HasToInt) { if (!HasFromInt && FromExpr) { - FromInt = FromExpr->EvaluateKnownConstInt(Context); + FromInt = GetInt(FromIter, FromExpr); HasFromInt = true; } if (!HasToInt && ToExpr) { - ToInt = ToExpr->EvaluateKnownConstInt(Context); + ToInt = GetInt(ToIter, ToExpr); HasToInt = true; } Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt); Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt)); Tree.SetDefault(FromIter.isEnd() && HasFromInt, ToIter.isEnd() && HasToInt); + Tree.SetKind(DiffTree::Integer); } else { - if (!HasFromValueDecl && FromExpr) { - DeclRefExpr *DRE = cast<DeclRefExpr>(FromExpr); - FromValueDecl = cast<ValueDecl>(DRE->getDecl()); - } - if (!HasToValueDecl && ToExpr) { - DeclRefExpr *DRE = cast<DeclRefExpr>(ToExpr); - ToValueDecl = cast<ValueDecl>(DRE->getDecl()); - } + if (!HasFromValueDecl && FromExpr) + FromValueDecl = GetValueDecl(FromIter, FromExpr); + if (!HasToValueDecl && ToExpr) + ToValueDecl = GetValueDecl(ToIter, ToExpr); Tree.SetNode(FromValueDecl, ToValueDecl); - Tree.SetSame(FromValueDecl->getCanonicalDecl() == + Tree.SetSame(FromValueDecl && ToValueDecl && + FromValueDecl->getCanonicalDecl() == ToValueDecl->getCanonicalDecl()); Tree.SetDefault(FromIter.isEnd() && FromValueDecl, ToIter.isEnd() && ToValueDecl); + Tree.SetKind(DiffTree::Declaration); } } @@ -937,16 +956,17 @@ class TemplateDiff { if (TemplateTemplateParmDecl *DefaultTTPD = dyn_cast<TemplateTemplateParmDecl>(ParamND)) { TemplateDecl *FromDecl, *ToDecl; - GetTemplateDecl(FromIter, DefaultTTPD, FromDecl); - GetTemplateDecl(ToIter, DefaultTTPD, ToDecl); + FromDecl = GetTemplateDecl(FromIter, DefaultTTPD); + ToDecl = GetTemplateDecl(ToIter, DefaultTTPD); Tree.SetNode(FromDecl, ToDecl); Tree.SetSame( FromDecl && ToDecl && FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl()); + Tree.SetKind(DiffTree::TemplateTemplate); } - if (!FromIter.isEnd()) ++FromIter; - if (!ToIter.isEnd()) ++ToIter; + ++FromIter; + ++ToIter; Tree.Up(); } } @@ -1012,22 +1032,21 @@ class TemplateDiff { /// GetType - Retrieves the template type arguments, including default /// arguments. - void GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD, - QualType &ArgType) { - ArgType = QualType(); + QualType GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD) { bool isVariadic = DefaultTTPD->isParameterPack(); if (!Iter.isEnd()) - ArgType = Iter->getAsType(); - else if (!isVariadic) - ArgType = DefaultTTPD->getDefaultArgument(); + return Iter->getAsType(); + if (!isVariadic) + return DefaultTTPD->getDefaultArgument(); + + return QualType(); } /// GetExpr - Retrieves the template expression argument, including default /// arguments. - void GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD, - Expr *&ArgExpr) { - ArgExpr = 0; + Expr *GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD) { + Expr *ArgExpr = 0; bool isVariadic = DefaultNTTPD->isParameterPack(); if (!Iter.isEnd()) @@ -1039,14 +1058,50 @@ class TemplateDiff { while (SubstNonTypeTemplateParmExpr *SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(ArgExpr)) ArgExpr = SNTTPE->getReplacement(); + + return ArgExpr; + } + + /// GetInt - Retrieves the template integer argument, including evaluating + /// default arguments. + llvm::APInt GetInt(const TSTiterator &Iter, Expr *ArgExpr) { + // Default, value-depenedent expressions require fetching + // from the desugared TemplateArgument + if (Iter.isEnd() && ArgExpr->isValueDependent()) + switch (Iter.getDesugar().getKind()) { + case TemplateArgument::Integral: + return Iter.getDesugar().getAsIntegral(); + case TemplateArgument::Expression: + ArgExpr = Iter.getDesugar().getAsExpr(); + return ArgExpr->EvaluateKnownConstInt(Context); + default: + assert(0 && "Unexpected template argument kind"); + } + return ArgExpr->EvaluateKnownConstInt(Context); + } + + /// GetValueDecl - Retrieves the template integer argument, including + /// default expression argument. + ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) { + // Default, value-depenedent expressions require fetching + // from the desugared TemplateArgument + if (Iter.isEnd() && ArgExpr->isValueDependent()) + switch (Iter.getDesugar().getKind()) { + case TemplateArgument::Declaration: + return Iter.getDesugar().getAsDecl(); + case TemplateArgument::Expression: + ArgExpr = Iter.getDesugar().getAsExpr(); + return cast<DeclRefExpr>(ArgExpr)->getDecl(); + default: + assert(0 && "Unexpected template argument kind"); + } + return cast<DeclRefExpr>(ArgExpr)->getDecl(); } /// GetTemplateDecl - Retrieves the template template arguments, including /// default arguments. - void GetTemplateDecl(const TSTiterator &Iter, - TemplateTemplateParmDecl *DefaultTTPD, - TemplateDecl *&ArgDecl) { - ArgDecl = 0; + TemplateDecl *GetTemplateDecl(const TSTiterator &Iter, + TemplateTemplateParmDecl *DefaultTTPD) { bool isVariadic = DefaultTTPD->isParameterPack(); TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument(); @@ -1055,9 +1110,11 @@ class TemplateDiff { DefaultTD = TA.getAsTemplate().getAsTemplateDecl(); if (!Iter.isEnd()) - ArgDecl = Iter->getAsTemplate().getAsTemplateDecl(); - else if (!isVariadic) - ArgDecl = DefaultTD; + return Iter->getAsTemplate().getAsTemplateDecl(); + if (!isVariadic) + return DefaultTD; + + return 0; } /// IsSameConvertedInt - Returns true if both integers are equal when @@ -1093,7 +1150,7 @@ class TemplateDiff { Expr::EvalResult FromResult, ToResult; if (!FromExpr->EvaluateAsRValue(FromResult, Context) || !ToExpr->EvaluateAsRValue(ToResult, Context)) - assert(0 && "Template arguments must be known at compile time."); + return false; APValue &FromVal = FromResult.Val; APValue &ToVal = ToResult.Val; @@ -1134,88 +1191,91 @@ class TemplateDiff { // Handle cases where the difference is not templates with different // arguments. - if (!Tree.NodeIsTemplate()) { - if (Tree.NodeIsQualType()) { + switch (Tree.GetKind()) { + case DiffTree::Invalid: + llvm_unreachable("Template diffing failed with bad DiffNode"); + case DiffTree::Type: { QualType FromType, ToType; Tree.GetNode(FromType, ToType); PrintTypeNames(FromType, ToType, Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); return; } - if (Tree.NodeIsExpr()) { + case DiffTree::Expression: { Expr *FromExpr, *ToExpr; Tree.GetNode(FromExpr, ToExpr); PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); return; } - if (Tree.NodeIsTemplateTemplate()) { + case DiffTree::TemplateTemplate: { TemplateDecl *FromTD, *ToTD; Tree.GetNode(FromTD, ToTD); PrintTemplateTemplate(FromTD, ToTD, Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); return; } - - if (Tree.NodeIsAPSInt()) { + case DiffTree::Integer: { llvm::APSInt FromInt, ToInt; + Expr *FromExpr, *ToExpr; bool IsValidFromInt, IsValidToInt; + Tree.GetNode(FromExpr, ToExpr); Tree.GetNode(FromInt, ToInt, IsValidFromInt, IsValidToInt); PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt, - Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); + FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(), + Tree.NodeIsSame()); return; } - - if (Tree.NodeIsValueDecl()) { + case DiffTree::Declaration: { ValueDecl *FromValueDecl, *ToValueDecl; Tree.GetNode(FromValueDecl, ToValueDecl); PrintValueDecl(FromValueDecl, ToValueDecl, Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); return; } + case DiffTree::Template: { + // Node is root of template. Recurse on children. + TemplateDecl *FromTD, *ToTD; + Tree.GetNode(FromTD, ToTD); - llvm_unreachable("Unable to deduce template difference."); - } - - // Node is root of template. Recurse on children. - TemplateDecl *FromTD, *ToTD; - Tree.GetNode(FromTD, ToTD); - - if (!Tree.HasChildren()) { - // If we're dealing with a template specialization with zero - // arguments, there are no children; special-case this. - OS << FromTD->getNameAsString() << "<>"; - return; - } - - Qualifiers FromQual, ToQual; - Tree.GetNode(FromQual, ToQual); - PrintQualifiers(FromQual, ToQual); - - OS << FromTD->getNameAsString() << '<'; - Tree.MoveToChild(); - unsigned NumElideArgs = 0; - do { - if (ElideType) { - if (Tree.NodeIsSame()) { - ++NumElideArgs; - continue; + if (!Tree.HasChildren()) { + // If we're dealing with a template specialization with zero + // arguments, there are no children; special-case this. + OS << FromTD->getNameAsString() << "<>"; + return; } - if (NumElideArgs > 0) { + + Qualifiers FromQual, ToQual; + Tree.GetNode(FromQual, ToQual); + PrintQualifiers(FromQual, ToQual); + + OS << FromTD->getNameAsString() << '<'; + Tree.MoveToChild(); + unsigned NumElideArgs = 0; + do { + if (ElideType) { + if (Tree.NodeIsSame()) { + ++NumElideArgs; + continue; + } + if (NumElideArgs > 0) { + PrintElideArgs(NumElideArgs, Indent); + NumElideArgs = 0; + OS << ", "; + } + } + TreeToString(Indent); + if (Tree.HasNextSibling()) + OS << ", "; + } while (Tree.AdvanceSibling()); + if (NumElideArgs > 0) PrintElideArgs(NumElideArgs, Indent); - NumElideArgs = 0; - OS << ", "; - } + + Tree.Parent(); + OS << ">"; + return; } - TreeToString(Indent); - if (Tree.HasNextSibling()) - OS << ", "; - } while (Tree.AdvanceSibling()); - if (NumElideArgs > 0) - PrintElideArgs(NumElideArgs, Indent); - - Tree.Parent(); - OS << ">"; + } } // To signal to the text printer that a certain text needs to be bolded, @@ -1364,8 +1424,8 @@ class TemplateDiff { /// PrintAPSInt - Handles printing of integral arguments, highlighting /// argument differences. void PrintAPSInt(llvm::APSInt FromInt, llvm::APSInt ToInt, - bool IsValidFromInt, bool IsValidToInt, bool FromDefault, - bool ToDefault, bool Same) { + bool IsValidFromInt, bool IsValidToInt, Expr *FromExpr, + Expr *ToExpr, bool FromDefault, bool ToDefault, bool Same) { assert((IsValidFromInt || IsValidToInt) && "Only one integral argument may be missing."); @@ -1373,23 +1433,48 @@ class TemplateDiff { OS << FromInt.toString(10); } else if (!PrintTree) { OS << (FromDefault ? "(default) " : ""); - Bold(); - OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)"); - Unbold(); + PrintAPSInt(FromInt, FromExpr, IsValidFromInt); } else { OS << (FromDefault ? "[(default) " : "["); - Bold(); - OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)"); - Unbold(); + PrintAPSInt(FromInt, FromExpr, IsValidFromInt); OS << " != " << (ToDefault ? "(default) " : ""); - Bold(); - OS << (IsValidToInt ? ToInt.toString(10) : "(no argument)"); - Unbold(); + PrintAPSInt(ToInt, ToExpr, IsValidToInt); OS << ']'; } } + /// PrintAPSInt - If valid, print the APSInt. If the expression is + /// gives more information, print it too. + void PrintAPSInt(llvm::APSInt Val, Expr *E, bool Valid) { + Bold(); + if (Valid) { + if (HasExtraInfo(E)) { + PrintExpr(E); + Unbold(); + OS << " aka "; + Bold(); + } + OS << Val.toString(10); + } else { + OS << "(no argument)"; + } + Unbold(); + } + /// HasExtraInfo - Returns true if E is not an integer literal or the + /// negation of an integer literal + bool HasExtraInfo(Expr *E) { + if (!E) return false; + if (isa<IntegerLiteral>(E)) return false; + + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) + if (UO->getOpcode() == UO_Minus) + if (isa<IntegerLiteral>(UO->getSubExpr())) + return false; + + return true; + } + /// PrintDecl - Handles printing of Decl arguments, highlighting /// argument differences. void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, @@ -1534,6 +1619,7 @@ public: ToQual -= QualType(ToOrigTST, 0).getQualifiers(); Tree.SetNode(FromType, ToType); Tree.SetNode(FromQual, ToQual); + Tree.SetKind(DiffTree::Template); // Same base template, but different arguments. Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(), diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 740153029b..340cc41f7e 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -749,7 +749,7 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { dumpName(D); dumpType(D->getType()); - StorageClass SC = D->getStorageClassAsWritten(); + StorageClass SC = D->getStorageClass(); if (SC != SC_None) OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); if (D->isInlineSpecified()) @@ -850,11 +850,14 @@ void ASTDumper::VisitFieldDecl(const FieldDecl *D) { void ASTDumper::VisitVarDecl(const VarDecl *D) { dumpName(D); dumpType(D->getType()); - StorageClass SC = D->getStorageClassAsWritten(); + StorageClass SC = D->getStorageClass(); if (SC != SC_None) OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); - if (D->isThreadSpecified()) - OS << " __thread"; + switch (D->getTLSKind()) { + case VarDecl::TLS_None: break; + case VarDecl::TLS_Static: OS << " tls"; break; + case VarDecl::TLS_Dynamic: OS << " tls_dynamic"; break; + } if (D->isModulePrivate()) OS << " __module_private__"; if (D->isNRVOVariable()) diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 01d1a1e917..915eb6feb8 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -839,6 +839,12 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl(); return IsStructurallyEquivalent(Context, D1, D2); } + + // Check for equivalent field names. + IdentifierInfo *Name1 = Field1->getIdentifier(); + IdentifierInfo *Name2 = Field2->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2)) + return false; if (!IsStructurallyEquivalent(Context, Field1->getType(), Field2->getType())) { @@ -1680,7 +1686,7 @@ QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) { } QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { - // FIXME: Make sure that the "to" context supports C++0x! + // FIXME: Make sure that the "to" context supports C++11! QualType FromDeduced = T->getDeducedType(); QualType ToDeduced; if (!FromDeduced.isNull()) { @@ -1689,7 +1695,7 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { return QualType(); } - return Importer.getToContext().getAutoType(ToDeduced); + return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto()); } QualType ASTNodeImporter::VisitRecordType(const RecordType *T) { @@ -2716,8 +2722,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { cast<CXXRecordDecl>(DC), D->getInnerLocStart(), NameInfo, T, TInfo, - Method->isStatic(), - Method->getStorageClassAsWritten(), + Method->getStorageClass(), Method->isInlineSpecified(), D->isConstexpr(), Importer.Import(D->getLocEnd())); @@ -2725,7 +2730,6 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, D->getInnerLocStart(), NameInfo, T, TInfo, D->getStorageClass(), - D->getStorageClassAsWritten(), D->isInlineSpecified(), D->hasWrittenPrototype(), D->isConstexpr()); @@ -3076,8 +3080,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), T, TInfo, - D->getStorageClass(), - D->getStorageClassAsWritten()); + D->getStorageClass()); ToVar->setQualifierInfo(Importer.Import(D->getQualifierLoc())); ToVar->setAccess(D->getAccess()); ToVar->setLexicalDeclContext(LexicalDC); @@ -3145,7 +3148,6 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getStorageClass(), - D->getStorageClassAsWritten(), /*FIXME: Default argument*/ 0); ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg()); return Importer.Imported(D, ToParm); @@ -3648,6 +3650,7 @@ Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { Iface, Super, Importer.Import(D->getLocation()), Importer.Import(D->getAtStartLoc()), + Importer.Import(D->getSuperClassLoc()), Importer.Import(D->getIvarLBraceLoc()), Importer.Import(D->getIvarRBraceLoc())); diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index 0a4f7ea556..daf65e56bd 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -23,4 +23,6 @@ void InheritableAttr::anchor() { } void InheritableParamAttr::anchor() { } +void MSInheritanceAttr::anchor() { } + #include "clang/AST/AttrImpl.inc" diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 14bbc2f724..e804fe7205 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -22,6 +22,7 @@ add_clang_library(clangAST DeclFriend.cpp DeclGroup.cpp DeclObjC.cpp + DeclOpenMP.cpp DeclPrinter.cpp DeclTemplate.cpp DumpXML.cpp diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h index 0d9c869d87..6d67d9a12b 100644 --- a/lib/AST/CXXABI.h +++ b/lib/AST/CXXABI.h @@ -27,9 +27,9 @@ class CXXABI { public: virtual ~CXXABI(); - /// Returns the size of a member pointer in multiples of the target - /// pointer size. - virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0; + /// Returns the width and alignment of a member pointer in bits. + virtual std::pair<uint64_t, unsigned> + getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const = 0; /// Returns the default calling convention for C++ methods. virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0; diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index db55c04544..68c73fd48e 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -134,7 +134,7 @@ void DeclInfo::fill() { IsObjCMethod = false; IsInstanceMethod = false; IsClassMethod = false; - ParamVars = ArrayRef<const ParmVarDecl *>(); + ParamVars = None; TemplateParameters = NULL; if (!CommentDecl) { diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp index 1194520bf3..70410d6108 100644 --- a/lib/AST/CommentLexer.cpp +++ b/lib/AST/CommentLexer.cpp @@ -1,5 +1,6 @@ #include "clang/AST/CommentLexer.h" #include "clang/AST/CommentCommandTraits.h" +#include "clang/AST/CommentDiagnostic.h" #include "clang/Basic/CharInfo.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -353,6 +354,7 @@ void Lexer::lexCommentText(Token &T) { if (!Info) { formTokenWithChars(T, TokenPtr, tok::unknown_command); T.setUnknownCommandName(CommandName); + Diag(T.getLocation(), diag::warn_unknown_comment_command_name); return; } if (Info->IsVerbatimBlockCommand) { @@ -685,10 +687,11 @@ void Lexer::lexHTMLEndTag(Token &T) { State = LS_Normal; } -Lexer::Lexer(llvm::BumpPtrAllocator &Allocator, const CommandTraits &Traits, +Lexer::Lexer(llvm::BumpPtrAllocator &Allocator, DiagnosticsEngine &Diags, + const CommandTraits &Traits, SourceLocation FileLoc, const char *BufferStart, const char *BufferEnd): - Allocator(Allocator), Traits(Traits), + Allocator(Allocator), Diags(Diags), Traits(Traits), BufferStart(BufferStart), BufferEnd(BufferEnd), FileLoc(FileLoc), BufferPtr(BufferStart), CommentState(LCS_BeforeComment), State(LS_Normal) { diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp index 09912c6188..d89c79b3d9 100644 --- a/lib/AST/CommentParser.cpp +++ b/lib/AST/CommentParser.cpp @@ -302,22 +302,18 @@ void Parser::parseBlockCommandArgs(BlockCommandComment *BC, BlockCommandComment *Parser::parseBlockCommand() { assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command)); - ParamCommandComment *PC; - TParamCommandComment *TPC; - BlockCommandComment *BC; - bool IsParam = false; - bool IsTParam = false; + ParamCommandComment *PC = 0; + TParamCommandComment *TPC = 0; + BlockCommandComment *BC = 0; const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); CommandMarkerKind CommandMarker = Tok.is(tok::backslash_command) ? CMK_Backslash : CMK_At; if (Info->IsParamCommand) { - IsParam = true; PC = S.actOnParamCommandStart(Tok.getLocation(), Tok.getEndLocation(), Tok.getCommandID(), CommandMarker); } else if (Info->IsTParamCommand) { - IsTParam = true; TPC = S.actOnTParamCommandStart(Tok.getLocation(), Tok.getEndLocation(), Tok.getCommandID(), @@ -333,12 +329,11 @@ BlockCommandComment *Parser::parseBlockCommand() { if (isTokBlockCommand()) { // Block command ahead. We can't nest block commands, so pretend that this // command has an empty argument. - ParagraphComment *Paragraph = S.actOnParagraphComment( - ArrayRef<InlineContentComment *>()); - if (IsParam) { + ParagraphComment *Paragraph = S.actOnParagraphComment(None); + if (PC) { S.actOnParamCommandFinish(PC, Paragraph); return PC; - } else if (IsTParam) { + } else if (TPC) { S.actOnTParamCommandFinish(TPC, Paragraph); return TPC; } else { @@ -347,14 +342,14 @@ BlockCommandComment *Parser::parseBlockCommand() { } } - if (IsParam || IsTParam || Info->NumArgs > 0) { + if (PC || TPC || Info->NumArgs > 0) { // In order to parse command arguments we need to retokenize a few // following text tokens. TextTokenRetokenizer Retokenizer(Allocator, *this); - if (IsParam) + if (PC) parseParamCommandArgs(PC, Retokenizer); - else if (IsTParam) + else if (TPC) parseTParamCommandArgs(TPC, Retokenizer); else parseBlockCommandArgs(BC, Retokenizer, Info->NumArgs); @@ -376,7 +371,7 @@ BlockCommandComment *Parser::parseBlockCommand() { ParagraphComment *Paragraph; if (EmptyParagraph) - Paragraph = S.actOnParagraphComment(ArrayRef<InlineContentComment *>()); + Paragraph = S.actOnParagraphComment(None); else { BlockContentComment *Block = parseParagraphOrBlockCommand(); // Since we have checked for a block command, we should have parsed a @@ -384,10 +379,10 @@ BlockCommandComment *Parser::parseBlockCommand() { Paragraph = cast<ParagraphComment>(Block); } - if (IsParam) { + if (PC) { S.actOnParamCommandFinish(PC, Paragraph); return PC; - } else if (IsTParam) { + } else if (TPC) { S.actOnTParamCommandFinish(TPC, Paragraph); return TPC; } else { diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp index e6367c9755..e0138d5f3f 100644 --- a/lib/AST/CommentSema.cpp +++ b/lib/AST/CommentSema.cpp @@ -101,11 +101,17 @@ void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) { case CommandTraits::KCI_function: DiagSelect = !isAnyFunctionDecl() ? 1 : 0; break; + case CommandTraits::KCI_functiongroup: + DiagSelect = !isAnyFunctionDecl() ? 2 : 0; + break; case CommandTraits::KCI_method: - DiagSelect = !isObjCMethodDecl() ? 2 : 0; + DiagSelect = !isObjCMethodDecl() ? 3 : 0; + break; + case CommandTraits::KCI_methodgroup: + DiagSelect = !isObjCMethodDecl() ? 4 : 0; break; case CommandTraits::KCI_callback: - DiagSelect = !isFunctionPointerVarDecl() ? 3 : 0; + DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0; break; default: DiagSelect = 0; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 9ee70e2510..ab9d73b917 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -471,9 +471,16 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) { FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr<GNUInlineAttr>(); } -template <typename T> static bool isInExternCContext(T *D) { +template <typename T> static bool isFirstInExternCContext(T *D) { const T *First = D->getFirstDeclaration(); - return First->getDeclContext()->isExternCContext(); + return First->isInExternCContext(); +} + +static bool isSingleLineExternC(const Decl &D) { + if (const LinkageSpecDecl *SD = dyn_cast<LinkageSpecDecl>(D.getDeclContext())) + if (SD->getLanguage() == LinkageSpecDecl::lang_c && !SD->hasBraces()) + return true; + return false; } static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, @@ -498,26 +505,25 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // declared to have external linkage; or (there is no equivalent in C99) if (Context.getLangOpts().CPlusPlus && Var->getType().isConstQualified() && - !Var->getType().isVolatileQualified() && - Var->getStorageClass() != SC_Extern && - Var->getStorageClass() != SC_PrivateExtern) { - bool FoundExtern = false; - for (const VarDecl *PrevVar = Var->getPreviousDecl(); - PrevVar && !FoundExtern; - PrevVar = PrevVar->getPreviousDecl()) - if (isExternalLinkage(PrevVar->getLinkage())) - FoundExtern = true; - - if (!FoundExtern) - return LinkageInfo::internal(); - } - if (Var->getStorageClass() == SC_None) { + !Var->getType().isVolatileQualified()) { const VarDecl *PrevVar = Var->getPreviousDecl(); - for (; PrevVar; PrevVar = PrevVar->getPreviousDecl()) - if (PrevVar->getStorageClass() == SC_PrivateExtern) - break; if (PrevVar) return PrevVar->getLinkageAndVisibility(); + + if (Var->getStorageClass() != SC_Extern && + Var->getStorageClass() != SC_PrivateExtern && + !isSingleLineExternC(*Var)) + return LinkageInfo::internal(); + } + + for (const VarDecl *PrevVar = Var->getPreviousDecl(); PrevVar; + PrevVar = PrevVar->getPreviousDecl()) { + if (PrevVar->getStorageClass() == SC_PrivateExtern && + Var->getStorageClass() == SC_None) + return PrevVar->getLinkageAndVisibility(); + // Explicitly declared static. + if (PrevVar->getStorageClass() == SC_Static) + return LinkageInfo::internal(); } } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { // C++ [temp]p4: @@ -531,7 +537,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, Function = cast<FunctionDecl>(D); // Explicitly declared static. - if (Function->getStorageClass() == SC_Static) + if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) return LinkageInfo(InternalLinkage, DefaultVisibility, false); } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) { // - a data member of an anonymous union. @@ -542,8 +548,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (D->isInAnonymousNamespace()) { const VarDecl *Var = dyn_cast<VarDecl>(D); const FunctionDecl *Func = dyn_cast<FunctionDecl>(D); - if ((!Var || !isInExternCContext(Var)) && - (!Func || !isInExternCContext(Func))) + if ((!Var || !isFirstInExternCContext(Var)) && + (!Func || !isFirstInExternCContext(Func))) return LinkageInfo::uniqueExternal(); } @@ -620,7 +626,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // // Note that we don't want to make the variable non-external // because of this, but unique-external linkage suits us. - if (Context.getLangOpts().CPlusPlus && !isInExternCContext(Var)) { + if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) { LinkageInfo TypeLV = Var->getType()->getLinkageAndVisibility(); if (TypeLV.getLinkage() != ExternalLinkage) return LinkageInfo::uniqueExternal(); @@ -654,7 +660,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // this translation unit. However, we should use the C linkage // rules instead for extern "C" declarations. if (Context.getLangOpts().CPlusPlus && - !Function->getDeclContext()->isExternCContext() && + !Function->isInExternCContext() && Function->getType()->getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); @@ -858,49 +864,14 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, return LV; } -static void clearLinkageForClass(const CXXRecordDecl *record) { - for (CXXRecordDecl::decl_iterator - i = record->decls_begin(), e = record->decls_end(); i != e; ++i) { - Decl *child = *i; - if (isa<NamedDecl>(child)) - cast<NamedDecl>(child)->ClearLinkageCache(); - } -} - void NamedDecl::anchor() { } -void NamedDecl::ClearLinkageCache() { - // Note that we can't skip clearing the linkage of children just - // because the parent doesn't have cached linkage: we don't cache - // when computing linkage for parent contexts. - - HasCachedLinkage = 0; - - // If we're changing the linkage of a class, we need to reset the - // linkage of child declarations, too. - if (const CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(this)) - clearLinkageForClass(record); - - if (ClassTemplateDecl *temp = dyn_cast<ClassTemplateDecl>(this)) { - // Clear linkage for the template pattern. - CXXRecordDecl *record = temp->getTemplatedDecl(); - record->HasCachedLinkage = 0; - clearLinkageForClass(record); - - // We need to clear linkage for specializations, too. - for (ClassTemplateDecl::spec_iterator - i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i) - i->ClearLinkageCache(); - } +bool NamedDecl::isLinkageValid() const { + if (!HasCachedLinkage) + return true; - // Clear cached linkage for function template decls, too. - if (FunctionTemplateDecl *temp = dyn_cast<FunctionTemplateDecl>(this)) { - temp->getTemplatedDecl()->ClearLinkageCache(); - for (FunctionTemplateDecl::spec_iterator - i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i) - i->ClearLinkageCache(); - } - + return getLVForDecl(this, LVForExplicitValue).getLinkage() == + Linkage(CachedLinkage); } Linkage NamedDecl::getLinkage() const { @@ -1026,11 +997,11 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, LVComputationKind computation) { if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { if (Function->isInAnonymousNamespace() && - !Function->getDeclContext()->isExternCContext()) + !Function->isInExternCContext()) return LinkageInfo::uniqueExternal(); // This is a "void f();" which got merged with a file static. - if (Function->getStorageClass() == SC_Static) + if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) return LinkageInfo::internal(); LinkageInfo LV; @@ -1048,15 +1019,10 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, } if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { - if (Var->hasExternalStorageAsWritten()) { - if (Var->isInAnonymousNamespace() && - !Var->getDeclContext()->isExternCContext()) + if (Var->hasExternalStorage()) { + if (Var->isInAnonymousNamespace() && !Var->isInExternCContext()) return LinkageInfo::uniqueExternal(); - // This is an "extern int foo;" which got merged with a file static. - if (Var->getStorageClass() == SC_Static) - return LinkageInfo::internal(); - LinkageInfo LV; if (Var->getStorageClass() == SC_PrivateExtern) LV.mergeVisibility(HiddenVisibility, true); @@ -1065,9 +1031,13 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, LV.mergeVisibility(*Vis, true); } - // Note that Sema::MergeVarDecl already takes care of implementing - // C99 6.2.2p4 and propagating the visibility attribute, so we don't - // have to do it here. + if (const VarDecl *Prev = Var->getPreviousDecl()) { + LinkageInfo PrevLV = getLVForDecl(Prev, computation); + if (PrevLV.getLinkage()) + LV.setLinkage(PrevLV.getLinkage()); + LV.mergeVisibility(PrevLV); + } + return LV; } } @@ -1330,7 +1300,7 @@ bool NamedDecl::isCXXInstanceMember() const { if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); - if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) + if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D) || isa<MSPropertyDecl>(D)) return true; if (isa<CXXMethodDecl>(D)) return cast<CXXMethodDecl>(D)->isInstance(); @@ -1502,21 +1472,18 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartL, SourceLocation IdL, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - StorageClass S, StorageClass SCAsWritten) { - return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S, SCAsWritten); + StorageClass S) { + return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S); } VarDecl *VarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarDecl)); return new (Mem) VarDecl(Var, 0, SourceLocation(), SourceLocation(), 0, - QualType(), 0, SC_None, SC_None); + QualType(), 0, SC_None); } void VarDecl::setStorageClass(StorageClass SC) { assert(isLegalForVariable(SC)); - if (getStorageClass() != SC) - ClearLinkageCache(); - VarDeclBits.SClass = SC; } @@ -1554,16 +1521,55 @@ static LanguageLinkage getLanguageLinkageTemplate(const T &D) { // If the first decl is in an extern "C" context, any other redeclaration // will have C language linkage. If the first one is not in an extern "C" // context, we would have reported an error for any other decl being in one. - const T *First = D.getFirstDeclaration(); - if (First->getDeclContext()->isExternCContext()) + if (isFirstInExternCContext(&D)) return CLanguageLinkage; return CXXLanguageLinkage; } +template<typename T> +static bool isExternCTemplate(const T &D) { + // Since the context is ignored for class members, they can only have C++ + // language linkage or no language linkage. + const DeclContext *DC = D.getDeclContext(); + if (DC->isRecord()) { + assert(D.getASTContext().getLangOpts().CPlusPlus); + return false; + } + + return D.getLanguageLinkage() == CLanguageLinkage; +} + LanguageLinkage VarDecl::getLanguageLinkage() const { return getLanguageLinkageTemplate(*this); } +bool VarDecl::isExternC() const { + return isExternCTemplate(*this); +} + +static bool isLinkageSpecContext(const DeclContext *DC, + LinkageSpecDecl::LanguageIDs ID) { + while (DC->getDeclKind() != Decl::TranslationUnit) { + if (DC->getDeclKind() == Decl::LinkageSpec) + return cast<LinkageSpecDecl>(DC)->getLanguage() == ID; + DC = DC->getParent(); + } + return false; +} + +template <typename T> +static bool isInLanguageSpecContext(T *D, LinkageSpecDecl::LanguageIDs ID) { + return isLinkageSpecContext(D->getLexicalDeclContext(), ID); +} + +bool VarDecl::isInExternCContext() const { + return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c); +} + +bool VarDecl::isInExternCXXContext() const { + return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx); +} + VarDecl *VarDecl::getCanonicalDecl() { return getFirstDeclaration(); } @@ -1595,17 +1601,17 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( // initializer, the declaration is an external definition for the identifier if (hasInit()) return Definition; - // AST for 'extern "C" int foo;' is annotated with 'extern'. + if (hasExternalStorage()) return DeclarationOnly; - if (hasExternalStorageAsWritten()) { - for (const VarDecl *PrevVar = getPreviousDecl(); - PrevVar; PrevVar = PrevVar->getPreviousDecl()) { - if (PrevVar->getLinkage() == InternalLinkage) - return DeclarationOnly; - } - } + // [dcl.link] p7: + // A declaration directly contained in a linkage-specification is treated + // as if it contains the extern specifier for the purpose of determining + // the linkage of the declared name and whether it is a definition. + if (isSingleLineExternC(*this)) + return DeclarationOnly; + // C99 6.9.2p2: // A declaration of an object that has file scope without an initializer, // and without a storage class specifier or the scs 'static', constitutes @@ -1897,16 +1903,15 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - StorageClass S, StorageClass SCAsWritten, - Expr *DefArg) { + StorageClass S, Expr *DefArg) { return new (C) ParmVarDecl(ParmVar, DC, StartLoc, IdLoc, Id, T, TInfo, - S, SCAsWritten, DefArg); + S, DefArg); } ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ParmVarDecl)); return new (Mem) ParmVarDecl(ParmVar, 0, SourceLocation(), SourceLocation(), - 0, QualType(), 0, SC_None, SC_None, 0); + 0, QualType(), 0, SC_None, 0); } SourceRange ParmVarDecl::getSourceRange() const { @@ -1916,6 +1921,11 @@ SourceRange ParmVarDecl::getSourceRange() const { return SourceRange(getOuterLocStart(), ArgRange.getEnd()); } + // DeclaratorDecl considers the range of postfix types as overlapping with the + // declaration name, but this is not the case with parameters in ObjC methods. + if (isa<ObjCMethodDecl>(getDeclContext())) + return SourceRange(DeclaratorDecl::getLocStart(), getLocation()); + return DeclaratorDecl::getSourceRange(); } @@ -2077,11 +2087,23 @@ LanguageLinkage FunctionDecl::getLanguageLinkage() const { return getLanguageLinkageTemplate(*this); } +bool FunctionDecl::isExternC() const { + return isExternCTemplate(*this); +} + +bool FunctionDecl::isInExternCContext() const { + return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c); +} + +bool FunctionDecl::isInExternCXXContext() const { + return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx); +} + bool FunctionDecl::isGlobal() const { if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this)) return Method->isStatic(); - if (getStorageClass() == SC_Static) + if (getCanonicalDecl()->getStorageClass() == SC_Static) return false; for (const DeclContext *DC = getDeclContext(); @@ -2126,14 +2148,6 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDeclaration(); } -void FunctionDecl::setStorageClass(StorageClass SC) { - assert(isLegalForFunction(SC)); - if (getStorageClass() != SC) - ClearLinkageCache(); - - SClass = SC; -} - /// \brief Returns a value indicating whether this function /// corresponds to a builtin function. /// @@ -2284,7 +2298,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { // // FIXME: What happens if gnu_inline gets added on after the first // declaration? - if (!isInlineSpecified() || getStorageClassAsWritten() == SC_Extern) + if (!isInlineSpecified() || getStorageClass() == SC_Extern) return false; const FunctionDecl *Prev = this; @@ -2296,10 +2310,10 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { // If it's not the case that both 'inline' and 'extern' are // specified on the definition, then it is always externally visible. if (!Prev->isInlineSpecified() || - Prev->getStorageClassAsWritten() != SC_Extern) + Prev->getStorageClass() != SC_Extern) return false; } else if (Prev->isInlineSpecified() && - Prev->getStorageClassAsWritten() != SC_Extern) { + Prev->getStorageClass() != SC_Extern) { return false; } } @@ -2354,7 +2368,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { // If it's not the case that both 'inline' and 'extern' are // specified on the definition, then this inline definition is // externally visible. - if (!(isInlineSpecified() && getStorageClassAsWritten() == SC_Extern)) + if (!(isInlineSpecified() && getStorageClass() == SC_Extern)) return true; // If any declaration is 'inline' but not 'extern', then this definition @@ -2363,7 +2377,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { Redecl != RedeclEnd; ++Redecl) { if (Redecl->isInlineSpecified() && - Redecl->getStorageClassAsWritten() != SC_Extern) + Redecl->getStorageClass() != SC_Extern) return true; } @@ -2864,11 +2878,11 @@ TagDecl* TagDecl::getCanonicalDecl() { return getFirstDeclaration(); } -void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { - TypedefNameDeclOrQualifier = TDD; +void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { + TypedefNameDeclOrQualifier = TDD; if (TypeForDecl) - const_cast<Type*>(TypeForDecl)->ClearLinkageCache(); - ClearLinkageCache(); + assert(TypeForDecl->isLinkageValid()); + assert(isLinkageValid()); } void TagDecl::startDefinition() { @@ -3226,12 +3240,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - StorageClass SC, StorageClass SCAsWritten, + StorageClass SC, bool isInlineSpecified, bool hasWrittenPrototype, bool isConstexprSpecified) { FunctionDecl *New = new (C) FunctionDecl(Function, DC, StartLoc, NameInfo, - T, TInfo, SC, SCAsWritten, + T, TInfo, SC, isInlineSpecified, isConstexprSpecified); New->HasWrittenPrototype = hasWrittenPrototype; @@ -3242,7 +3256,7 @@ FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FunctionDecl)); return new (Mem) FunctionDecl(Function, 0, SourceLocation(), DeclarationNameInfo(), QualType(), 0, - SC_None, SC_None, false, false); + SC_None, false, false); } BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { @@ -3254,6 +3268,27 @@ BlockDecl *BlockDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (Mem) BlockDecl(0, SourceLocation()); } +MSPropertyDecl *MSPropertyDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + void *Mem = AllocateDeserializedDecl(C, ID, sizeof(MSPropertyDecl)); + return new (Mem) MSPropertyDecl(0, SourceLocation(), DeclarationName(), + QualType(), 0, SourceLocation(), + 0, 0); +} + +CapturedDecl *CapturedDecl::Create(ASTContext &C, DeclContext *DC, + unsigned NumParams) { + unsigned Size = sizeof(CapturedDecl) + NumParams * sizeof(ImplicitParamDecl*); + return new (C.Allocate(Size)) CapturedDecl(DC, NumParams); +} + +CapturedDecl *CapturedDecl::CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NumParams) { + unsigned Size = sizeof(CapturedDecl) + NumParams * sizeof(ImplicitParamDecl*); + void *Mem = AllocateDeserializedDecl(C, ID, Size); + return new (Mem) CapturedDecl(0, NumParams); +} + EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, SourceLocation L, IdentifierInfo *Id, QualType T, @@ -3423,7 +3458,7 @@ ImportDecl *ImportDecl::CreateDeserialized(ASTContext &C, unsigned ID, ArrayRef<SourceLocation> ImportDecl::getIdentifierLocs() const { if (!ImportedAndComplete.getInt()) - return ArrayRef<SourceLocation>(); + return None; const SourceLocation *StoredLocs = reinterpret_cast<const SourceLocation *>(this + 1); diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 0db520e7d6..084a4321d8 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -20,6 +20,7 @@ #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DependentDiagnostic.h" #include "clang/AST/ExternalASTSource.h" @@ -434,7 +435,7 @@ bool Decl::canBeWeakImported(bool &IsDefinition) const { // Variables, if they aren't definitions. if (const VarDecl *Var = dyn_cast<VarDecl>(this)) { - if (!Var->hasExternalStorage() || Var->getInit()) { + if (Var->isThisDeclarationADefinition()) { IsDefinition = true; return false; } @@ -492,6 +493,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case NonTypeTemplateParm: case ObjCMethod: case ObjCProperty: + case MSProperty: return IDNS_Ordinary; case Label: return IDNS_Label; @@ -551,6 +553,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case StaticAssert: case ObjCPropertyImpl: case Block: + case Captured: case TranslationUnit: case UsingDirective: @@ -561,6 +564,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCCategory: case ObjCCategoryImpl: case Import: + case OMPThreadPrivate: case Empty: // Never looked up by name. return 0; @@ -700,21 +704,37 @@ void Decl::CheckAccessDeclContext() const { #endif } -DeclContext *Decl::getNonClosureContext() { - return getDeclContext()->getNonClosureAncestor(); +static Decl::Kind getKind(const Decl *D) { return D->getKind(); } +static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); } + +/// Starting at a given context (a Decl or DeclContext), look for a +/// code context that is not a closure (a lambda, block, etc.). +template <class T> static Decl *getNonClosureContext(T *D) { + if (getKind(D) == Decl::CXXMethod) { + CXXMethodDecl *MD = cast<CXXMethodDecl>(D); + if (MD->getOverloadedOperator() == OO_Call && + MD->getParent()->isLambda()) + return getNonClosureContext(MD->getParent()->getParent()); + return MD; + } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + return FD; + } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + return MD; + } else if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + return getNonClosureContext(BD->getParent()); + } else if (CapturedDecl *CD = dyn_cast<CapturedDecl>(D)) { + return getNonClosureContext(CD->getParent()); + } else { + return 0; + } } -DeclContext *DeclContext::getNonClosureAncestor() { - DeclContext *DC = this; - - // This is basically "while (DC->isClosure()) DC = DC->getParent();" - // except that it's significantly more efficient to cast to a known - // decl type and call getDeclContext() than to call getParent(). - while (isa<BlockDecl>(DC)) - DC = cast<BlockDecl>(DC)->getDeclContext(); +Decl *Decl::getNonClosureContext() { + return ::getNonClosureContext(this); +} - assert(!DC->isClosure()); - return DC; +Decl *DeclContext::getNonClosureAncestor() { + return ::getNonClosureContext(this); } //===----------------------------------------------------------------------===// @@ -799,28 +819,6 @@ bool DeclContext::isTransparentContext() const { return false; } -bool DeclContext::isExternCContext() const { - const DeclContext *DC = this; - while (DC->DeclKind != Decl::TranslationUnit) { - if (DC->DeclKind == Decl::LinkageSpec) - return cast<LinkageSpecDecl>(DC)->getLanguage() - == LinkageSpecDecl::lang_c; - DC = DC->getParent(); - } - return false; -} - -bool DeclContext::isExternCXXContext() const { - const DeclContext *DC = this; - while (DC->DeclKind != Decl::TranslationUnit) { - if (DC->DeclKind == Decl::LinkageSpec) - return cast<LinkageSpecDecl>(DC)->getLanguage() - == LinkageSpecDecl::lang_cxx; - DC = DC->getParent(); - } - return false; -} - bool DeclContext::Encloses(const DeclContext *DC) const { if (getPrimaryContext() != this) return getPrimaryContext()->Encloses(DC); @@ -836,6 +834,7 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::TranslationUnit: case Decl::LinkageSpec: case Decl::Block: + case Decl::Captured: // There is only one DeclContext for these entities. return this; @@ -1043,6 +1042,11 @@ bool DeclContext::decls_empty() const { return !FirstDecl; } +bool DeclContext::containsDecl(Decl *D) const { + return (D->getLexicalDeclContext() == this && + (D->NextInContextAndBits.getPointer() || D == LastDecl)); +} + void DeclContext::removeDecl(Decl *D) { assert(D->getLexicalDeclContext() == this && "decl being removed from non-lexical context"); diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 9ed9b7d363..064649904d 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -186,7 +186,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, data().IsStandardLayout = false; // Record if this base is the first non-literal field or base. - if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType()) + if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType(C)) data().HasNonLiteralTypeFieldsOrBases = true; // Now go through all virtual bases of this base and add them. @@ -505,7 +505,7 @@ void CXXRecordDecl::addedMember(Decl *D) { // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class with no user-declared // constructors [...]. - // C++0x [dcl.init.aggr]p1: + // C++11 [dcl.init.aggr]p1: // An aggregate is an array or a class with no user-provided // constructors [...]. if (getASTContext().getLangOpts().CPlusPlus11 @@ -542,22 +542,28 @@ void CXXRecordDecl::addedMember(Decl *D) { // Keep the list of conversion functions up-to-date. if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { - // FIXME: We intentionally don't use the decl's access here because it - // hasn't been set yet. That's really just a misdesign in Sema. + // FIXME: We use the 'unsafe' accessor for the access specifier here, + // because Sema may not have set it yet. That's really just a misdesign + // in Sema. However, LLDB *will* have set the access specifier correctly, + // and adds declarations after the class is technically completed, + // so completeDefinition()'s overriding of the access specifiers doesn't + // work. + AccessSpecifier AS = Conversion->getAccessUnsafe(); + if (Conversion->getPrimaryTemplate()) { // We don't record specializations. } else if (FunTmpl) { if (FunTmpl->getPreviousDecl()) data().Conversions.replace(FunTmpl->getPreviousDecl(), - FunTmpl); + FunTmpl, AS); else - data().Conversions.addDecl(getASTContext(), FunTmpl); + data().Conversions.addDecl(getASTContext(), FunTmpl, AS); } else { if (Conversion->getPreviousDecl()) data().Conversions.replace(Conversion->getPreviousDecl(), - Conversion); + Conversion, AS); else - data().Conversions.addDecl(getASTContext(), Conversion); + data().Conversions.addDecl(getASTContext(), Conversion, AS); } } @@ -670,7 +676,7 @@ void CXXRecordDecl::addedMember(Decl *D) { } // Record if this field is the first non-literal or volatile field or base. - if (!T->isLiteralType() || T.isVolatileQualified()) + if (!T->isLiteralType(Context) || T.isVolatileQualified()) data().HasNonLiteralTypeFieldsOrBases = true; if (Field->hasInClassInitializer()) { @@ -684,7 +690,10 @@ void CXXRecordDecl::addedMember(Decl *D) { // C++11 [dcl.init.aggr]p1: // An aggregate is a [...] class with [...] no // brace-or-equal-initializers for non-static data members. - data().Aggregate = false; + // + // This rule was removed in C++1y. + if (!getASTContext().getLangOpts().CPlusPlus1y) + data().Aggregate = false; // C++11 [class]p10: // A POD struct is [...] a trivial class. @@ -836,7 +845,7 @@ void CXXRecordDecl::addedMember(Decl *D) { } } else { // Base element type of field is a non-class type. - if (!T->isLiteralType() || + if (!T->isLiteralType(Context) || (!Field->hasInClassInitializer() && !isUnion())) data().DefaultedDefaultConstructorIsConstexpr = false; @@ -1251,6 +1260,29 @@ bool CXXRecordDecl::mayBeAbstract() const { void CXXMethodDecl::anchor() { } +bool CXXMethodDecl::isStatic() const { + const CXXMethodDecl *MD = getCanonicalDecl(); + + if (MD->getStorageClass() == SC_Static) + return true; + + DeclarationName Name = getDeclName(); + // [class.free]p1: + // Any allocation function for a class T is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_New || + Name.getCXXOverloadedOperator() == OO_Array_New) + return true; + + // [class.free]p6 Any deallocation function for a class X is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_Delete || + Name.getCXXOverloadedOperator() == OO_Array_Delete) + return true; + + return false; +} + static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD, const CXXMethodDecl *BaseMD) { for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(), @@ -1312,10 +1344,10 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isStatic, StorageClass SCAsWritten, bool isInline, + StorageClass SC, bool isInline, bool isConstexpr, SourceLocation EndLocation) { return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo, - isStatic, SCAsWritten, isInline, isConstexpr, + SC, isInline, isConstexpr, EndLocation); } @@ -1323,7 +1355,7 @@ CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXMethodDecl)); return new (Mem) CXXMethodDecl(CXXMethod, 0, SourceLocation(), DeclarationNameInfo(), QualType(), - 0, false, SC_None, false, false, + 0, SC_None, false, false, SourceLocation()); } @@ -1784,14 +1816,14 @@ LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, SourceLocation ExternLoc, SourceLocation LangLoc, LanguageIDs Lang, - SourceLocation RBraceLoc) { - return new (C) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, RBraceLoc); + bool HasBraces) { + return new (C) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, HasBraces); } LinkageSpecDecl *LinkageSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(LinkageSpecDecl)); return new (Mem) LinkageSpecDecl(0, SourceLocation(), SourceLocation(), - lang_c, SourceLocation()); + lang_c, false); } void UsingDirectiveDecl::anchor() { } diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index d1bf9a9e45..4ddbb22199 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -65,12 +65,13 @@ ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const { // Get the local instance/class method declared in this interface. ObjCMethodDecl * -ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const { +ObjCContainerDecl::getMethod(Selector Sel, bool isInstance, + bool AllowHidden) const { // If this context is a hidden protocol definition, don't find any // methods there. if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) { if (const ObjCProtocolDecl *Def = Proto->getDefinition()) - if (Def->isHidden()) + if (Def->isHidden() && !AllowHidden) return 0; } @@ -92,6 +93,72 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const { return 0; } +/// HasUserDeclaredSetterMethod - This routine returns 'true' if a user declared setter +/// method was found in the class, its protocols, its super classes or categories. +/// It also returns 'true' if one of its categories has declared a 'readwrite' property. +/// This is because, user must provide a setter method for the category's 'readwrite' +/// property. +bool +ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property) const { + Selector Sel = Property->getSetterName(); + lookup_const_result R = lookup(Sel); + for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end(); + Meth != MethEnd; ++Meth) { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + if (MD && MD->isInstanceMethod() && !MD->isImplicit()) + return true; + } + + if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(this)) { + // Also look into categories, including class extensions, looking + // for a user declared instance method. + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = ID->visible_categories_begin(), + CatEnd = ID->visible_categories_end(); + Cat != CatEnd; + ++Cat) { + if (ObjCMethodDecl *MD = Cat->getInstanceMethod(Sel)) + if (!MD->isImplicit()) + return true; + if (Cat->IsClassExtension()) + continue; + // Also search through the categories looking for a 'readwrite' declaration + // of this property. If one found, presumably a setter will be provided + // (properties declared in categories will not get auto-synthesized). + for (ObjCContainerDecl::prop_iterator P = Cat->prop_begin(), + E = Cat->prop_end(); P != E; ++P) + if (P->getIdentifier() == Property->getIdentifier()) { + if (P->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) + return true; + break; + } + } + + // Also look into protocols, for a user declared instance method. + for (ObjCInterfaceDecl::all_protocol_iterator P = + ID->all_referenced_protocol_begin(), + PE = ID->all_referenced_protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *Proto = (*P); + if (Proto->HasUserDeclaredSetterMethod(Property)) + return true; + } + // And in its super class. + ObjCInterfaceDecl *OSC = ID->getSuperClass(); + while (OSC) { + if (OSC->HasUserDeclaredSetterMethod(Property)) + return true; + OSC = OSC->getSuperClass(); + } + } + if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(this)) + for (ObjCProtocolDecl::protocol_iterator PI = PD->protocol_begin(), + E = PD->protocol_end(); PI != E; ++PI) { + if ((*PI)->HasUserDeclaredSetterMethod(Property)) + return true; + } + return false; +} + ObjCPropertyDecl * ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC, IdentifierInfo *propertyID) { @@ -376,9 +443,12 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass( /// lookupMethod - This method returns an instance/class method by looking in /// the class, its categories, and its super classes (using a linear search). +/// When argument category "C" is specified, any implicit method found +/// in this category is ignored. ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, bool isInstance, - bool shallowCategoryLookup) const { + bool shallowCategoryLookup, + const ObjCCategoryDecl *C) const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) return 0; @@ -402,20 +472,22 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, // Didn't find one yet - now look through categories. for (ObjCInterfaceDecl::visible_categories_iterator - Cat = ClassDecl->visible_categories_begin(), - CatEnd = ClassDecl->visible_categories_end(); + Cat = ClassDecl->visible_categories_begin(), + CatEnd = ClassDecl->visible_categories_end(); Cat != CatEnd; ++Cat) { if ((MethodDecl = Cat->getMethod(Sel, isInstance))) - return MethodDecl; + if (C != (*Cat) || !MethodDecl->isImplicit()) + return MethodDecl; if (!shallowCategoryLookup) { // Didn't find one yet - look through protocols. const ObjCList<ObjCProtocolDecl> &Protocols = - Cat->getReferencedProtocols(); + Cat->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) - return MethodDecl; + if (C != (*Cat) || !MethodDecl->isImplicit()) + return MethodDecl; } } @@ -532,12 +604,12 @@ void ObjCMethodDecl::setMethodParams(ASTContext &C, assert((!SelLocs.empty() || isImplicit()) && "No selector locs for non-implicit method"); if (isImplicit()) - return setParamsAndSelLocs(C, Params, ArrayRef<SourceLocation>()); + return setParamsAndSelLocs(C, Params, llvm::None); SelLocsKind = hasStandardSelectorLocs(getSelector(), SelLocs, Params, DeclEndLoc); if (SelLocsKind != SelLoc_NonStandard) - return setParamsAndSelLocs(C, Params, ArrayRef<SourceLocation>()); + return setParamsAndSelLocs(C, Params, llvm::None); setParamsAndSelLocs(C, Params, SelLocs); } @@ -788,7 +860,8 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, if (MovedToSuper) if (ObjCMethodDecl * Overridden = Container->getMethod(Method->getSelector(), - Method->isInstanceMethod())) + Method->isInstanceMethod(), + /*AllowHidden=*/true)) if (Method != Overridden) { // We found an override at this category; there is no need to look // into its protocols. @@ -806,7 +879,8 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, // Check whether we have a matching method at this level. if (const ObjCMethodDecl * Overridden = Container->getMethod(Method->getSelector(), - Method->isInstanceMethod())) + Method->isInstanceMethod(), + /*AllowHidden=*/true)) if (Method != Overridden) { // We found an override at this level; there is no need to look // into other protocols or categories. @@ -828,9 +902,9 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, P != PEnd; ++P) CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper); - for (ObjCInterfaceDecl::visible_categories_iterator - Cat = Interface->visible_categories_begin(), - CatEnd = Interface->visible_categories_end(); + for (ObjCInterfaceDecl::known_categories_iterator + Cat = Interface->known_categories_begin(), + CatEnd = Interface->known_categories_end(); Cat != CatEnd; ++Cat) { CollectOverriddenMethodsRecurse(*Cat, Method, Methods, MovedToSuper); @@ -865,7 +939,8 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method, // Start searching for overridden methods using the method from the // interface as starting point. if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(), - Method->isInstanceMethod())) + Method->isInstanceMethod(), + /*AllowHidden=*/true)) Method = IFaceMeth; CollectOverriddenMethods(ID, Method, overridden); @@ -877,7 +952,8 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method, // Start searching for overridden methods using the method from the // interface as starting point. if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(), - Method->isInstanceMethod())) + Method->isInstanceMethod(), + /*AllowHidden=*/true)) Method = IFaceMeth; CollectOverriddenMethods(ID, Method, overridden); @@ -888,52 +964,6 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method, } } -static void collectOnCategoriesAfterLocation(SourceLocation Loc, - const ObjCInterfaceDecl *Class, - SourceManager &SM, - const ObjCMethodDecl *Method, - SmallVectorImpl<const ObjCMethodDecl *> &Methods) { - if (!Class) - return; - - for (ObjCInterfaceDecl::visible_categories_iterator - Cat = Class->visible_categories_begin(), - CatEnd = Class->visible_categories_end(); - Cat != CatEnd; ++Cat) { - if (SM.isBeforeInTranslationUnit(Loc, Cat->getLocation())) - CollectOverriddenMethodsRecurse(*Cat, Method, Methods, true); - } - - collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM, - Method, Methods); -} - -/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding() -/// returns false. -/// You'd think that in that case there are no overrides but categories can -/// "introduce" new overridden methods that are missed by Sema because the -/// overrides lookup that it does for methods, inside implementations, will -/// stop at the interface level (if there is a method there) and not look -/// further in super classes. -/// Methods in an implementation can overide methods in super class's category -/// but not in current class's category. But, such methods -static void collectOverriddenMethodsFast(SourceManager &SM, - const ObjCMethodDecl *Method, - SmallVectorImpl<const ObjCMethodDecl *> &Methods) { - assert(!Method->isOverriding()); - - const ObjCContainerDecl * - ContD = cast<ObjCContainerDecl>(Method->getDeclContext()); - if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(ContD)) - return; - const ObjCInterfaceDecl *Class = Method->getClassInterface(); - if (!Class) - return; - - collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(), - SM, Method, Methods); -} - void ObjCMethodDecl::getOverriddenMethods( SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const { const ObjCMethodDecl *Method = this; @@ -943,10 +973,7 @@ void ObjCMethodDecl::getOverriddenMethods( getMethod(Method->getSelector(), Method->isInstanceMethod()); } - if (!Method->isOverriding()) { - collectOverriddenMethodsFast(getASTContext().getSourceManager(), - Method, Overridden); - } else { + if (Method->isOverriding()) { collectOverriddenMethodsSlow(Method, Overridden); assert(!Overridden.empty() && "ObjCMethodDecl's overriding bit is not as expected"); @@ -1575,7 +1602,7 @@ void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) { } /// FindPropertyImplIvarDecl - This method lookup the ivar in the list of -/// properties implemented in this category \@implementation block and returns +/// properties implemented in this \@implementation block and returns /// the implemented property that uses it. /// ObjCPropertyImplDecl *ObjCImplDecl:: @@ -1621,12 +1648,13 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, ObjCInterfaceDecl *SuperDecl, SourceLocation nameLoc, SourceLocation atStartLoc, + SourceLocation superLoc, SourceLocation IvarLBraceLoc, SourceLocation IvarRBraceLoc) { if (ClassInterface && ClassInterface->hasDefinition()) ClassInterface = ClassInterface->getDefinition(); return new (C) ObjCImplementationDecl(DC, ClassInterface, SuperDecl, - nameLoc, atStartLoc, + nameLoc, atStartLoc, superLoc, IvarLBraceLoc, IvarRBraceLoc); } diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp new file mode 100644 index 0000000000..c0d10a0f41 --- /dev/null +++ b/lib/AST/DeclOpenMP.cpp @@ -0,0 +1,60 @@ +//===--- DeclOpenMP.cpp - Declaration OpenMP AST Node Implementation ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This file implements OMPThreadPrivateDecl class. +/// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclOpenMP.h" +#include "clang/AST/Expr.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// OMPThreadPrivateDecl Implementation. +//===----------------------------------------------------------------------===// + +void OMPThreadPrivateDecl::anchor() { } + +OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation L, + ArrayRef<DeclRefExpr *> VL) { + unsigned Size = sizeof(OMPThreadPrivateDecl) + + (VL.size() * sizeof(DeclRefExpr *)); + + void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>()); + OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, + DC, L); + D->NumVars = VL.size(); + D->setVars(VL); + return D; +} + +OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, + unsigned ID, + unsigned N) { + unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *)); + + void *Mem = AllocateDeserializedDecl(C, ID, Size); + OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, + 0, SourceLocation()); + D->NumVars = N; + return D; +} + +void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) { + assert(VL.size() == NumVars && + "Number of variables is not the same as the preallocated buffer"); + DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1); + std::copy(VL.begin(), VL.end(), Vars); +} diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index e2a66fb8a7..d47972bc61 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -82,6 +82,7 @@ namespace { void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); + void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); void PrintTemplateParameters(const TemplateParameterList *Params, const TemplateArgumentList *Args = 0); @@ -291,8 +292,10 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { // FIXME: Need to be able to tell the DeclPrinter when const char *Terminator = 0; - if (isa<FunctionDecl>(*D) && - cast<FunctionDecl>(*D)->isThisDeclarationADefinition()) + if (isa<OMPThreadPrivateDecl>(*D)) + Terminator = 0; + else if (isa<FunctionDecl>(*D) && + cast<FunctionDecl>(*D)->isThisDeclarationADefinition()) Terminator = 0; else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody()) Terminator = 0; @@ -390,7 +393,7 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D); if (!Policy.SuppressSpecifiers) { - switch (D->getStorageClassAsWritten()) { + switch (D->getStorageClass()) { case SC_None: break; case SC_Extern: Out << "extern "; break; case SC_Static: Out << "static "; break; @@ -484,7 +487,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), E = CDecl->init_end(); B != E; ++B) { - CXXCtorInitializer * BMInitializer = (*B); + CXXCtorInitializer *BMInitializer = (*B); if (BMInitializer->isInClassMemberInitializer()) continue; @@ -614,7 +617,8 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) { if (!Policy.SuppressSpecifiers && D->isModulePrivate()) Out << "__module_private__ "; - Out << D->getType().stream(Policy, D->getName()); + Out << D->getASTContext().getUnqualifiedObjCPointerType(D->getType()). + stream(Policy, D->getName()); if (D->isBitField()) { Out << " : "; @@ -638,16 +642,30 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) { void DeclPrinter::VisitVarDecl(VarDecl *D) { - StorageClass SCAsWritten = D->getStorageClassAsWritten(); - if (!Policy.SuppressSpecifiers && SCAsWritten != SC_None) - Out << VarDecl::getStorageClassSpecifierString(SCAsWritten) << " "; + if (!Policy.SuppressSpecifiers) { + StorageClass SC = D->getStorageClass(); + if (SC != SC_None) + Out << VarDecl::getStorageClassSpecifierString(SC) << " "; - if (!Policy.SuppressSpecifiers && D->isThreadSpecified()) - Out << "__thread "; - if (!Policy.SuppressSpecifiers && D->isModulePrivate()) - Out << "__module_private__ "; + switch (D->getTSCSpec()) { + case TSCS_unspecified: + break; + case TSCS___thread: + Out << "__thread "; + break; + case TSCS__Thread_local: + Out << "_Thread_local "; + break; + case TSCS_thread_local: + Out << "thread_local "; + break; + } - QualType T = D->getType(); + if (D->isModulePrivate()) + Out << "__module_private__ "; + } + + QualType T = D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) T = Parm->getOriginalType(); T.print(Out, Policy, D->getName()); @@ -896,7 +914,8 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { else Out << "+ "; if (!OMD->getResultType().isNull()) - Out << '(' << OMD->getResultType().getAsString(Policy) << ")"; + Out << '(' << OMD->getASTContext().getUnqualifiedObjCPointerType(OMD->getResultType()). + getAsString(Policy) << ")"; std::string name = OMD->getSelector().getAsString(); std::string::size_type pos, lastPos = 0; @@ -905,7 +924,8 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { // FIXME: selector is missing here! pos = name.find_first_of(':', lastPos); Out << " " << name.substr(lastPos, pos - lastPos); - Out << ":(" << (*PI)->getType().getAsString(Policy) << ')' << **PI; + Out << ":(" << (*PI)->getASTContext().getUnqualifiedObjCPointerType((*PI)->getType()). + getAsString(Policy) << ')' << **PI; lastPos = pos + 1; } @@ -938,7 +958,8 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { Indentation += Policy.Indentation; for (ObjCImplementationDecl::ivar_iterator I = OID->ivar_begin(), E = OID->ivar_end(); I != E; ++I) { - Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n"; + Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()). + getAsString(Policy) << ' ' << **I << ";\n"; } Indentation -= Policy.Indentation; Out << "}\n"; @@ -976,7 +997,8 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { Indentation += Policy.Indentation; for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), E = OID->ivar_end(); I != E; ++I) { - Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n"; + Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()). + getAsString(Policy) << ' ' << **I << ";\n"; } Indentation -= Policy.Indentation; Out << "}\n"; @@ -1027,7 +1049,8 @@ void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { Indentation += Policy.Indentation; for (ObjCCategoryDecl::ivar_iterator I = PID->ivar_begin(), E = PID->ivar_end(); I != E; ++I) { - Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n"; + Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()). + getAsString(Policy) << ' ' << **I << ";\n"; } Indentation -= Policy.Indentation; Out << "}\n"; @@ -1113,7 +1136,8 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { (void) first; // Silence dead store warning due to idiomatic code. Out << " )"; } - Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << *PDecl; + Out << ' ' << PDecl->getASTContext().getUnqualifiedObjCPointerType(PDecl->getType()). + getAsString(Policy) << ' ' << *PDecl; if (Policy.PolishForDeclaration) Out << ';'; } @@ -1150,3 +1174,17 @@ void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) { // ignore } + +void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { + Out << "#pragma omp threadprivate"; + if (!D->varlist_empty()) { + for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(), + E = D->varlist_end(); + I != E; ++I) { + Out << (I == D->varlist_begin() ? '(' : ',') + << *cast<NamedDecl>((*I)->getDecl()); + } + Out << ")"; + } +} + diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index b97f4d1d3a..9538ddf941 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -100,11 +100,20 @@ Expr::skipRValueSubobjectAdjustments( const Expr * Expr::findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const { const Expr *E = this; + + // This might be a default initializer for a reference member. Walk over the + // wrapper node for that. + if (const CXXDefaultInitExpr *DAE = dyn_cast<CXXDefaultInitExpr>(E)) + E = DAE->getExpr(); + // Look through single-element init lists that claim to be lvalues. They're // just syntactic wrappers in this case. if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) { - if (ILE->getNumInits() == 1 && ILE->isGLValue()) + if (ILE->getNumInits() == 1 && ILE->isGLValue()) { E = ILE->getInit(0); + if (const CXXDefaultInitExpr *DAE = dyn_cast<CXXDefaultInitExpr>(E)) + E = DAE->getExpr(); + } } // Look through expressions for materialized temporaries (for now). @@ -280,7 +289,7 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T, // expression that is value-dependent [C++11] if (VarDecl *Var = dyn_cast<VarDecl>(D)) { if ((Ctx.getLangOpts().CPlusPlus11 ? - Var->getType()->isLiteralType() : + Var->getType()->isLiteralType(Ctx) : Var->getType()->isIntegralOrEnumerationType()) && (Var->getType().isConstQualified() || Var->getType()->isReferenceType())) { @@ -2174,6 +2183,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, case CXXDefaultArgExprClass: return (cast<CXXDefaultArgExpr>(this) ->getExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx)); + case CXXDefaultInitExprClass: + return (cast<CXXDefaultInitExpr>(this) + ->getExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx)); case CXXNewExprClass: // FIXME: In theory, there might be new expressions that don't have side @@ -2789,6 +2801,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { return false; case CallExprClass: + case MSPropertyRefExprClass: case CompoundAssignOperatorClass: case VAArgExprClass: case AtomicExprClass: @@ -2850,6 +2863,12 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case CXXDefaultArgExprClass: return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(Ctx); + case CXXDefaultInitExprClass: + if (const Expr *E = cast<CXXDefaultInitExpr>(this)->getExpr()) + return E->HasSideEffects(Ctx); + // If we've not yet parsed the initializer, assume it has side-effects. + return true; + case CXXDynamicCastExprClass: { // A dynamic_cast expression has side-effects if it can throw. const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(this); @@ -3037,8 +3056,12 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC); } else if (const CXXDefaultArgExpr *DefaultArg = dyn_cast<CXXDefaultArgExpr>(this)) { - // See through default argument expressions + // See through default argument expressions. return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC); + } else if (const CXXDefaultInitExpr *DefaultInit + = dyn_cast<CXXDefaultInitExpr>(this)) { + // See through default initializer expressions. + return DefaultInit->getExpr()->isNullPointerConstant(Ctx, NPC); } else if (isa<GNUNullExpr>(this)) { // The GNU __null extension is always a null pointer constant. return NPCK_GNUNull; @@ -3126,7 +3149,7 @@ bool Expr::isObjCSelfExpr() const { return M->getSelfDecl() == Param; } -FieldDecl *Expr::getBitField() { +FieldDecl *Expr::getSourceBitField() { Expr *E = this->IgnoreParens(); while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { @@ -3142,6 +3165,11 @@ FieldDecl *Expr::getBitField() { if (Field->isBitField()) return Field; + if (ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) + if (FieldDecl *Ivar = dyn_cast<FieldDecl>(IvarRef->getDecl())) + if (Ivar->isBitField()) + return Ivar; + if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E)) if (FieldDecl *Field = dyn_cast<FieldDecl>(DeclRef->getDecl())) if (Field->isBitField()) @@ -3149,10 +3177,10 @@ FieldDecl *Expr::getBitField() { if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E)) { if (BinOp->isAssignmentOp() && BinOp->getLHS()) - return BinOp->getLHS()->getBitField(); + return BinOp->getLHS()->getSourceBitField(); if (BinOp->getOpcode() == BO_Comma && BinOp->getRHS()) - return BinOp->getRHS()->getBitField(); + return BinOp->getRHS()->getSourceBitField(); } return 0; diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 12a47fcd78..402d7b532b 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -178,8 +178,7 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context, SourceLocation ColonColonLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType) : Expr(CXXPseudoDestructorExprClass, - Context.getPointerType(Context.getFunctionType(Context.VoidTy, - ArrayRef<QualType>(), + Context.getPointerType(Context.getFunctionType(Context.VoidTy, None, FunctionProtoType::ExtProtoInfo())), VK_RValue, OK_Ordinary, /*isTypeDependent=*/(Base->isTypeDependent() || @@ -704,6 +703,17 @@ CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc, SubExpr); } +CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc, + FieldDecl *Field, QualType T) + : Expr(CXXDefaultInitExprClass, T.getNonLValueExprType(C), + T->isLValueReferenceType() ? VK_LValue : T->isRValueReferenceType() + ? VK_XValue + : VK_RValue, + /*FIXME*/ OK_Ordinary, false, false, false, false), + Field(Field), Loc(Loc) { + assert(Field->hasInClassInitializer()); +} + CXXTemporary *CXXTemporary::Create(ASTContext &C, const CXXDestructorDecl *Destructor) { return new (C) CXXTemporary(Destructor); diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 61bc3e2de5..bcb6d4e809 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -134,6 +134,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // FIXME: ObjC++0x might have different rules case Expr::ObjCIvarRefExprClass: case Expr::FunctionParmPackExprClass: + case Expr::MSPropertyRefExprClass: return Cl::CL_LValue; // C99 6.5.2.5p5 says that compound literals are lvalues. @@ -297,6 +298,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXDefaultArgExprClass: return ClassifyInternal(Ctx, cast<CXXDefaultArgExpr>(E)->getExpr()); + // Same idea for default initializers. + case Expr::CXXDefaultInitExprClass: + return ClassifyInternal(Ctx, cast<CXXDefaultInitExpr>(E)->getExpr()); + // Same idea for temporary binding. case Expr::CXXBindTemporaryExprClass: return ClassifyInternal(Ctx, cast<CXXBindTemporaryExpr>(E)->getSubExpr()); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index ae86150ee2..8c650290b5 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -286,21 +286,37 @@ namespace { /// ParmBindings - Parameter bindings for this function call, indexed by /// parameters' function scope indices. - const APValue *Arguments; + APValue *Arguments; // Note that we intentionally use std::map here so that references to // values are stable. - typedef std::map<const Expr*, APValue> MapTy; + typedef std::map<const void*, APValue> MapTy; typedef MapTy::const_iterator temp_iterator; /// Temporaries - Temporary lvalues materialized within this stack frame. MapTy Temporaries; CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, const FunctionDecl *Callee, const LValue *This, - const APValue *Arguments); + APValue *Arguments); ~CallStackFrame(); }; + /// Temporarily override 'this'. + class ThisOverrideRAII { + public: + ThisOverrideRAII(CallStackFrame &Frame, const LValue *NewThis, bool Enable) + : Frame(Frame), OldThis(Frame.This) { + if (Enable) + Frame.This = NewThis; + } + ~ThisOverrideRAII() { + Frame.This = OldThis; + } + private: + CallStackFrame &Frame; + const LValue *OldThis; + }; + /// A partial diagnostic which we might know in advance that we are not going /// to emit. class OptionalDiagnostic { @@ -581,7 +597,7 @@ void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info, CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, const FunctionDecl *Callee, const LValue *This, - const APValue *Arguments) + APValue *Arguments) : Info(Info), Caller(Info.CurrentCall), CallLoc(CallLoc), Callee(Callee), Index(Info.NextCallIndex++), This(This), Arguments(Arguments) { Info.CurrentCall = this; @@ -897,6 +913,18 @@ static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info); // Misc utilities //===----------------------------------------------------------------------===// +/// Evaluate an expression to see if it had side-effects, and discard its +/// result. +/// \return \c true if the caller should keep evaluating. +static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) { + APValue Scratch; + if (!Evaluate(Scratch, Info, E)) { + Info.EvalStatus.HasSideEffects = true; + return Info.keepEvaluatingAfterFailure(); + } + return true; +} + /// Should this call expression be treated as a string literal? static bool IsStringLiteralCall(const CallExpr *E) { unsigned Builtin = E->isBuiltinCall(); @@ -999,7 +1027,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, // Check if this is a thread-local variable. if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) { - if (Var->isThreadSpecified()) + if (Var->getTLSKind()) return false; } } @@ -1030,7 +1058,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, /// Check that this core constant expression is of literal type, and if not, /// produce an appropriate diagnostic. static bool CheckLiteralType(EvalInfo &Info, const Expr *E) { - if (!E->isRValue() || E->getType()->isLiteralType()) + if (!E->isRValue() || E->getType()->isLiteralType(Info.Ctx)) return true; // Prvalue constant expressions must be of literal types. @@ -1427,9 +1455,16 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E, } /// Try to evaluate the initializer for a variable declaration. -static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, - const VarDecl *VD, - CallStackFrame *Frame, APValue &Result) { +/// +/// \param Info Information about the ongoing evaluation. +/// \param E An expression to be used when printing diagnostics. +/// \param VD The variable whose initializer should be obtained. +/// \param Frame The frame in which the variable was created. Must be null +/// if this variable is not local to the evaluation. +/// \param Result Filled in with a pointer to the value of the variable. +static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, + const VarDecl *VD, CallStackFrame *Frame, + APValue *&Result) { // If this is a parameter to an active constexpr function call, perform // argument substitution. if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) { @@ -1441,10 +1476,19 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); return false; } - Result = Frame->Arguments[PVD->getFunctionScopeIndex()]; + Result = &Frame->Arguments[PVD->getFunctionScopeIndex()]; return true; } + // If this is a local variable, dig out its value. + if (Frame) { + Result = &Frame->Temporaries[VD]; + // If we've carried on past an unevaluatable local variable initializer, + // we can't go any further. This can happen during potential constant + // expression checking. + return !Result->isUninit(); + } + // Dig out the initializer, and use the declaration which it's attached to. const Expr *Init = VD->getAnyInitializer(VD); if (!Init || Init->isValueDependent()) { @@ -1458,8 +1502,8 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, // If we're currently evaluating the initializer of this declaration, use that // in-flight value. if (Info.EvaluatingDecl == VD) { - Result = *Info.EvaluatingDeclValue; - return !Result.isUninit(); + Result = Info.EvaluatingDeclValue; + return !Result->isUninit(); } // Never evaluate the initializer of a weak variable. We can't be sure that @@ -1485,7 +1529,7 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, Info.addNotes(Notes); } - Result = *VD->getEvaluatedValue(); + Result = VD->getEvaluatedValue(); return true; } @@ -1509,15 +1553,15 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived, llvm_unreachable("base class missing from derived class's bases list"); } -/// Extract the value of a character from a string literal. CharType is used to -/// determine the expected signedness of the result -- a string literal used to -/// initialize an array of 'signed char' or 'unsigned char' might contain chars -/// of the wrong signedness. -static APSInt ExtractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, - uint64_t Index, QualType CharType) { +/// Extract the value of a character from a string literal. +static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, + uint64_t Index) { // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant - const StringLiteral *S = dyn_cast<StringLiteral>(Lit); - assert(S && "unexpected string literal expression kind"); + const StringLiteral *S = cast<StringLiteral>(Lit); + const ConstantArrayType *CAT = + Info.Ctx.getAsConstantArrayType(S->getType()); + assert(CAT && "string literal isn't an array"); + QualType CharType = CAT->getElementType(); assert(CharType->isIntegerType() && "unexpected character type"); APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(), @@ -1527,26 +1571,99 @@ static APSInt ExtractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, return Value; } -/// Extract the designated sub-object of an rvalue. -static bool ExtractSubobject(EvalInfo &Info, const Expr *E, - APValue &Obj, QualType ObjType, - const SubobjectDesignator &Sub, QualType SubType) { +// Expand a string literal into an array of characters. +static void expandStringLiteral(EvalInfo &Info, const Expr *Lit, + APValue &Result) { + const StringLiteral *S = cast<StringLiteral>(Lit); + const ConstantArrayType *CAT = + Info.Ctx.getAsConstantArrayType(S->getType()); + assert(CAT && "string literal isn't an array"); + QualType CharType = CAT->getElementType(); + assert(CharType->isIntegerType() && "unexpected character type"); + + unsigned Elts = CAT->getSize().getZExtValue(); + Result = APValue(APValue::UninitArray(), + std::min(S->getLength(), Elts), Elts); + APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(), + CharType->isUnsignedIntegerType()); + if (Result.hasArrayFiller()) + Result.getArrayFiller() = APValue(Value); + for (unsigned I = 0, N = Result.getArrayInitializedElts(); I != N; ++I) { + Value = S->getCodeUnit(I); + Result.getArrayInitializedElt(I) = APValue(Value); + } +} + +// Expand an array so that it has more than Index filled elements. +static void expandArray(APValue &Array, unsigned Index) { + unsigned Size = Array.getArraySize(); + assert(Index < Size); + + // Always at least double the number of elements for which we store a value. + unsigned OldElts = Array.getArrayInitializedElts(); + unsigned NewElts = std::max(Index+1, OldElts * 2); + NewElts = std::min(Size, std::max(NewElts, 8u)); + + // Copy the data across. + APValue NewValue(APValue::UninitArray(), NewElts, Size); + for (unsigned I = 0; I != OldElts; ++I) + NewValue.getArrayInitializedElt(I).swap(Array.getArrayInitializedElt(I)); + for (unsigned I = OldElts; I != NewElts; ++I) + NewValue.getArrayInitializedElt(I) = Array.getArrayFiller(); + if (NewValue.hasArrayFiller()) + NewValue.getArrayFiller() = Array.getArrayFiller(); + Array.swap(NewValue); +} + +/// Kinds of access we can perform on an object. +enum AccessKinds { + AK_Read, + AK_Assign, + AK_Increment, + AK_Decrement +}; + +/// A handle to a complete object (an object that is not a subobject of +/// another object). +struct CompleteObject { + /// The value of the complete object. + APValue *Value; + /// The type of the complete object. + QualType Type; + + CompleteObject() : Value(0) {} + CompleteObject(APValue *Value, QualType Type) + : Value(Value), Type(Type) { + assert(Value && "missing value for complete object"); + } + + operator bool() const { return Value; } +}; + +/// Find the designated sub-object of an rvalue. +template<typename SubobjectHandler> +typename SubobjectHandler::result_type +findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, + const SubobjectDesignator &Sub, SubobjectHandler &handler) { if (Sub.Invalid) // A diagnostic will have already been produced. - return false; + return handler.failed(); if (Sub.isOnePastTheEnd()) { - Info.Diag(E, Info.getLangOpts().CPlusPlus11 ? - (unsigned)diag::note_constexpr_read_past_end : - (unsigned)diag::note_invalid_subexpr_in_const_expr); - return false; + if (Info.getLangOpts().CPlusPlus11) + Info.Diag(E, diag::note_constexpr_access_past_end) + << handler.AccessKind; + else + Info.Diag(E); + return handler.failed(); } if (Sub.Entries.empty()) - return true; - if (Info.CheckingPotentialConstantExpression && Obj.isUninit()) + return handler.found(*Obj.Value, Obj.Type); + if (Info.CheckingPotentialConstantExpression && Obj.Value->isUninit()) // This object might be initialized later. - return false; + return handler.failed(); - APValue *O = &Obj; + APValue *O = Obj.Value; + QualType ObjType = Obj.Type; // Walk the designator's path to find the subobject. for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) { if (ObjType->isArrayType()) { @@ -1557,49 +1674,67 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, if (CAT->getSize().ule(Index)) { // Note, it should not be possible to form a pointer with a valid // designator which points more than one past the end of the array. - Info.Diag(E, Info.getLangOpts().CPlusPlus11 ? - (unsigned)diag::note_constexpr_read_past_end : - (unsigned)diag::note_invalid_subexpr_in_const_expr); - return false; + if (Info.getLangOpts().CPlusPlus11) + Info.Diag(E, diag::note_constexpr_access_past_end) + << handler.AccessKind; + else + Info.Diag(E); + return handler.failed(); } + + ObjType = CAT->getElementType(); + // An array object is represented as either an Array APValue or as an // LValue which refers to a string literal. if (O->isLValue()) { assert(I == N - 1 && "extracting subobject of character?"); assert(!O->hasLValuePath() || O->getLValuePath().empty()); - Obj = APValue(ExtractStringLiteralCharacter( - Info, O->getLValueBase().get<const Expr*>(), Index, SubType)); - return true; - } else if (O->getArrayInitializedElts() > Index) + if (handler.AccessKind != AK_Read) + expandStringLiteral(Info, O->getLValueBase().get<const Expr *>(), + *O); + else + return handler.foundString(*O, ObjType, Index); + } + + if (O->getArrayInitializedElts() > Index) O = &O->getArrayInitializedElt(Index); - else + else if (handler.AccessKind != AK_Read) { + expandArray(*O, Index); + O = &O->getArrayInitializedElt(Index); + } else O = &O->getArrayFiller(); - ObjType = CAT->getElementType(); } else if (ObjType->isAnyComplexType()) { // Next subobject is a complex number. uint64_t Index = Sub.Entries[I].ArrayIndex; if (Index > 1) { - Info.Diag(E, Info.getLangOpts().CPlusPlus11 ? - (unsigned)diag::note_constexpr_read_past_end : - (unsigned)diag::note_invalid_subexpr_in_const_expr); - return false; + if (Info.getLangOpts().CPlusPlus11) + Info.Diag(E, diag::note_constexpr_access_past_end) + << handler.AccessKind; + else + Info.Diag(E); + return handler.failed(); } + + bool WasConstQualified = ObjType.isConstQualified(); + ObjType = ObjType->castAs<ComplexType>()->getElementType(); + if (WasConstQualified) + ObjType.addConst(); + assert(I == N - 1 && "extracting subobject of scalar?"); if (O->isComplexInt()) { - Obj = APValue(Index ? O->getComplexIntImag() - : O->getComplexIntReal()); + return handler.found(Index ? O->getComplexIntImag() + : O->getComplexIntReal(), ObjType); } else { assert(O->isComplexFloat()); - Obj = APValue(Index ? O->getComplexFloatImag() - : O->getComplexFloatReal()); + return handler.found(Index ? O->getComplexFloatImag() + : O->getComplexFloatReal(), ObjType); } - return true; } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) { - if (Field->isMutable()) { + if (Field->isMutable() && handler.AccessKind == AK_Read) { Info.Diag(E, diag::note_constexpr_ltor_mutable, 1) << Field; Info.Note(Field->getLocation(), diag::note_declared_at); - return false; + return handler.failed(); } // Next subobject is a class, struct or union field. @@ -1608,49 +1743,150 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, const FieldDecl *UnionField = O->getUnionField(); if (!UnionField || UnionField->getCanonicalDecl() != Field->getCanonicalDecl()) { - Info.Diag(E, diag::note_constexpr_read_inactive_union_member) - << Field << !UnionField << UnionField; - return false; + Info.Diag(E, diag::note_constexpr_access_inactive_union_member) + << handler.AccessKind << Field << !UnionField << UnionField; + return handler.failed(); } O = &O->getUnionValue(); } else O = &O->getStructField(Field->getFieldIndex()); + + bool WasConstQualified = ObjType.isConstQualified(); ObjType = Field->getType(); + if (WasConstQualified && !Field->isMutable()) + ObjType.addConst(); if (ObjType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) { // FIXME: Include a description of the path to the volatile subobject. - Info.Diag(E, diag::note_constexpr_ltor_volatile_obj, 1) - << 2 << Field; + Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) + << handler.AccessKind << 2 << Field; Info.Note(Field->getLocation(), diag::note_declared_at); } else { Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); } - return false; + return handler.failed(); } } else { // Next subobject is a base class. const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl(); const CXXRecordDecl *Base = getAsBaseClass(Sub.Entries[I]); O = &O->getStructBase(getBaseIndex(Derived, Base)); + + bool WasConstQualified = ObjType.isConstQualified(); ObjType = Info.Ctx.getRecordType(Base); + if (WasConstQualified) + ObjType.addConst(); } if (O->isUninit()) { if (!Info.CheckingPotentialConstantExpression) - Info.Diag(E, diag::note_constexpr_read_uninit); + Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind; + return handler.failed(); + } + } + + return handler.found(*O, ObjType); +} + +namespace { +struct ExtractSubobjectHandler { + EvalInfo &Info; + APValue &Result; + + static const AccessKinds AccessKind = AK_Read; + + typedef bool result_type; + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + Result = Subobj; + return true; + } + bool found(APSInt &Value, QualType SubobjType) { + Result = APValue(Value); + return true; + } + bool found(APFloat &Value, QualType SubobjType) { + Result = APValue(Value); + return true; + } + bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { + Result = APValue(extractStringLiteralCharacter( + Info, Subobj.getLValueBase().get<const Expr *>(), Character)); + return true; + } +}; +} // end anonymous namespace + +const AccessKinds ExtractSubobjectHandler::AccessKind; + +/// Extract the designated sub-object of an rvalue. +static bool extractSubobject(EvalInfo &Info, const Expr *E, + const CompleteObject &Obj, + const SubobjectDesignator &Sub, + APValue &Result) { + ExtractSubobjectHandler Handler = { Info, Result }; + return findSubobject(Info, E, Obj, Sub, Handler); +} + +namespace { +struct ModifySubobjectHandler { + EvalInfo &Info; + APValue &NewVal; + const Expr *E; + + typedef bool result_type; + static const AccessKinds AccessKind = AK_Assign; + + bool checkConst(QualType QT) { + // Assigning to a const object has undefined behavior. + if (QT.isConstQualified()) { + Info.Diag(E, diag::note_constexpr_modify_const_type) << QT; return false; } + return true; } - // This may look super-stupid, but it serves an important purpose: if we just - // swapped Obj and *O, we'd create an object which had itself as a subobject. - // To avoid the leak, we ensure that Tmp ends up owning the original complete - // object, which is destroyed by Tmp's destructor. - APValue Tmp; - O->swap(Tmp); - Obj.swap(Tmp); - return true; + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + // We've been given ownership of NewVal, so just swap it in. + Subobj.swap(NewVal); + return true; + } + bool found(APSInt &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + if (!NewVal.isInt()) { + // Maybe trying to write a cast pointer value into a complex? + Info.Diag(E); + return false; + } + Value = NewVal.getInt(); + return true; + } + bool found(APFloat &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + Value = NewVal.getFloat(); + return true; + } + bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { + llvm_unreachable("shouldn't encounter string elements with ExpandArrays"); + } +}; +} // end anonymous namespace + +const AccessKinds ModifySubobjectHandler::AccessKind; + +/// Update the designated sub-object of an rvalue to the given value. +static bool modifySubobject(EvalInfo &Info, const Expr *E, + const CompleteObject &Obj, + const SubobjectDesignator &Sub, + APValue &NewVal) { + ModifySubobjectHandler Handler = { Info, NewVal, E }; + return findSubobject(Info, E, Obj, Sub, Handler); } /// Find the position where two subobject designators diverge, or equivalently @@ -1710,59 +1946,52 @@ static bool AreElementsOfSameArray(QualType ObjType, return CommonLength >= A.Entries.size() - IsArray; } -/// HandleLValueToRValueConversion - Perform an lvalue-to-rvalue conversion on -/// the given lvalue. This can also be used for 'lvalue-to-lvalue' conversions -/// for looking up the glvalue referred to by an entity of reference type. -/// -/// \param Info - Information about the ongoing evaluation. -/// \param Conv - The expression for which we are performing the conversion. -/// Used for diagnostics. -/// \param Type - The type we expect this conversion to produce, before -/// stripping cv-qualifiers in the case of a non-clas type. -/// \param LVal - The glvalue on which we are attempting to perform this action. -/// \param RVal - The produced value will be placed here. -static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, - QualType Type, - const LValue &LVal, APValue &RVal) { - if (LVal.Designator.Invalid) - // A diagnostic will have already been produced. - return false; - - const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); - +/// Find the complete object to which an LValue refers. +CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, + const LValue &LVal, QualType LValType) { if (!LVal.Base) { - // FIXME: Indirection through a null pointer deserves a specific diagnostic. - Info.Diag(Conv, diag::note_invalid_subexpr_in_const_expr); - return false; + Info.Diag(E, diag::note_constexpr_access_null) << AK; + return CompleteObject(); } CallStackFrame *Frame = 0; if (LVal.CallIndex) { Frame = Info.getCallFrame(LVal.CallIndex); if (!Frame) { - Info.Diag(Conv, diag::note_constexpr_lifetime_ended, 1) << !Base; + Info.Diag(E, diag::note_constexpr_lifetime_ended, 1) + << AK << LVal.Base.is<const ValueDecl*>(); NoteLValueLocation(Info, LVal.Base); - return false; + return CompleteObject(); } + } else if (AK != AK_Read) { + Info.Diag(E, diag::note_constexpr_modify_global); + return CompleteObject(); } // C++11 DR1311: An lvalue-to-rvalue conversion on a volatile-qualified type // is not a constant expression (even if the object is non-volatile). We also // apply this rule to C++98, in order to conform to the expected 'volatile' // semantics. - if (Type.isVolatileQualified()) { + if (LValType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) - Info.Diag(Conv, diag::note_constexpr_ltor_volatile_type) << Type; + Info.Diag(E, diag::note_constexpr_access_volatile_type) + << AK << LValType; else - Info.Diag(Conv); - return false; + Info.Diag(E); + return CompleteObject(); } + // Compute value storage location and type of base object. + APValue *BaseVal = 0; + QualType BaseType; + if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) { // In C++98, const, non-volatile integers initialized with ICEs are ICEs. // In C++11, constexpr, non-volatile variables initialized with constant // expressions are constant expressions too. Inside constexpr functions, // parameters are constant expressions even if they're non-const. + // In C++1y, objects local to a constant expression (those with a Frame) are + // both readable and writable inside constant expressions. // In C, such things can also be folded, although they are not ICEs. const VarDecl *VD = dyn_cast<VarDecl>(D); if (VD) { @@ -1770,120 +1999,312 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, VD = VDef; } if (!VD || VD->isInvalidDecl()) { - Info.Diag(Conv); - return false; + Info.Diag(E); + return CompleteObject(); } - // DR1313: If the object is volatile-qualified but the glvalue was not, - // behavior is undefined so the result is not a constant expression. - QualType VT = VD->getType(); - if (VT.isVolatileQualified()) { + // Accesses of volatile-qualified objects are not allowed. + BaseType = VD->getType(); + if (BaseType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) { - Info.Diag(Conv, diag::note_constexpr_ltor_volatile_obj, 1) << 1 << VD; + Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) + << AK << 1 << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.Diag(Conv); + Info.Diag(E); } - return false; + return CompleteObject(); } - if (!isa<ParmVarDecl>(VD)) { + // Unless we're looking at a local variable or argument in a constexpr call, + // the variable we're reading must be const. + if (!Frame) { + assert(AK == AK_Read && "can't modify non-local"); if (VD->isConstexpr()) { // OK, we can read this variable. - } else if (VT->isIntegralOrEnumerationType()) { - if (!VT.isConstQualified()) { + } else if (BaseType->isIntegralOrEnumerationType()) { + if (!BaseType.isConstQualified()) { if (Info.getLangOpts().CPlusPlus) { - Info.Diag(Conv, diag::note_constexpr_ltor_non_const_int, 1) << VD; + Info.Diag(E, diag::note_constexpr_ltor_non_const_int, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.Diag(Conv); + Info.Diag(E); } - return false; + return CompleteObject(); } - } else if (VT->isFloatingType() && VT.isConstQualified()) { + } else if (BaseType->isFloatingType() && BaseType.isConstQualified()) { // We support folding of const floating-point types, in order to make // static const data members of such types (supported as an extension) // more useful. if (Info.getLangOpts().CPlusPlus11) { - Info.CCEDiag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD; + Info.CCEDiag(E, diag::note_constexpr_ltor_non_constexpr, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.CCEDiag(Conv); + Info.CCEDiag(E); } } else { // FIXME: Allow folding of values of any literal type in all languages. if (Info.getLangOpts().CPlusPlus11) { - Info.Diag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD; + Info.Diag(E, diag::note_constexpr_ltor_non_constexpr, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.Diag(Conv); + Info.Diag(E); } - return false; + return CompleteObject(); } } - if (!EvaluateVarDeclInit(Info, Conv, VD, Frame, RVal)) - return false; + if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal)) + return CompleteObject(); + } else { + const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); + + if (!Frame) { + Info.Diag(E); + return CompleteObject(); + } - if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue()) - return ExtractSubobject(Info, Conv, RVal, VT, LVal.Designator, Type); - - // The declaration was initialized by an lvalue, with no lvalue-to-rvalue - // conversion. This happens when the declaration and the lvalue should be - // considered synonymous, for instance when initializing an array of char - // from a string literal. Continue as if the initializer lvalue was the - // value we were originally given. - assert(RVal.getLValueOffset().isZero() && - "offset for lvalue init of non-reference"); - Base = RVal.getLValueBase().get<const Expr*>(); - - if (unsigned CallIndex = RVal.getLValueCallIndex()) { - Frame = Info.getCallFrame(CallIndex); - if (!Frame) { - Info.Diag(Conv, diag::note_constexpr_lifetime_ended, 1) << !Base; - NoteLValueLocation(Info, RVal.getLValueBase()); + BaseType = Base->getType(); + BaseVal = &Frame->Temporaries[Base]; + + // Volatile temporary objects cannot be accessed in constant expressions. + if (BaseType.isVolatileQualified()) { + if (Info.getLangOpts().CPlusPlus) { + Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) + << AK << 0; + Info.Note(Base->getExprLoc(), diag::note_constexpr_temporary_here); + } else { + Info.Diag(E); + } + return CompleteObject(); + } + } + + // In C++1y, we can't safely access any mutable state when checking a + // potential constant expression. + if (Frame && Info.getLangOpts().CPlusPlus1y && + Info.CheckingPotentialConstantExpression) + return CompleteObject(); + + return CompleteObject(BaseVal, BaseType); +} + +/// \brief Perform an lvalue-to-rvalue conversion on the given glvalue. This +/// can also be used for 'lvalue-to-lvalue' conversions for looking up the +/// glvalue referred to by an entity of reference type. +/// +/// \param Info - Information about the ongoing evaluation. +/// \param Conv - The expression for which we are performing the conversion. +/// Used for diagnostics. +/// \param Type - The type of the glvalue (before stripping cv-qualifiers in the +/// case of a non-class type). +/// \param LVal - The glvalue on which we are attempting to perform this action. +/// \param RVal - The produced value will be placed here. +static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, + QualType Type, + const LValue &LVal, APValue &RVal) { + if (LVal.Designator.Invalid) + return false; + + // Check for special cases where there is no existing APValue to look at. + const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); + if (!LVal.Designator.Invalid && Base && !LVal.CallIndex && + !Type.isVolatileQualified()) { + if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) { + // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the + // initializer until now for such expressions. Such an expression can't be + // an ICE in C, so this only matters for fold. + assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); + if (Type.isVolatileQualified()) { + Info.Diag(Conv); return false; } - } else { - Frame = 0; + APValue Lit; + if (!Evaluate(Lit, Info, CLE->getInitializer())) + return false; + CompleteObject LitObj(&Lit, Base->getType()); + return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal); + } else if (isa<StringLiteral>(Base)) { + // We represent a string literal array as an lvalue pointing at the + // corresponding expression, rather than building an array of chars. + // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant + APValue Str(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0); + CompleteObject StrObj(&Str, Base->getType()); + return extractSubobject(Info, Conv, StrObj, LVal.Designator, RVal); } } - // Volatile temporary objects cannot be read in constant expressions. - if (Base->getType().isVolatileQualified()) { - if (Info.getLangOpts().CPlusPlus) { - Info.Diag(Conv, diag::note_constexpr_ltor_volatile_obj, 1) << 0; - Info.Note(Base->getExprLoc(), diag::note_constexpr_temporary_here); + CompleteObject Obj = findCompleteObject(Info, Conv, AK_Read, LVal, Type); + return Obj && extractSubobject(Info, Conv, Obj, LVal.Designator, RVal); +} + +/// Perform an assignment of Val to LVal. Takes ownership of Val. +static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal, + QualType LValType, APValue &Val) { + if (LVal.Designator.Invalid) + return false; + + if (!Info.getLangOpts().CPlusPlus1y) { + Info.Diag(E); + return false; + } + + CompleteObject Obj = findCompleteObject(Info, E, AK_Assign, LVal, LValType); + return Obj && modifySubobject(Info, E, Obj, LVal.Designator, Val); +} + +static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) { + return T->isSignedIntegerType() && + Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy); +} + +namespace { +struct IncDecSubobjectHandler { + EvalInfo &Info; + const Expr *E; + AccessKinds AccessKind; + APValue *Old; + + typedef bool result_type; + + bool checkConst(QualType QT) { + // Assigning to a const object has undefined behavior. + if (QT.isConstQualified()) { + Info.Diag(E, diag::note_constexpr_modify_const_type) << QT; + return false; + } + return true; + } + + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + // Stash the old value. Also clear Old, so we don't clobber it later + // if we're post-incrementing a complex. + if (Old) { + *Old = Subobj; + Old = 0; + } + + switch (Subobj.getKind()) { + case APValue::Int: + return found(Subobj.getInt(), SubobjType); + case APValue::Float: + return found(Subobj.getFloat(), SubobjType); + case APValue::ComplexInt: + return found(Subobj.getComplexIntReal(), + SubobjType->castAs<ComplexType>()->getElementType() + .withCVRQualifiers(SubobjType.getCVRQualifiers())); + case APValue::ComplexFloat: + return found(Subobj.getComplexFloatReal(), + SubobjType->castAs<ComplexType>()->getElementType() + .withCVRQualifiers(SubobjType.getCVRQualifiers())); + case APValue::LValue: + return foundPointer(Subobj, SubobjType); + default: + // FIXME: can this happen? + Info.Diag(E); + return false; + } + } + bool found(APSInt &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + + if (!SubobjType->isIntegerType()) { + // We don't support increment / decrement on integer-cast-to-pointer + // values. + Info.Diag(E); + return false; + } + + if (Old) *Old = APValue(Value); + + // bool arithmetic promotes to int, and the conversion back to bool + // doesn't reduce mod 2^n, so special-case it. + if (SubobjType->isBooleanType()) { + if (AccessKind == AK_Increment) + Value = 1; + else + Value = !Value; + return true; + } + + bool WasNegative = Value.isNegative(); + if (AccessKind == AK_Increment) { + ++Value; + + if (!WasNegative && Value.isNegative() && + isOverflowingIntegerType(Info.Ctx, SubobjType)) { + APSInt ActualValue(Value, /*IsUnsigned*/true); + HandleOverflow(Info, E, ActualValue, SubobjType); + } } else { - Info.Diag(Conv); + --Value; + + if (WasNegative && !Value.isNegative() && + isOverflowingIntegerType(Info.Ctx, SubobjType)) { + unsigned BitWidth = Value.getBitWidth(); + APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false); + ActualValue.setBit(BitWidth); + HandleOverflow(Info, E, ActualValue, SubobjType); + } } - return false; + return true; } + bool found(APFloat &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; - if (Frame) { - // If this is a temporary expression with a nontrivial initializer, grab the - // value from the relevant stack frame. - RVal = Frame->Temporaries[Base]; - } else if (const CompoundLiteralExpr *CLE - = dyn_cast<CompoundLiteralExpr>(Base)) { - // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the - // initializer until now for such expressions. Such an expression can't be - // an ICE in C, so this only matters for fold. - assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); - if (!Evaluate(RVal, Info, CLE->getInitializer())) + if (Old) *Old = APValue(Value); + + APFloat One(Value.getSemantics(), 1); + if (AccessKind == AK_Increment) + Value.add(One, APFloat::rmNearestTiesToEven); + else + Value.subtract(One, APFloat::rmNearestTiesToEven); + return true; + } + bool foundPointer(APValue &Subobj, QualType SubobjType) { + if (!checkConst(SubobjType)) return false; - } else if (isa<StringLiteral>(Base)) { - // We represent a string literal array as an lvalue pointing at the - // corresponding expression, rather than building an array of chars. - // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant - RVal = APValue(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0); - } else { - Info.Diag(Conv, diag::note_invalid_subexpr_in_const_expr); + + QualType PointeeType; + if (const PointerType *PT = SubobjType->getAs<PointerType>()) + PointeeType = PT->getPointeeType(); + else { + Info.Diag(E); + return false; + } + + LValue LVal; + LVal.setFrom(Info.Ctx, Subobj); + if (!HandleLValueArrayAdjustment(Info, E, LVal, PointeeType, + AccessKind == AK_Increment ? 1 : -1)) + return false; + LVal.moveInto(Subobj); + return true; + } + bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { + llvm_unreachable("shouldn't encounter string elements here"); + } +}; +} // end anonymous namespace + +/// Perform an increment or decrement on LVal. +static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal, + QualType LValType, bool IsIncrement, APValue *Old) { + if (LVal.Designator.Invalid) + return false; + + if (!Info.getLangOpts().CPlusPlus1y) { + Info.Diag(E); return false; } - return ExtractSubobject(Info, Conv, RVal, Base->getType(), LVal.Designator, - Type); + AccessKinds AK = IsIncrement ? AK_Increment : AK_Decrement; + CompleteObject Obj = findCompleteObject(Info, E, AK, LVal, LValType); + IncDecSubobjectHandler Handler = { Info, E, AK, Old }; + return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler); } /// Build an lvalue for the object argument of a member function call. @@ -1895,7 +2316,7 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object, if (Object->isGLValue()) return EvaluateLValue(Object, This, Info); - if (Object->getType()->isLiteralType()) + if (Object->getType()->isLiteralType(Info.Ctx)) return EvaluateTemporary(Object, This, Info); return false; @@ -2040,24 +2461,95 @@ enum EvalStmtResult { /// Hit a 'return' statement. ESR_Returned, /// Evaluation succeeded. - ESR_Succeeded + ESR_Succeeded, + /// Hit a 'continue' statement. + ESR_Continue, + /// Hit a 'break' statement. + ESR_Break }; } +static bool EvaluateDecl(EvalInfo &Info, const Decl *D) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + // We don't need to evaluate the initializer for a static local. + if (!VD->hasLocalStorage()) + return true; + + LValue Result; + Result.set(VD, Info.CurrentCall->Index); + APValue &Val = Info.CurrentCall->Temporaries[VD]; + + if (!EvaluateInPlace(Val, Info, Result, VD->getInit())) { + // Wipe out any partially-computed value, to allow tracking that this + // evaluation failed. + Val = APValue(); + return false; + } + } + + return true; +} + +/// Evaluate a condition (either a variable declaration or an expression). +static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl, + const Expr *Cond, bool &Result) { + if (CondDecl && !EvaluateDecl(Info, CondDecl)) + return false; + return EvaluateAsBooleanCondition(Cond, Result, Info); +} + +static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, + const Stmt *S); + +/// Evaluate the body of a loop, and translate the result as appropriate. +static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, + const Stmt *Body) { + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body)) { + case ESR_Break: + return ESR_Succeeded; + case ESR_Succeeded: + case ESR_Continue: + return ESR_Continue; + case ESR_Failed: + case ESR_Returned: + return ESR; + } + llvm_unreachable("Invalid EvalStmtResult!"); +} + // Evaluate a statement. static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, const Stmt *S) { + // FIXME: Mark all temporaries in the current frame as destroyed at + // the end of each full-expression. switch (S->getStmtClass()) { default: + if (const Expr *E = dyn_cast<Expr>(S)) { + // Don't bother evaluating beyond an expression-statement which couldn't + // be evaluated. + if (!EvaluateIgnoredValue(Info, E)) + return ESR_Failed; + return ESR_Succeeded; + } + + Info.Diag(S->getLocStart()); return ESR_Failed; case Stmt::NullStmtClass: - case Stmt::DeclStmtClass: return ESR_Succeeded; + case Stmt::DeclStmtClass: { + const DeclStmt *DS = cast<DeclStmt>(S); + for (DeclStmt::const_decl_iterator DclIt = DS->decl_begin(), + DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) + if (!EvaluateDecl(Info, *DclIt) && !Info.keepEvaluatingAfterFailure()) + return ESR_Failed; + return ESR_Succeeded; + } + case Stmt::ReturnStmtClass: { const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue(); - if (!Evaluate(Result, Info, RetExpr)) + if (RetExpr && !Evaluate(Result, Info, RetExpr)) return ESR_Failed; return ESR_Returned; } @@ -2072,6 +2564,123 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, } return ESR_Succeeded; } + + case Stmt::IfStmtClass: { + const IfStmt *IS = cast<IfStmt>(S); + + // Evaluate the condition, as either a var decl or as an expression. + bool Cond; + if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond)) + return ESR_Failed; + + if (const Stmt *SubStmt = Cond ? IS->getThen() : IS->getElse()) { + EvalStmtResult ESR = EvaluateStmt(Result, Info, SubStmt); + if (ESR != ESR_Succeeded) + return ESR; + } + return ESR_Succeeded; + } + + case Stmt::WhileStmtClass: { + const WhileStmt *WS = cast<WhileStmt>(S); + while (true) { + bool Continue; + if (!EvaluateCond(Info, WS->getConditionVariable(), WS->getCond(), + Continue)) + return ESR_Failed; + if (!Continue) + break; + + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, WS->getBody()); + if (ESR != ESR_Continue) + return ESR; + } + return ESR_Succeeded; + } + + case Stmt::DoStmtClass: { + const DoStmt *DS = cast<DoStmt>(S); + bool Continue; + do { + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody()); + if (ESR != ESR_Continue) + return ESR; + + if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info)) + return ESR_Failed; + } while (Continue); + return ESR_Succeeded; + } + + case Stmt::ForStmtClass: { + const ForStmt *FS = cast<ForStmt>(S); + if (FS->getInit()) { + EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit()); + if (ESR != ESR_Succeeded) + return ESR; + } + while (true) { + bool Continue = true; + if (FS->getCond() && !EvaluateCond(Info, FS->getConditionVariable(), + FS->getCond(), Continue)) + return ESR_Failed; + if (!Continue) + break; + + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody()); + if (ESR != ESR_Continue) + return ESR; + + if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc())) + return ESR_Failed; + } + return ESR_Succeeded; + } + + case Stmt::CXXForRangeStmtClass: { + const CXXForRangeStmt *FS = cast<CXXForRangeStmt>(S); + + // Initialize the __range variable. + EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getRangeStmt()); + if (ESR != ESR_Succeeded) + return ESR; + + // Create the __begin and __end iterators. + ESR = EvaluateStmt(Result, Info, FS->getBeginEndStmt()); + if (ESR != ESR_Succeeded) + return ESR; + + while (true) { + // Condition: __begin != __end. + bool Continue = true; + if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info)) + return ESR_Failed; + if (!Continue) + break; + + // User's variable declaration, initialized by *__begin. + ESR = EvaluateStmt(Result, Info, FS->getLoopVarStmt()); + if (ESR != ESR_Succeeded) + return ESR; + + // Loop body. + ESR = EvaluateLoopBody(Result, Info, FS->getBody()); + if (ESR != ESR_Continue) + return ESR; + + // Increment: ++__begin + if (!EvaluateIgnoredValue(Info, FS->getInc())) + return ESR_Failed; + } + + return ESR_Succeeded; + } + + case Stmt::ContinueStmtClass: + return ESR_Continue; + + case Stmt::BreakStmtClass: + return ESR_Break; } } @@ -2165,7 +2774,13 @@ static bool HandleFunctionCall(SourceLocation CallLoc, return false; CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data()); - return EvaluateStmt(Result, Info, Body) == ESR_Returned; + EvalStmtResult ESR = EvaluateStmt(Result, Info, Body); + if (ESR == ESR_Succeeded) { + if (Callee->getResultType()->isVoidType()) + return true; + Info.Diag(Callee->getLocEnd(), diag::note_constexpr_no_return); + } + return ESR == ESR_Returned; } /// Evaluate a constructor call. @@ -2191,7 +2806,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, // If it's a delegating constructor, just delegate. if (Definition->isDelegatingConstructor()) { CXXConstructorDecl::init_const_iterator I = Definition->init_begin(); - return EvaluateInPlace(Result, Info, This, (*I)->getInit()); + if (!EvaluateInPlace(Result, Info, This, (*I)->getInit())) + return false; + return EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; } // For a trivial copy or move constructor, perform an APValue copy. This is @@ -2202,7 +2819,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, (Definition->isMoveConstructor() && Definition->isTrivial()))) { LValue RHS; RHS.setFrom(Info.Ctx, ArgValues[0]); - return HandleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), + return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), RHS, Result); } @@ -2291,7 +2908,8 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, } } - return Success; + return Success && + EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; } //===----------------------------------------------------------------------===// @@ -2397,6 +3015,8 @@ public: { return StmtVisitorTy::Visit(E->getReplacement()); } RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { return StmtVisitorTy::Visit(E->getExpr()); } + RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) + { return StmtVisitorTy::Visit(E->getExpr()); } // We cannot create any objects for which cleanups are required, so there is // nothing to do here; all cleanups must come from unevaluated subexpressions. RetTy VisitExprWithCleanups(const ExprWithCleanups *E) @@ -2426,7 +3046,7 @@ public: if (!HandleMemberPointerAccess(Info, E, Obj)) return false; APValue Result; - if (!HandleLValueToRValueConversion(Info, E, E->getType(), Obj, Result)) + if (!handleLValueToRValueConversion(Info, E, E->getType(), Obj, Result)) return false; return DerivedSuccess(Result, E); } @@ -2606,11 +3226,13 @@ public: assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); + CompleteObject Obj(&Val, BaseTy); SubobjectDesignator Designator(BaseTy); Designator.addDeclUnchecked(FD); - return ExtractSubobject(Info, E, Val, BaseTy, Designator, E->getType()) && - DerivedSuccess(Val, E); + APValue Result; + return extractSubobject(Info, E, Obj, Designator, Result) && + DerivedSuccess(Result, E); } RetTy VisitCastExpr(const CastExpr *E) { @@ -2630,7 +3252,7 @@ public: return false; APValue RVal; // Note, we use the subexpression's type in order to retain cv-qualifiers. - if (!HandleLValueToRValueConversion(Info, E, E->getSubExpr()->getType(), + if (!handleLValueToRValueConversion(Info, E, E->getSubExpr()->getType(), LVal, RVal)) return false; return DerivedSuccess(RVal, E); @@ -2640,11 +3262,29 @@ public: return Error(E); } + RetTy VisitUnaryPostInc(const UnaryOperator *UO) { + return VisitUnaryPostIncDec(UO); + } + RetTy VisitUnaryPostDec(const UnaryOperator *UO) { + return VisitUnaryPostIncDec(UO); + } + RetTy VisitUnaryPostIncDec(const UnaryOperator *UO) { + if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + return Error(UO); + + LValue LVal; + if (!EvaluateLValue(UO->getSubExpr(), LVal, Info)) + return false; + APValue RVal; + if (!handleIncDec(this->Info, UO, LVal, UO->getSubExpr()->getType(), + UO->isIncrementOp(), &RVal)) + return false; + return DerivedSuccess(RVal, UO); + } + /// Visit a value which is evaluated, but whose value is ignored. void VisitIgnoredValue(const Expr *E) { - APValue Scratch; - if (!Evaluate(Scratch, Info, E)) - Info.EvalStatus.HasSideEffects = true; + EvaluateIgnoredValue(Info, E); } }; @@ -2709,7 +3349,7 @@ public: if (MD->getType()->isReferenceType()) { APValue RefValue; - if (!HandleLValueToRValueConversion(this->Info, E, MD->getType(), Result, + if (!handleLValueToRValueConversion(this->Info, E, MD->getType(), Result, RefValue)) return false; return Success(RefValue, E); @@ -2792,6 +3432,7 @@ public: LValueExprEvaluatorBaseTy(Info, Result) {} bool VisitVarDecl(const Expr *E, const VarDecl *VD); + bool VisitUnaryPreIncDec(const UnaryOperator *UO); bool VisitDeclRefExpr(const DeclRefExpr *E); bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); } @@ -2806,6 +3447,14 @@ public: bool VisitUnaryDeref(const UnaryOperator *E); bool VisitUnaryReal(const UnaryOperator *E); bool VisitUnaryImag(const UnaryOperator *E); + bool VisitUnaryPreInc(const UnaryOperator *UO) { + return VisitUnaryPreIncDec(UO); + } + bool VisitUnaryPreDec(const UnaryOperator *UO) { + return VisitUnaryPreIncDec(UO); + } + bool VisitBinAssign(const BinaryOperator *BO); + bool VisitCompoundAssignOperator(const CompoundAssignOperator *CAO); bool VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { @@ -2829,14 +3478,12 @@ public: } // end anonymous namespace /// Evaluate an expression as an lvalue. This can be legitimately called on -/// expressions which are not glvalues, in a few cases: -/// * function designators in C, -/// * "extern void" objects, -/// * temporaries, if building with -Wno-address-of-temporary. -static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) { - assert((E->isGLValue() || E->getType()->isFunctionType() || - E->getType()->isVoidType() || isa<CXXTemporaryObjectExpr>(E)) && - "can't evaluate expression as an lvalue"); +/// expressions which are not glvalues, in two cases: +/// * function designators in C, and +/// * "extern void" objects +static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info) { + assert(E->isGLValue() || E->getType()->isFunctionType() || + E->getType()->isVoidType()); return LValueExprEvaluator(Info, Result).Visit(E); } @@ -2849,41 +3496,32 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { } bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { + CallStackFrame *Frame = 0; + if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1) + Frame = Info.CurrentCall; + if (!VD->getType()->isReferenceType()) { - if (isa<ParmVarDecl>(VD)) { - Result.set(VD, Info.CurrentCall->Index); + if (Frame) { + Result.set(VD, Frame->Index); return true; } return Success(VD); } - APValue V; - if (!EvaluateVarDeclInit(Info, E, VD, Info.CurrentCall, V)) + APValue *V; + if (!evaluateVarDeclInit(Info, E, VD, Frame, V)) return false; - return Success(V, E); + return Success(*V, E); } bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E) { - if (E->GetTemporaryExpr()->isRValue()) { - if (E->getType()->isRecordType()) - return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info); + if (E->getType()->isRecordType()) + return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info); - Result.set(E, Info.CurrentCall->Index); - return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, - Result, E->GetTemporaryExpr()); - } - - // Materialization of an lvalue temporary occurs when we need to force a copy - // (for instance, if it's a bitfield). - // FIXME: The AST should contain an lvalue-to-rvalue node for such cases. - if (!Visit(E->GetTemporaryExpr())) - return false; - if (!HandleLValueToRValueConversion(Info, E, E->getType(), Result, - Info.CurrentCall->Temporaries[E])) - return false; Result.set(E, Info.CurrentCall->Index); - return true; + return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, + Result, E->GetTemporaryExpr()); } bool @@ -2906,7 +3544,7 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { return Success(E); -} +} bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { // Handle static data members. @@ -2967,6 +3605,64 @@ bool LValueExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { return true; } +bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) { + if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + return Error(UO); + + if (!this->Visit(UO->getSubExpr())) + return false; + + return handleIncDec( + this->Info, UO, Result, UO->getSubExpr()->getType(), + UO->isIncrementOp(), 0); +} + +bool LValueExprEvaluator::VisitCompoundAssignOperator( + const CompoundAssignOperator *CAO) { + if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + return Error(CAO); + + APValue RHS; + + // The overall lvalue result is the result of evaluating the LHS. + if (!this->Visit(CAO->getLHS())) { + if (Info.keepEvaluatingAfterFailure()) + Evaluate(RHS, this->Info, CAO->getRHS()); + return false; + } + + if (!Evaluate(RHS, this->Info, CAO->getRHS())) + return false; + + // FIXME: + //return handleCompoundAssignment( + // this->Info, CAO, + // Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(), + // RHS, CAO->getRHS()->getType(), + // CAO->getOpForCompoundAssignment(CAO->getOpcode()), + // CAO->getComputationResultType()); + return Error(CAO); +} + +bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { + if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + return Error(E); + + APValue NewVal; + + if (!this->Visit(E->getLHS())) { + if (Info.keepEvaluatingAfterFailure()) + Evaluate(NewVal, this->Info, E->getRHS()); + return false; + } + + if (!Evaluate(NewVal, this->Info, E->getRHS())) + return false; + + return handleAssignment(this->Info, E, Result, E->getLHS()->getType(), + NewVal); +} + //===----------------------------------------------------------------------===// // Pointer Evaluation //===----------------------------------------------------------------------===// @@ -3411,12 +4107,20 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // If the initializer list for a union does not contain any elements, the // first element of the union is value-initialized. + // FIXME: The element should be initialized from an initializer list. + // Is this difference ever observable for initializer lists which + // we don't build? ImplicitValueInitExpr VIE(Field->getType()); const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE; LValue Subobject = This; if (!HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout)) return false; + + // Temporarily override This, in case there's a CXXDefaultInitExpr in here. + ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, + isa<CXXDefaultInitExpr>(InitExpr)); + return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr); } @@ -3446,10 +4150,14 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // Perform an implicit value-initialization for members beyond the end of // the initializer list. ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType()); + const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE; - if (!EvaluateInPlace( - Result.getStructField(Field->getFieldIndex()), - Info, Subobject, HaveInit ? E->getInit(ElementNo++) : &VIE)) { + // Temporarily override This, in case there's a CXXDefaultInitExpr in here. + ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, + isa<CXXDefaultInitExpr>(Init)); + + if (!EvaluateInPlace(Result.getStructField(Field->getFieldIndex()), Info, + Subobject, Init)) { if (!Info.keepEvaluatingAfterFailure()) return false; Success = false; @@ -3777,6 +4485,9 @@ namespace { bool VisitInitListExpr(const InitListExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E); + bool VisitCXXConstructExpr(const CXXConstructExpr *E, + const LValue &Subobject, + APValue *Value, QualType Type); }; } // end anonymous namespace @@ -3810,8 +4521,16 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { if (Result.isArray() && Result.hasArrayFiller()) Filler = Result.getArrayFiller(); - Result = APValue(APValue::UninitArray(), E->getNumInits(), - CAT->getSize().getZExtValue()); + unsigned NumEltsToInit = E->getNumInits(); + unsigned NumElts = CAT->getSize().getZExtValue(); + const Expr *FillerExpr = E->hasArrayFiller() ? E->getArrayFiller() : 0; + + // If the initializer might depend on the array index, run it for each + // array element. For now, just whitelist non-class value-initialization. + if (NumEltsToInit != NumElts && !isa<ImplicitValueInitExpr>(FillerExpr)) + NumEltsToInit = NumElts; + + Result = APValue(APValue::UninitArray(), NumEltsToInit, NumElts); // If the array was previously zero-initialized, preserve the // zero-initialized values. @@ -3824,12 +4543,12 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { LValue Subobject = This; Subobject.addArray(Info, E, CAT); - unsigned Index = 0; - for (InitListExpr::const_iterator I = E->begin(), End = E->end(); - I != End; ++I, ++Index) { + for (unsigned Index = 0; Index != NumEltsToInit; ++Index) { + const Expr *Init = + Index < E->getNumInits() ? E->getInit(Index) : FillerExpr; if (!EvaluateInPlace(Result.getArrayInitializedElt(Index), - Info, Subobject, cast<Expr>(*I)) || - !HandleLValueArrayAdjustment(Info, cast<Expr>(*I), Subobject, + Info, Subobject, Init) || + !HandleLValueArrayAdjustment(Info, Init, Subobject, CAT->getElementType(), 1)) { if (!Info.keepEvaluatingAfterFailure()) return false; @@ -3837,39 +4556,54 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { } } - if (!Result.hasArrayFiller()) return Success; - assert(E->hasArrayFiller() && "no array filler for incomplete init list"); - // FIXME: The Subobject here isn't necessarily right. This rarely matters, - // but sometimes does: - // struct S { constexpr S() : p(&p) {} void *p; }; - // S s[10] = {}; - return EvaluateInPlace(Result.getArrayFiller(), Info, - Subobject, E->getArrayFiller()) && Success; + if (!Result.hasArrayFiller()) + return Success; + + // If we get here, we have a trivial filler, which we can just evaluate + // once and splat over the rest of the array elements. + assert(FillerExpr && "no array filler for incomplete init list"); + return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, + FillerExpr) && Success; } bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { - // FIXME: The Subobject here isn't necessarily right. This rarely matters, - // but sometimes does: - // struct S { constexpr S() : p(&p) {} void *p; }; - // S s[10]; - LValue Subobject = This; + return VisitCXXConstructExpr(E, This, &Result, E->getType()); +} - APValue *Value = &Result; - bool HadZeroInit = true; - QualType ElemTy = E->getType(); - while (const ConstantArrayType *CAT = - Info.Ctx.getAsConstantArrayType(ElemTy)) { - Subobject.addArray(Info, E, CAT); - HadZeroInit &= !Value->isUninit(); - if (!HadZeroInit) - *Value = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue()); - if (!Value->hasArrayFiller()) - return true; - Value = &Value->getArrayFiller(); - ElemTy = CAT->getElementType(); +bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, + const LValue &Subobject, + APValue *Value, + QualType Type) { + bool HadZeroInit = !Value->isUninit(); + + if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) { + unsigned N = CAT->getSize().getZExtValue(); + + // Preserve the array filler if we had prior zero-initialization. + APValue Filler = + HadZeroInit && Value->hasArrayFiller() ? Value->getArrayFiller() + : APValue(); + + *Value = APValue(APValue::UninitArray(), N, N); + + if (HadZeroInit) + for (unsigned I = 0; I != N; ++I) + Value->getArrayInitializedElt(I) = Filler; + + // Initialize the elements. + LValue ArrayElt = Subobject; + ArrayElt.addArray(Info, E, CAT); + for (unsigned I = 0; I != N; ++I) + if (!VisitCXXConstructExpr(E, ArrayElt, &Value->getArrayInitializedElt(I), + CAT->getElementType()) || + !HandleLValueArrayAdjustment(Info, E, ArrayElt, + CAT->getElementType(), 1)) + return false; + + return true; } - if (!ElemTy->isRecordType()) + if (!Type->isRecordType()) return Error(E); const CXXConstructorDecl *FD = E->getConstructor(); @@ -3880,7 +4614,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { return true; if (ZeroInit) { - ImplicitValueInitExpr VIE(ElemTy); + ImplicitValueInitExpr VIE(Type); return EvaluateInPlace(*Value, Info, Subobject, &VIE); } @@ -3901,7 +4635,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { return false; if (ZeroInit && !HadZeroInit) { - ImplicitValueInitExpr VIE(ElemTy); + ImplicitValueInitExpr VIE(Type); if (!EvaluateInPlace(*Value, Info, Subobject, &VIE)) return false; } @@ -5182,6 +5916,10 @@ CharUnits IntExprEvaluator::GetAlignOfType(QualType T) { CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) { E = E->IgnoreParens(); + // The kinds of expressions that we have special-case logic here for + // should be kept up to date with the special checks for those + // expressions in Sema. + // alignof decl is always accepted, even if it doesn't make sense: we default // to 1 in those cases. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) @@ -6267,7 +7005,7 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) { if (E->isGLValue()) { LValue LV; LV.setFrom(Info.Ctx, Result); - if (!HandleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) + if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) return false; } @@ -6501,6 +7239,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXDynamicCastExprClass: case Expr::CXXTypeidExprClass: case Expr::CXXUuidofExprClass: + case Expr::MSPropertyRefExprClass: case Expr::CXXNullPtrLiteralExprClass: case Expr::UserDefinedLiteralClass: case Expr::CXXThisExprClass: @@ -6819,6 +7558,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } case Expr::CXXDefaultArgExprClass: return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx); + case Expr::CXXDefaultInitExprClass: + return CheckICE(cast<CXXDefaultInitExpr>(E)->getExpr(), Ctx); case Expr::ChooseExprClass: { return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx); } diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp index 7973177ad2..894eb3bff5 100644 --- a/lib/AST/ItaniumCXXABI.cpp +++ b/lib/AST/ItaniumCXXABI.cpp @@ -33,10 +33,15 @@ protected: public: ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { } - unsigned getMemberPointerSize(const MemberPointerType *MPT) const { - QualType Pointee = MPT->getPointeeType(); - if (Pointee->isFunctionType()) return 2; - return 1; + std::pair<uint64_t, unsigned> + getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const { + const TargetInfo &Target = Context.getTargetInfo(); + TargetInfo::IntType PtrDiff = Target.getPtrDiffType(0); + uint64_t Width = Target.getTypeWidth(PtrDiff); + unsigned Align = Target.getTypeAlign(PtrDiff); + if (MPT->getPointeeType()->isFunctionType()) + Width = 2 * Width; + return std::make_pair(Width, Align); } CallingConv getDefaultMethodCallConv(bool isVariadic) const { diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 21c499317f..5ad8021fac 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -141,6 +141,8 @@ public: raw_ostream &); void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &); + void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &); + void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &); void mangleInitDiscriminator() { Discriminator = 0; @@ -1095,6 +1097,15 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, mangleSourceName(FD->getIdentifier()); break; } + + // Class extensions have no name as a category, and it's possible + // for them to be the semantic parent of certain declarations + // (primarily, tag decls defined within declarations). Such + // declarations will always have internal linkage, so the name + // doesn't really matter, but we shouldn't crash on them. For + // safety, just handle all ObjC containers here. + if (isa<ObjCContainerDecl>(ND)) + break; // We must have an anonymous struct. const TagDecl *TD = cast<TagDecl>(ND); @@ -2264,7 +2275,7 @@ void CXXNameMangler::mangleType(const AutoType *T) { QualType D = T->getDeducedType(); // <builtin-type> ::= Da # dependent auto if (D.isNull()) - Out << "Da"; + Out << (T->isDecltypeAuto() ? "Dc" : "Da"); else mangleType(D); } @@ -2385,6 +2396,7 @@ recurse: case Expr::ImplicitValueInitExprClass: case Expr::ParenListExprClass: case Expr::LambdaExprClass: + case Expr::MSPropertyRefExprClass: llvm_unreachable("unexpected statement kind"); // FIXME: invent manglings for all these. @@ -2461,6 +2473,10 @@ recurse: mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity); break; + case Expr::CXXDefaultInitExprClass: + mangleExpression(cast<CXXDefaultInitExpr>(E)->getExpr(), Arity); + break; + case Expr::SubstNonTypeTemplateParmExprClass: mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Arity); @@ -3521,6 +3537,22 @@ void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, Mangler.mangleName(D); } +void ItaniumMangleContext::mangleItaniumThreadLocalInit(const VarDecl *D, + raw_ostream &Out) { + // <special-name> ::= TH <object name> + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTH"; + Mangler.mangleName(D); +} + +void ItaniumMangleContext::mangleItaniumThreadLocalWrapper(const VarDecl *D, + raw_ostream &Out) { + // <special-name> ::= TW <object name> + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTW"; + Mangler.mangleName(D); +} + void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D, raw_ostream &Out) { // We match the GCC mangling here. diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp index 51308ea0c0..fd932f7330 100644 --- a/lib/AST/MicrosoftCXXABI.cpp +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "CXXABI.h" +#include "clang/AST/Attr.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/RecordLayout.h" @@ -27,13 +28,14 @@ class MicrosoftCXXABI : public CXXABI { public: MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { } - unsigned getMemberPointerSize(const MemberPointerType *MPT) const; + std::pair<uint64_t, unsigned> + getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const; CallingConv getDefaultMethodCallConv(bool isVariadic) const { - if (!isVariadic && Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) + if (!isVariadic && + Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) return CC_X86ThisCall; - else - return CC_C; + return CC_C; } bool isNearlyEmpty(const CXXRecordDecl *RD) const { @@ -52,17 +54,125 @@ public: }; } -unsigned MicrosoftCXXABI::getMemberPointerSize(const MemberPointerType *MPT) const { - QualType Pointee = MPT->getPointeeType(); - CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); - if (RD->getNumVBases() > 0) { - if (Pointee->isFunctionType()) - return 3; - else - return 2; - } else if (RD->getNumBases() > 1 && Pointee->isFunctionType()) - return 2; - return 1; +// getNumBases() seems to only give us the number of direct bases, and not the +// total. This function tells us if we inherit from anybody that uses MI, or if +// we have a non-primary base class, which uses the multiple inheritance model. +static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) { + while (RD->getNumBases() > 0) { + if (RD->getNumBases() > 1) + return true; + assert(RD->getNumBases() == 1); + const CXXRecordDecl *Base = + RD->bases_begin()->getType()->getAsCXXRecordDecl(); + if (RD->isPolymorphic() && !Base->isPolymorphic()) + return true; + RD = Base; + } + return false; +} + +static MSInheritanceModel MSInheritanceAttrToModel(attr::Kind Kind) { + switch (Kind) { + default: llvm_unreachable("expected MS inheritance attribute"); + case attr::SingleInheritance: return MSIM_Single; + case attr::MultipleInheritance: return MSIM_Multiple; + case attr::VirtualInheritance: return MSIM_Virtual; + case attr::UnspecifiedInheritance: return MSIM_Unspecified; + } +} + +MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const { + if (Attr *IA = this->getAttr<MSInheritanceAttr>()) + return MSInheritanceAttrToModel(IA->getKind()); + // If there was no explicit attribute, the record must be defined already, and + // we can figure out the inheritance model from its other properties. + if (this->getNumVBases() > 0) + return MSIM_Virtual; + if (usesMultipleInheritanceModel(this)) + return this->isPolymorphic() ? MSIM_MultiplePolymorphic : MSIM_Multiple; + return this->isPolymorphic() ? MSIM_SinglePolymorphic : MSIM_Single; +} + +// Returns the number of pointer and integer slots used to represent a member +// pointer in the MS C++ ABI. +// +// Member function pointers have the following general form; however, fields +// are dropped as permitted (under the MSVC interpretation) by the inheritance +// model of the actual class. +// +// struct { +// // A pointer to the member function to call. If the member function is +// // virtual, this will be a thunk that forwards to the appropriate vftable +// // slot. +// void *FunctionPointerOrVirtualThunk; +// +// // An offset to add to the address of the vbtable pointer after (possibly) +// // selecting the virtual base but before resolving and calling the function. +// // Only needed if the class has any virtual bases or bases at a non-zero +// // offset. +// int NonVirtualBaseAdjustment; +// +// // An offset within the vb-table that selects the virtual base containing +// // the member. Loading from this offset produces a new offset that is +// // added to the address of the vb-table pointer to produce the base. +// int VirtualBaseAdjustmentOffset; +// +// // The offset of the vb-table pointer within the object. Only needed for +// // incomplete types. +// int VBPtrOffset; +// }; +static std::pair<unsigned, unsigned> +getMSMemberPointerSlots(const MemberPointerType *MPT) { + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + unsigned Ptrs; + unsigned Ints = 0; + if (MPT->isMemberFunctionPointer()) { + // Member function pointers are a struct of a function pointer followed by a + // variable number of ints depending on the inheritance model used. The + // function pointer is a real function if it is non-virtual and a vftable + // slot thunk if it is virtual. The ints select the object base passed for + // the 'this' pointer. + Ptrs = 1; // First slot is always a function pointer. + switch (Inheritance) { + case MSIM_Unspecified: ++Ints; // VBTableOffset + case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset + case MSIM_MultiplePolymorphic: + case MSIM_Multiple: ++Ints; // NonVirtualBaseAdjustment + case MSIM_SinglePolymorphic: + case MSIM_Single: break; // Nothing + } + } else { + // Data pointers are an aggregate of ints. The first int is an offset + // followed by vbtable-related offsets. + Ptrs = 0; + switch (Inheritance) { + case MSIM_Unspecified: ++Ints; // VBTableOffset + case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset + case MSIM_MultiplePolymorphic: + case MSIM_Multiple: // Nothing + case MSIM_SinglePolymorphic: + case MSIM_Single: ++Ints; // Field offset + } + } + return std::make_pair(Ptrs, Ints); +} + +std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign( + const MemberPointerType *MPT) const { + const TargetInfo &Target = Context.getTargetInfo(); + assert(Target.getTriple().getArch() == llvm::Triple::x86 || + Target.getTriple().getArch() == llvm::Triple::x86_64); + unsigned Ptrs, Ints; + llvm::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT); + // The nominal struct is laid out with pointers followed by ints and aligned + // to a pointer width if any are present and an int width otherwise. + unsigned PtrSize = Target.getPointerWidth(0); + unsigned IntSize = Target.getIntWidth(); + uint64_t Width = Ptrs * PtrSize + Ints * IntSize; + unsigned Align = Ptrs > 0 ? Target.getPointerAlign(0) : Target.getIntAlign(); + Width = llvm::RoundUpToAlignment(Width, Align); + return std::make_pair(Width, Align); } CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) { diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 8c31e57578..1785063d7b 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -59,6 +59,8 @@ class MicrosoftCXXNameMangler { ASTContext &getASTContext() const { return Context.getASTContext(); } public: + enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result }; + MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_) : Context(C), Out(Out_), Structor(0), StructorType(-1), @@ -78,7 +80,8 @@ public: void mangleVariableEncoding(const VarDecl *VD); void mangleNumber(int64_t Number); void mangleNumber(const llvm::APSInt &Value); - void mangleType(QualType T, SourceRange Range, bool MangleQualifiers = true); + void mangleType(QualType T, SourceRange Range, + QualifierMangleMode QMM = QMM_Mangle); private: void disableBackReferences() { UseNameBackReferences = false; } @@ -95,7 +98,7 @@ private: void mangleUnscopedTemplateName(const TemplateDecl *ND); void mangleTemplateInstantiationName(const TemplateDecl *TD, - const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs); + const TemplateArgumentList &TemplateArgs); void mangleObjCMethodName(const ObjCMethodDecl *MD); void mangleLocalName(const FunctionDecl *FD); @@ -112,18 +115,18 @@ private: #undef TYPE void mangleType(const TagType*); - void mangleType(const FunctionType *T, const FunctionDecl *D, - bool IsStructor, bool IsInstMethod); - void mangleType(const ArrayType *T, bool IsGlobal); - void mangleExtraDimensions(QualType T); + void mangleFunctionType(const FunctionType *T, const FunctionDecl *D, + bool IsStructor, bool IsInstMethod); + void mangleDecayedArrayType(const ArrayType *T, bool IsGlobal); + void mangleArrayType(const ArrayType *T, Qualifiers Quals); void mangleFunctionClass(const FunctionDecl *FD); void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false); void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean); void mangleExpression(const Expr *E); void mangleThrowSpecification(const FunctionProtoType *T); - void mangleTemplateArgs( - const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs); + void mangleTemplateArgs(const TemplateDecl *TD, + const TemplateArgumentList &TemplateArgs); }; @@ -264,7 +267,7 @@ void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { // First, the function class. mangleFunctionClass(FD); - mangleType(FT, FD, InStructor, InInstMethod); + mangleFunctionType(FT, FD, InStructor, InInstMethod); } void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { @@ -297,14 +300,17 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc(); QualType Ty = TL.getType(); if (Ty->isPointerType() || Ty->isReferenceType()) { - mangleType(Ty, TL.getSourceRange()); + mangleType(Ty, TL.getSourceRange(), QMM_Drop); mangleQualifiers(Ty->getPointeeType().getQualifiers(), false); } else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) { // Global arrays are funny, too. - mangleType(AT, true); - mangleQualifiers(Ty.getQualifiers(), false); + mangleDecayedArrayType(AT, true); + if (AT->getElementType()->isArrayType()) + Out << 'A'; + else + mangleQualifiers(Ty.getQualifiers(), false); } else { - mangleType(Ty.getLocalUnqualifiedType(), TL.getSourceRange()); + mangleType(Ty, TL.getSourceRange(), QMM_Drop); mangleQualifiers(Ty.getLocalQualifiers(), false); } } @@ -367,47 +373,19 @@ void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) { } static const TemplateDecl * -isTemplate(const NamedDecl *ND, - SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { +isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { // Check if we have a function template. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){ if (const TemplateDecl *TD = FD->getPrimaryTemplate()) { - if (FD->getTemplateSpecializationArgsAsWritten()) { - const ASTTemplateArgumentListInfo *ArgList = - FD->getTemplateSpecializationArgsAsWritten(); - TemplateArgs.append(ArgList->getTemplateArgs(), - ArgList->getTemplateArgs() + - ArgList->NumTemplateArgs); - } else { - const TemplateArgumentList *ArgList = - FD->getTemplateSpecializationArgs(); - TemplateArgumentListInfo LI; - for (unsigned i = 0, e = ArgList->size(); i != e; ++i) - TemplateArgs.push_back(TemplateArgumentLoc(ArgList->get(i), - FD->getTypeSourceInfo())); - } + TemplateArgs = FD->getTemplateSpecializationArgs(); return TD; } } // Check if we have a class template. if (const ClassTemplateSpecializationDecl *Spec = - dyn_cast<ClassTemplateSpecializationDecl>(ND)) { - TypeSourceInfo *TSI = Spec->getTypeAsWritten(); - if (TSI) { - TemplateSpecializationTypeLoc TSTL = - TSI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>(); - TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc()); - for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i) - TemplateArgs.push_back(TSTL.getArgLoc(i)); - } else { - TemplateArgumentListInfo LI; - const TemplateArgumentList &ArgList = - Spec->getTemplateArgs(); - for (unsigned i = 0, e = ArgList.size(); i != e; ++i) - TemplateArgs.push_back(TemplateArgumentLoc(ArgList[i], - TemplateArgumentLocInfo())); - } + dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + TemplateArgs = &Spec->getTemplateArgs(); return Spec->getSpecializedTemplate(); } @@ -421,8 +399,9 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // ::= <ctor-dtor-name> // ::= <source-name> // ::= <template-name> - SmallVector<TemplateArgumentLoc, 2> TemplateArgs; + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { // We have a template. // Here comes the tricky thing: if we need to mangle something like @@ -452,7 +431,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, Found = NameBackReferences.find(BackReferenceKey); } if (!UseNameBackReferences || Found == NameBackReferences.end()) { - mangleTemplateInstantiationName(TD, TemplateArgs); + mangleTemplateInstantiationName(TD, *TemplateArgs); if (UseNameBackReferences && NameBackReferences.size() < 10) { size_t Size = NameBackReferences.size(); NameBackReferences[BackReferenceKey] = Size; @@ -786,7 +765,7 @@ void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) { void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( const TemplateDecl *TD, - const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { + const TemplateArgumentList &TemplateArgs) { // <template-name> ::= <unscoped-template-name> <template-args> // ::= <substitution> // Always start with the unqualified name. @@ -798,7 +777,7 @@ void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( TypeBackReferences.swap(OuterArgsContext); mangleUnscopedTemplateName(TD); - mangleTemplateArgs(TemplateArgs); + mangleTemplateArgs(TD, TemplateArgs); // Restore the previous back reference contexts. NameBackReferences.swap(OuterTemplateContext); @@ -842,18 +821,22 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) { } void -MicrosoftCXXNameMangler::mangleTemplateArgs( - const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { +MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD, + const TemplateArgumentList &TemplateArgs) { // <template-args> ::= {<type> | <integer-literal>}+ @ unsigned NumTemplateArgs = TemplateArgs.size(); for (unsigned i = 0; i < NumTemplateArgs; ++i) { - const TemplateArgumentLoc &TAL = TemplateArgs[i]; - const TemplateArgument &TA = TAL.getArgument(); + const TemplateArgument &TA = TemplateArgs[i]; switch (TA.getKind()) { case TemplateArgument::Null: llvm_unreachable("Can't mangle null template arguments!"); - case TemplateArgument::Type: - mangleType(TA.getAsType(), TAL.getSourceRange()); + case TemplateArgument::Type: { + QualType T = TA.getAsType(); + mangleType(T, SourceRange(), QMM_Escape); + break; + } + case TemplateArgument::Declaration: + mangle(cast<NamedDecl>(TA.getAsDecl()), "$1?"); break; case TemplateArgument::Integral: mangleIntegerLiteral(TA.getAsIntegral(), @@ -864,18 +847,18 @@ MicrosoftCXXNameMangler::mangleTemplateArgs( break; case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - case TemplateArgument::Declaration: case TemplateArgument::NullPtr: case TemplateArgument::Pack: { // Issue a diagnostic. DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this %select{ERROR|ERROR|pointer/reference|nullptr|" - "integral|template|template pack expansion|ERROR|parameter pack}0 " - "template argument yet"); - Diags.Report(TAL.getLocation(), DiagID) + "cannot mangle template argument %0 of kind %select{ERROR|ERROR|" + "pointer/reference|nullptr|integral|template|template pack expansion|" + "ERROR|parameter pack}1 yet"); + Diags.Report(TD->getLocation(), DiagID) + << i + 1 << TA.getKind() - << TAL.getSourceRange(); + << TD->getSourceRange(); } } } @@ -989,7 +972,14 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, if (Found == TypeBackReferences.end()) { size_t OutSizeBefore = Out.GetNumBytesInBuffer(); - mangleType(T, Range, false); + if (const ArrayType *AT = getASTContext().getAsArrayType(T)) { + mangleDecayedArrayType(AT, false); + } else if (const FunctionType *FT = T->getAs<FunctionType>()) { + Out << "P6"; + mangleFunctionType(FT, 0, false, false); + } else { + mangleType(T, Range, QMM_Drop); + } // See if it's worth creating a back reference. // Only types longer than 1 character are considered @@ -1005,28 +995,53 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, } void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, - bool MangleQualifiers) { + QualifierMangleMode QMM) { // Only operate on the canonical type! T = getASTContext().getCanonicalType(T); - Qualifiers Quals = T.getLocalQualifiers(); - // We have to mangle these now, while we still have enough information. - if (T->isAnyPointerType() || T->isMemberPointerType() || - T->isBlockPointerType()) { - manglePointerQualifiers(Quals); - } else if (Quals && MangleQualifiers) { - mangleQualifiers(Quals, false); + + if (const ArrayType *AT = dyn_cast<ArrayType>(T)) { + if (QMM == QMM_Mangle) + Out << 'A'; + else if (QMM == QMM_Escape || QMM == QMM_Result) + Out << "$$B"; + mangleArrayType(AT, Quals); + return; } - SplitQualType split = T.split(); - const Type *ty = split.Ty; + bool IsPointer = T->isAnyPointerType() || T->isMemberPointerType() || + T->isBlockPointerType(); - // If we're mangling a qualified array type, push the qualifiers to - // the element type. - if (split.Quals && isa<ArrayType>(T)) { - ty = Context.getASTContext().getAsArrayType(T); + switch (QMM) { + case QMM_Drop: + break; + case QMM_Mangle: + if (const FunctionType *FT = dyn_cast<FunctionType>(T)) { + Out << '6'; + mangleFunctionType(FT, 0, false, false); + return; + } + mangleQualifiers(Quals, false); + break; + case QMM_Escape: + if (!IsPointer && Quals) { + Out << "$$C"; + mangleQualifiers(Quals, false); + } + break; + case QMM_Result: + if ((!IsPointer && Quals) || isa<TagType>(T)) { + Out << '?'; + mangleQualifiers(Quals, false); + } + break; } + // We have to mangle these now, while we still have enough information. + if (IsPointer) + manglePointerQualifiers(Quals); + const Type *ty = T.getTypePtr(); + switch (ty->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) \ @@ -1136,17 +1151,17 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, // structor type. // FIXME: This may not be lambda-friendly. Out << "$$A6"; - mangleType(T, NULL, false, false); + mangleFunctionType(T, NULL, false, false); } void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, SourceRange) { llvm_unreachable("Can't mangle K&R function prototypes"); } -void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, - const FunctionDecl *D, - bool IsStructor, - bool IsInstMethod) { +void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, + const FunctionDecl *D, + bool IsStructor, + bool IsInstMethod) { // <function-type> ::= <this-cvr-qualifiers> <calling-convention> // <return-type> <argument-list> <throw-spec> const FunctionProtoType *Proto = cast<FunctionProtoType>(T); @@ -1172,21 +1187,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, } Out << '@'; } else { - QualType Result = Proto->getResultType(); - const Type* RT = Result.getTypePtr(); - if (!RT->isAnyPointerType() && !RT->isReferenceType()) { - if (Result.hasQualifiers() || !RT->isBuiltinType()) - Out << '?'; - if (!RT->isBuiltinType() && !Result.hasQualifiers()) { - // Lack of qualifiers for user types is mangled as 'A'. - Out << 'A'; - } - } - - // FIXME: Get the source range for the result type. Or, better yet, - // implement the unimplemented stuff so we don't need accurate source - // location info anymore :). - mangleType(Result, SourceRange()); + mangleType(Proto->getResultType(), SourceRange(), QMM_Result); } // <argument-list> ::= X # void @@ -1381,7 +1382,8 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) { // It's supposed to be the other way around, but for some strange reason, it // isn't. Today this behavior is retained for the sole purpose of backwards // compatibility. -void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { +void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T, + bool IsGlobal) { // This isn't a recursive mangling, so now we have to do it all in this // one call. if (IsGlobal) { @@ -1389,25 +1391,27 @@ void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { } else { Out << 'Q'; } - mangleExtraDimensions(T->getElementType()); + mangleType(T->getElementType(), SourceRange()); } void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, SourceRange) { - mangleType(cast<ArrayType>(T), false); + llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T, SourceRange) { - mangleType(cast<ArrayType>(T), false); + llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T, SourceRange) { - mangleType(cast<ArrayType>(T), false); + llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T, SourceRange) { - mangleType(cast<ArrayType>(T), false); + llvm_unreachable("Should have been special cased"); } -void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { +void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T, + Qualifiers Quals) { + QualType ElementTy(T, 0); SmallVector<llvm::APInt, 3> Dimensions; for (;;) { if (const ConstantArrayType *CAT = @@ -1433,20 +1437,20 @@ void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { Diags.Report(DSAT->getSizeExpr()->getExprLoc(), DiagID) << DSAT->getBracketsRange(); return; - } else if (ElementTy->isIncompleteArrayType()) continue; - else break; - } - mangleQualifiers(ElementTy.getQualifiers(), false); - // If there are any additional dimensions, mangle them now. - if (Dimensions.size() > 0) { - Out << 'Y'; - // <dimension-count> ::= <number> # number of extra dimensions - mangleNumber(Dimensions.size()); - for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) { - mangleNumber(Dimensions[Dim].getLimitedValue()); + } else if (const IncompleteArrayType *IAT = + getASTContext().getAsIncompleteArrayType(ElementTy)) { + Dimensions.push_back(llvm::APInt(32, 0)); + ElementTy = IAT->getElementType(); } + else break; } - mangleType(ElementTy.getLocalUnqualifiedType(), SourceRange()); + Out << 'Y'; + // <dimension-count> ::= <number> # number of extra dimensions + mangleNumber(Dimensions.size()); + for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) + mangleNumber(Dimensions[Dim].getLimitedValue()); + mangleType(getASTContext().getQualifiedType(ElementTy.getTypePtr(), Quals), + SourceRange(), QMM_Escape); } // <type> ::= <pointer-to-member-type> @@ -1458,11 +1462,11 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T, if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) { Out << '8'; mangleName(T->getClass()->castAs<RecordType>()->getDecl()); - mangleType(FPT, NULL, false, true); + mangleFunctionType(FPT, NULL, false, true); } else { mangleQualifiers(PointeeType.getQualifiers(), true); mangleName(T->getClass()->castAs<RecordType>()->getDecl()); - mangleType(PointeeType.getLocalUnqualifiedType(), Range); + mangleType(PointeeType, Range, QMM_Drop); } } @@ -1490,17 +1494,7 @@ void MicrosoftCXXNameMangler::mangleType( void MicrosoftCXXNameMangler::mangleType(const PointerType *T, SourceRange Range) { QualType PointeeTy = T->getPointeeType(); - if (PointeeTy->isArrayType()) { - // Pointers to arrays are mangled like arrays. - mangleExtraDimensions(PointeeTy); - } else if (const FunctionType *FT = PointeeTy->getAs<FunctionType>()) { - // Function pointers are special. - Out << '6'; - mangleType(FT, NULL, false, false); - } else { - mangleQualifiers(PointeeTy.getQualifiers(), false); - mangleType(PointeeTy, Range, false); - } + mangleType(PointeeTy, Range); } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, SourceRange Range) { @@ -1514,11 +1508,7 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, SourceRange Range) { Out << 'A'; - QualType PointeeTy = T->getPointeeType(); - if (!PointeeTy.hasQualifiers()) - // Lack of qualifiers is mangled as 'A'. - Out << 'A'; - mangleType(PointeeTy, Range); + mangleType(T->getPointeeType(), Range); } // <type> ::= <r-value-reference-type> @@ -1526,11 +1516,7 @@ void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T, SourceRange Range) { Out << "$$Q"; - QualType PointeeTy = T->getPointeeType(); - if (!PointeeTy.hasQualifiers()) - // Lack of qualifiers is mangled as 'A'. - Out << 'A'; - mangleType(PointeeTy, Range); + mangleType(T->getPointeeType(), Range); } void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, @@ -1544,12 +1530,38 @@ void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, void MicrosoftCXXNameMangler::mangleType(const VectorType *T, SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this vector type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; + const BuiltinType *ET = T->getElementType()->getAs<BuiltinType>(); + assert(ET && "vectors with non-builtin elements are unsupported"); + uint64_t Width = getASTContext().getTypeSize(T); + // Pattern match exactly the typedefs in our intrinsic headers. Anything that + // doesn't match the Intel types uses a custom mangling below. + bool IntelVector = true; + if (Width == 64 && ET->getKind() == BuiltinType::LongLong) { + Out << "T__m64"; + } else if (Width == 128 || Width == 256) { + if (ET->getKind() == BuiltinType::Float) + Out << "T__m" << Width; + else if (ET->getKind() == BuiltinType::LongLong) + Out << "T__m" << Width << 'i'; + else if (ET->getKind() == BuiltinType::Double) + Out << "U__m" << Width << 'd'; + else + IntelVector = false; + } else { + IntelVector = false; + } + + if (!IntelVector) { + // The MS ABI doesn't have a special mangling for vector types, so we define + // our own mangling to handle uses of __vector_size__ on user-specified + // types, and for extensions like __v4sf. + Out << "T__clang_vec" << T->getNumElements() << '_'; + mangleType(ET, Range); + } + + Out << "@@"; } + void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); @@ -1586,7 +1598,7 @@ void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, Out << "_E"; QualType pointee = T->getPointeeType(); - mangleType(pointee->castAs<FunctionProtoType>(), NULL, false, false); + mangleFunctionType(pointee->castAs<FunctionProtoType>(), NULL, false, false); } void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T, diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp index f2386a56fc..92b96dc8e5 100644 --- a/lib/AST/RawCommentList.cpp +++ b/lib/AST/RawCommentList.cpp @@ -21,8 +21,10 @@ using namespace clang; namespace { /// Get comment kind and bool describing if it is a trailing comment. -std::pair<RawComment::CommentKind, bool> getCommentKind(StringRef Comment) { - if (Comment.size() < 3 || Comment[0] != '/') +std::pair<RawComment::CommentKind, bool> getCommentKind(StringRef Comment, + bool ParseAllComments) { + const size_t MinCommentLength = ParseAllComments ? 2 : 3; + if ((Comment.size() < MinCommentLength) || Comment[0] != '/') return std::make_pair(RawComment::RCK_Invalid, false); RawComment::CommentKind K; @@ -63,9 +65,10 @@ bool mergedCommentIsTrailingComment(StringRef Comment) { } // unnamed namespace RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, - bool Merged) : + bool Merged, bool ParseAllComments) : Range(SR), RawTextValid(false), BriefTextValid(false), IsAttached(false), IsAlmostTrailingComment(false), + ParseAllComments(ParseAllComments), BeginLineValid(false), EndLineValid(false) { // Extract raw comment text, if possible. if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) { @@ -75,7 +78,7 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, if (!Merged) { // Guess comment kind. - std::pair<CommentKind, bool> K = getCommentKind(RawText); + std::pair<CommentKind, bool> K = getCommentKind(RawText, ParseAllComments); Kind = K.first; IsTrailingComment = K.second; @@ -143,7 +146,8 @@ const char *RawComment::extractBriefText(const ASTContext &Context) const { // a separate allocator for all temporary stuff. llvm::BumpPtrAllocator Allocator; - comments::Lexer L(Allocator, Context.getCommentCommandTraits(), + comments::Lexer L(Allocator, Context.getDiagnostics(), + Context.getCommentCommandTraits(), Range.getBegin(), RawText.begin(), RawText.end()); comments::BriefParser P(L, Context.getCommentCommandTraits()); @@ -164,7 +168,8 @@ comments::FullComment *RawComment::parse(const ASTContext &Context, // Make sure that RawText is valid. getRawText(Context.getSourceManager()); - comments::Lexer L(Context.getAllocator(), Context.getCommentCommandTraits(), + comments::Lexer L(Context.getAllocator(), Context.getDiagnostics(), + Context.getCommentCommandTraits(), getSourceRange().getBegin(), RawText.begin(), RawText.end()); comments::Sema S(Context.getAllocator(), Context.getSourceManager(), @@ -253,7 +258,8 @@ void RawCommentList::addComment(const RawComment &RC, if (C1EndLine + 1 == C2BeginLine || C1EndLine == C2BeginLine) { SourceRange MergedRange(C1.getSourceRange().getBegin(), C2.getSourceRange().getEnd()); - *Comments.back() = RawComment(SourceMgr, MergedRange, true); + *Comments.back() = RawComment(SourceMgr, MergedRange, true, + RC.isParseAllComments()); Merged = true; } } @@ -262,4 +268,3 @@ void RawCommentList::addComment(const RawComment &RC, OnlyWhitespaceSeen = true; } - diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 2ae5a1266c..5b29c073f9 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -673,19 +673,38 @@ GCCAsmStmt::GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc, bool issimple, bool isvolatile, ArrayRef<Token> asmtoks, unsigned numoutputs, - unsigned numinputs, ArrayRef<IdentifierInfo*> names, + unsigned numinputs, ArrayRef<StringRef> constraints, ArrayRef<Expr*> exprs, StringRef asmstr, ArrayRef<StringRef> clobbers, SourceLocation endloc) : AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, numinputs, clobbers.size()), LBraceLoc(lbraceloc), - EndLoc(endloc), AsmStr(asmstr.str()), NumAsmToks(asmtoks.size()) { + EndLoc(endloc), NumAsmToks(asmtoks.size()) { - unsigned NumExprs = NumOutputs + NumInputs; + initialize(C, asmstr, asmtoks, constraints, exprs, clobbers); +} - Names = new (C) IdentifierInfo*[NumExprs]; - for (unsigned i = 0, e = NumExprs; i != e; ++i) - Names[i] = names[i]; +static StringRef copyIntoContext(ASTContext &C, StringRef str) { + size_t size = str.size(); + char *buffer = new (C) char[size]; + memcpy(buffer, str.data(), size); + return StringRef(buffer, size); +} + +void MSAsmStmt::initialize(ASTContext &C, + StringRef asmstr, + ArrayRef<Token> asmtoks, + ArrayRef<StringRef> constraints, + ArrayRef<Expr*> exprs, + ArrayRef<StringRef> clobbers) { + assert(NumAsmToks == asmtoks.size()); + assert(NumClobbers == clobbers.size()); + + unsigned NumExprs = exprs.size(); + assert(NumExprs == NumOutputs + NumInputs); + assert(NumExprs == constraints.size()); + + AsmStr = copyIntoContext(C, asmstr); Exprs = new (C) Stmt*[NumExprs]; for (unsigned i = 0, e = NumExprs; i != e; ++i) @@ -697,19 +716,13 @@ MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc, Constraints = new (C) StringRef[NumExprs]; for (unsigned i = 0, e = NumExprs; i != e; ++i) { - size_t size = constraints[i].size(); - char *dest = new (C) char[size]; - std::strncpy(dest, constraints[i].data(), size); - Constraints[i] = StringRef(dest, size); + Constraints[i] = copyIntoContext(C, constraints[i]); } Clobbers = new (C) StringRef[NumClobbers]; for (unsigned i = 0, e = NumClobbers; i != e; ++i) { // FIXME: Avoid the allocation/copy if at all possible. - size_t size = clobbers[i].size(); - char *dest = new (C) char[size]; - std::strncpy(dest, clobbers[i].data(), size); - Clobbers[i] = StringRef(dest, size); + Clobbers[i] = copyIntoContext(C, clobbers[i]); } } @@ -1023,3 +1036,107 @@ SEHFinallyStmt* SEHFinallyStmt::Create(ASTContext &C, Stmt *Block) { return new(C)SEHFinallyStmt(Loc,Block); } + +CapturedStmt::Capture *CapturedStmt::getStoredCaptures() const { + unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1); + + // Offset of the first Capture object. + unsigned FirstCaptureOffset = + llvm::RoundUpToAlignment(Size, llvm::alignOf<Capture>()); + + return reinterpret_cast<Capture *>( + reinterpret_cast<char *>(const_cast<CapturedStmt *>(this)) + + FirstCaptureOffset); +} + +CapturedStmt::CapturedStmt(Stmt *S, CapturedRegionKind Kind, + ArrayRef<Capture> Captures, + ArrayRef<Expr *> CaptureInits, + CapturedDecl *CD, + RecordDecl *RD) + : Stmt(CapturedStmtClass), NumCaptures(Captures.size()), + CapDeclAndKind(CD, Kind), TheRecordDecl(RD) { + assert( S && "null captured statement"); + assert(CD && "null captured declaration for captured statement"); + assert(RD && "null record declaration for captured statement"); + + // Copy initialization expressions. + Stmt **Stored = getStoredStmts(); + for (unsigned I = 0, N = NumCaptures; I != N; ++I) + *Stored++ = CaptureInits[I]; + + // Copy the statement being captured. + *Stored = S; + + // Copy all Capture objects. + Capture *Buffer = getStoredCaptures(); + std::copy(Captures.begin(), Captures.end(), Buffer); +} + +CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures) + : Stmt(CapturedStmtClass, Empty), NumCaptures(NumCaptures), + CapDeclAndKind(0, CR_Default), TheRecordDecl(0) { + getStoredStmts()[NumCaptures] = 0; +} + +CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S, + CapturedRegionKind Kind, + ArrayRef<Capture> Captures, + ArrayRef<Expr *> CaptureInits, + CapturedDecl *CD, + RecordDecl *RD) { + // The layout is + // + // ----------------------------------------------------------- + // | CapturedStmt, Init, ..., Init, S, Capture, ..., Capture | + // ----------------^-------------------^---------------------- + // getStoredStmts() getStoredCaptures() + // + // where S is the statement being captured. + // + assert(CaptureInits.size() == Captures.size() && "wrong number of arguments"); + + unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (Captures.size() + 1); + if (!Captures.empty()) { + // Realign for the following Capture array. + Size = llvm::RoundUpToAlignment(Size, llvm::alignOf<Capture>()); + Size += sizeof(Capture) * Captures.size(); + } + + void *Mem = Context.Allocate(Size); + return new (Mem) CapturedStmt(S, Kind, Captures, CaptureInits, CD, RD); +} + +CapturedStmt *CapturedStmt::CreateDeserialized(ASTContext &Context, + unsigned NumCaptures) { + unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1); + if (NumCaptures > 0) { + // Realign for the following Capture array. + Size = llvm::RoundUpToAlignment(Size, llvm::alignOf<Capture>()); + Size += sizeof(Capture) * NumCaptures; + } + + void *Mem = Context.Allocate(Size); + return new (Mem) CapturedStmt(EmptyShell(), NumCaptures); +} + +Stmt::child_range CapturedStmt::children() { + // Children are captured field initilizers. + return child_range(getStoredStmts(), getStoredStmts() + NumCaptures); +} + +bool CapturedStmt::capturesVariable(const VarDecl *Var) const { + for (const_capture_iterator I = capture_begin(), + E = capture_end(); I != E; ++I) { + if (I->capturesThis()) + continue; + + // This does not handle variable redeclarations. This should be + // extended to capture variables with redeclarations, for example + // a thread-private variable in OpenMP. + if (I->getCapturedVar() == Var) + return true; + } + + return false; +} diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 23506b5e26..9203dc1584 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -445,11 +445,15 @@ void StmtPrinter::VisitMSAsmStmt(MSAsmStmt *Node) { Indent() << "__asm "; if (Node->hasBraces()) OS << "{\n"; - OS << *(Node->getAsmString()) << "\n"; + OS << Node->getAsmString() << "\n"; if (Node->hasBraces()) Indent() << "}\n"; } +void StmtPrinter::VisitCapturedStmt(CapturedStmt *Node) { + PrintStmt(Node->getCapturedDecl()->getBody()); +} + void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { Indent() << "@try"; if (CompoundStmt *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) { @@ -1109,24 +1113,25 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) { // AtomicExpr stores its subexpressions in a permuted order. PrintExpr(Node->getPtr()); - OS << ", "; if (Node->getOp() != AtomicExpr::AO__c11_atomic_load && Node->getOp() != AtomicExpr::AO__atomic_load_n) { - PrintExpr(Node->getVal1()); OS << ", "; + PrintExpr(Node->getVal1()); } if (Node->getOp() == AtomicExpr::AO__atomic_exchange || Node->isCmpXChg()) { - PrintExpr(Node->getVal2()); OS << ", "; + PrintExpr(Node->getVal2()); } if (Node->getOp() == AtomicExpr::AO__atomic_compare_exchange || Node->getOp() == AtomicExpr::AO__atomic_compare_exchange_n) { - PrintExpr(Node->getWeak()); OS << ", "; + PrintExpr(Node->getWeak()); } - if (Node->getOp() != AtomicExpr::AO__c11_atomic_init) + if (Node->getOp() != AtomicExpr::AO__c11_atomic_init) { + OS << ", "; PrintExpr(Node->getOrder()); + } if (Node->isCmpXChg()) { OS << ", "; PrintExpr(Node->getOrderFail()); @@ -1238,6 +1243,18 @@ void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) { OS << ")"; } +void StmtPrinter::VisitMSPropertyRefExpr(MSPropertyRefExpr *Node) { + PrintExpr(Node->getBaseExpr()); + if (Node->isArrow()) + OS << "->"; + else + OS << "."; + if (NestedNameSpecifier *Qualifier = + Node->getQualifierLoc().getNestedNameSpecifier()) + Qualifier->print(OS, Policy); + OS << Node->getPropertyDecl()->getDeclName(); +} + void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) { switch (Node->getLiteralOperatorKind()) { case UserDefinedLiteral::LOK_Raw: @@ -1298,7 +1315,11 @@ void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) { } void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) { - // Nothing to print: we picked up the default argument + // Nothing to print: we picked up the default argument. +} + +void StmtPrinter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Node) { + // Nothing to print: we picked up the default initializer. } void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { @@ -1558,9 +1579,12 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { static const char *getTypeTraitName(UnaryTypeTrait UTT) { switch (UTT) { case UTT_HasNothrowAssign: return "__has_nothrow_assign"; + case UTT_HasNothrowMoveAssign: return "__has_nothrow_move_assign"; case UTT_HasNothrowConstructor: return "__has_nothrow_constructor"; case UTT_HasNothrowCopy: return "__has_nothrow_copy"; case UTT_HasTrivialAssign: return "__has_trivial_assign"; + case UTT_HasTrivialMoveAssign: return "__has_trivial_move_assign"; + case UTT_HasTrivialMoveConstructor: return "__has_trivial_move_constructor"; case UTT_HasTrivialDefaultConstructor: return "__has_trivial_constructor"; case UTT_HasTrivialCopy: return "__has_trivial_copy"; case UTT_HasTrivialDestructor: return "__has_trivial_destructor"; diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index bfd3132506..8ade242d56 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -215,6 +215,10 @@ void StmtProfiler::VisitSEHExceptStmt(const SEHExceptStmt *S) { VisitStmt(S); } +void StmtProfiler::VisitCapturedStmt(const CapturedStmt *S) { + VisitStmt(S); +} + void StmtProfiler::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { VisitStmt(S); } @@ -766,6 +770,11 @@ void StmtProfiler::VisitCXXUuidofExpr(const CXXUuidofExpr *S) { VisitType(S->getTypeOperand()); } +void StmtProfiler::VisitMSPropertyRefExpr(const MSPropertyRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getPropertyDecl()); +} + void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) { VisitExpr(S); ID.AddBoolean(S->isImplicit()); @@ -780,6 +789,11 @@ void StmtProfiler::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *S) { VisitDecl(S->getParam()); } +void StmtProfiler::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { + VisitExpr(S); + VisitDecl(S->getField()); +} + void StmtProfiler::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { VisitExpr(S); VisitDecl( diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index ca086b1951..fa16facb63 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -76,16 +76,35 @@ bool QualType::isConstant(QualType T, ASTContext &Ctx) { unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context, QualType ElementType, const llvm::APInt &NumElements) { + uint64_t ElementSize = Context.getTypeSizeInChars(ElementType).getQuantity(); + + // Fast path the common cases so we can avoid the conservative computation + // below, which in common cases allocates "large" APSInt values, which are + // slow. + + // If the element size is a power of 2, we can directly compute the additional + // number of addressing bits beyond those required for the element count. + if (llvm::isPowerOf2_64(ElementSize)) { + return NumElements.getActiveBits() + llvm::Log2_64(ElementSize); + } + + // If both the element count and element size fit in 32-bits, we can do the + // computation directly in 64-bits. + if ((ElementSize >> 32) == 0 && NumElements.getBitWidth() <= 64 && + (NumElements.getZExtValue() >> 32) == 0) { + uint64_t TotalSize = NumElements.getZExtValue() * ElementSize; + return 64 - llvm::CountLeadingZeros_64(TotalSize); + } + + // Otherwise, use APSInt to handle arbitrary sized values. llvm::APSInt SizeExtended(NumElements, true); unsigned SizeTypeBits = Context.getTypeSize(Context.getSizeType()); SizeExtended = SizeExtended.extend(std::max(SizeTypeBits, SizeExtended.getBitWidth()) * 2); - uint64_t ElementSize - = Context.getTypeSizeInChars(ElementType).getQuantity(); llvm::APSInt TotalSize(llvm::APInt(SizeExtended.getBitWidth(), ElementSize)); TotalSize *= SizeExtended; - + return TotalSize.getActiveBits(); } @@ -1123,16 +1142,20 @@ bool QualType::isTriviallyCopyableType(ASTContext &Context) const { -bool Type::isLiteralType() const { +bool Type::isLiteralType(ASTContext &Ctx) const { if (isDependentType()) return false; - // C++0x [basic.types]p10: + // C++1y [basic.types]p10: + // A type is a literal type if it is: + // -- cv void; or + if (Ctx.getLangOpts().CPlusPlus1y && isVoidType()) + return true; + + // C++11 [basic.types]p10: // A type is a literal type if it is: // [...] - // -- an array of literal type. - // Extension: variable arrays cannot be literal types, since they're - // runtime-sized. + // -- an array of literal type other than an array of runtime bound; or if (isVariableArrayType()) return false; const Type *BaseTy = getBaseElementTypeUnsafe(); @@ -1143,7 +1166,7 @@ bool Type::isLiteralType() const { if (BaseTy->isIncompleteType()) return false; - // C++0x [basic.types]p10: + // C++11 [basic.types]p10: // A type is a literal type if it is: // -- a scalar type; or // As an extension, Clang treats vector types and complex types as @@ -2082,6 +2105,11 @@ static CachedProperties computeCachedProperties(const Type *T) { assert(T->isInstantiationDependentType()); return CachedProperties(ExternalLinkage, false); + case Type::Auto: + // Give non-deduced 'auto' types external linkage. We should only see them + // here in error recovery. + return CachedProperties(ExternalLinkage, false); + case Type::Builtin: // C++ [basic.link]p8: // A type is said to have linkage if and only if: @@ -2183,6 +2211,9 @@ static LinkageInfo computeLinkageInfo(const Type *T) { case Type::Builtin: return LinkageInfo::external(); + case Type::Auto: + return LinkageInfo::external(); + case Type::Record: case Type::Enum: return cast<TagType>(T)->getDecl()->getLinkageAndVisibility(); @@ -2236,6 +2267,14 @@ static LinkageInfo computeLinkageInfo(QualType T) { return computeLinkageInfo(T.getTypePtr()); } +bool Type::isLinkageValid() const { + if (!TypeBits.isCacheValid()) + return true; + + return computeLinkageInfo(getCanonicalTypeInternal()).getLinkage() == + TypeBits.getLinkage(); +} + LinkageInfo Type::getLinkageAndVisibility() const { if (!isCanonicalUnqualified()) return computeLinkageInfo(getCanonicalTypeInternal()); @@ -2245,12 +2284,6 @@ LinkageInfo Type::getLinkageAndVisibility() const { return LV; } -void Type::ClearLinkageCache() { - TypeBits.CacheValid = false; - if (QualType(this, 0) != CanonicalType) - CanonicalType->TypeBits.CacheValid = false; -} - Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const { if (isObjCARCImplicitlyUnretainedType()) return Qualifiers::OCL_ExplicitNone; diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 9d1717a220..043707622b 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -776,16 +776,16 @@ void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T, void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) { // If the type has been deduced, do not print 'auto'. - if (T->isDeduced()) { + if (!T->getDeducedType().isNull()) { printBefore(T->getDeducedType(), OS); } else { - OS << "auto"; + OS << (T->isDecltypeAuto() ? "decltype(auto)" : "auto"); spaceBeforePlaceHolder(OS); } } void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) { // If the type has been deduced, do not print 'auto'. - if (T->isDeduced()) + if (!T->getDeducedType().isNull()) printAfter(T->getDeducedType(), OS); } diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp index 1af2f09c3e..6ebd736e3c 100644 --- a/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/lib/ASTMatchers/ASTMatchFinder.cpp @@ -20,6 +20,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" +#include <deque> #include <set> namespace clang { @@ -388,7 +389,8 @@ public: const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) { - return matchesAncestorOfRecursively(Node, Matcher, Builder, MatchMode); + return memoizedMatchesAncestorOfRecursively(Node, Matcher, Builder, + MatchMode); } // Matches all registered matchers on the given node and calls the @@ -421,7 +423,20 @@ public: bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; } private: - bool matchesAncestorOfRecursively( + // Returns whether an ancestor of \p Node matches \p Matcher. + // + // The order of matching ((which can lead to different nodes being bound in + // case there are multiple matches) is breadth first search. + // + // To allow memoization in the very common case of having deeply nested + // expressions inside a template function, we first walk up the AST, memoizing + // the result of the match along the way, as long as there is only a single + // parent. + // + // Once there are multiple parents, the breadth first search order does not + // allow simple memoization on the ancestors. Thus, we only memoize as long + // as there is a single parent. + bool memoizedMatchesAncestorOfRecursively( const ast_type_traits::DynTypedNode &Node, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) { if (Node.get<TranslationUnitDecl>() == @@ -435,24 +450,57 @@ private: assert(false && "Found node that is not in the parent map."); return false; } - for (ASTContext::ParentVector::const_iterator AncestorI = Parents.begin(), - AncestorE = Parents.end(); - AncestorI != AncestorE; ++AncestorI) { - if (Matcher.matches(*AncestorI, this, Builder)) - return true; - } - if (MatchMode == ASTMatchFinder::AMM_ParentOnly) - return false; - for (ASTContext::ParentVector::const_iterator AncestorI = Parents.begin(), - AncestorE = Parents.end(); - AncestorI != AncestorE; ++AncestorI) { - if (matchesAncestorOfRecursively(*AncestorI, Matcher, Builder, MatchMode)) - return true; + const UntypedMatchInput input(Matcher.getID(), Node.getMemoizationData()); + MemoizationMap::iterator I = ResultCache.find(input); + if (I == ResultCache.end()) { + BoundNodesTreeBuilder AncestorBoundNodesBuilder; + bool Matches = false; + if (Parents.size() == 1) { + // Only one parent - do recursive memoization. + const ast_type_traits::DynTypedNode Parent = Parents[0]; + if (Matcher.matches(Parent, this, &AncestorBoundNodesBuilder)) { + Matches = true; + } else if (MatchMode != ASTMatchFinder::AMM_ParentOnly) { + Matches = memoizedMatchesAncestorOfRecursively( + Parent, Matcher, &AncestorBoundNodesBuilder, MatchMode); + } + } else { + // Multiple parents - BFS over the rest of the nodes. + llvm::DenseSet<const void *> Visited; + std::deque<ast_type_traits::DynTypedNode> Queue(Parents.begin(), + Parents.end()); + while (!Queue.empty()) { + if (Matcher.matches(Queue.front(), this, + &AncestorBoundNodesBuilder)) { + Matches = true; + break; + } + if (MatchMode != ASTMatchFinder::AMM_ParentOnly) { + ASTContext::ParentVector Ancestors = + ActiveASTContext->getParents(Queue.front()); + for (ASTContext::ParentVector::const_iterator I = Ancestors.begin(), + E = Ancestors.end(); + I != E; ++I) { + // Make sure we do not visit the same node twice. + // Otherwise, we'll visit the common ancestors as often as there + // are splits on the way down. + if (Visited.insert(I->getMemoizationData()).second) + Queue.push_back(*I); + } + } + Queue.pop_front(); + } + } + + I = ResultCache.insert(std::make_pair(input, MemoizedMatchResult())) + .first; + I->second.Nodes = AncestorBoundNodesBuilder.build(); + I->second.ResultOfMatch = Matches; } - return false; + I->second.Nodes.copyTo(Builder); + return I->second.ResultOfMatch; } - // Implements a BoundNodesTree::Visitor that calls a MatchCallback with // the aggregated bound nodes for each match. class MatchVisitor : public BoundNodesTree::Visitor { diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp index 36d1dba5e3..5ff7842407 100644 --- a/lib/Analysis/AnalysisDeclContext.cpp +++ b/lib/Analysis/AnalysisDeclContext.cpp @@ -28,6 +28,7 @@ #include "clang/Analysis/Support/BumpVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/SaveAndRestore.h" using namespace clang; @@ -66,13 +67,15 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, bool addImplicitDtors, bool addInitializers, bool addTemporaryDtors, - bool synthesizeBodies) + bool synthesizeBodies, + bool addStaticInitBranch) : SynthesizeBodies(synthesizeBodies) { cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG; cfgBuildOptions.AddImplicitDtors = addImplicitDtors; cfgBuildOptions.AddInitializers = addInitializers; cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors; + cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch; } void AnalysisDeclContextManager::clear() { @@ -384,6 +387,31 @@ bool LocationContext::isParentOf(const LocationContext *LC) const { return false; } +void LocationContext::dumpStack() const { + ASTContext &Ctx = getAnalysisDeclContext()->getASTContext(); + PrintingPolicy PP(Ctx.getLangOpts()); + PP.TerseOutput = 1; + + unsigned Frame = 0; + for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) { + switch (LCtx->getKind()) { + case StackFrame: + llvm::errs() << '#' << Frame++ << ' '; + cast<StackFrameContext>(LCtx)->getDecl()->print(llvm::errs(), PP); + llvm::errs() << '\n'; + break; + case Scope: + llvm::errs() << " (scope)\n"; + break; + case Block: + llvm::errs() << " (block context: " + << cast<BlockInvocationContext>(LCtx)->getContextData() + << ")\n"; + break; + } + } +} + //===----------------------------------------------------------------------===// // Lazily generated map to query the external variables referenced by a Block. //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp index dda26bfab8..4d5c2ee236 100644 --- a/lib/Analysis/BodyFarm.cpp +++ b/lib/Analysis/BodyFarm.cpp @@ -194,8 +194,8 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { // (1) Create the call. DeclRefExpr *DR = M.makeDeclRefExpr(Block); ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); - CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy, - VK_RValue, SourceLocation()); + CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue, + SourceLocation()); // (2) Create the assignment to the predicate. IntegerLiteral *IL = @@ -257,8 +257,8 @@ static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) { ASTMaker M(C); DeclRefExpr *DR = M.makeDeclRefExpr(PV); ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); - CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy, - VK_RValue, SourceLocation()); + CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue, + SourceLocation()); return CE; } diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 4d20467a79..096c7a080b 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -675,7 +675,7 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { E = BackpatchBlocks.end(); I != E; ++I ) { CFGBlock *B = I->block; - GotoStmt *G = cast<GotoStmt>(B->getTerminator()); + const GotoStmt *G = cast<GotoStmt>(B->getTerminator()); LabelMapTy::iterator LI = LabelMap.find(G->getLabel()); // If there is no target for the goto, then we are looking at an @@ -1085,11 +1085,16 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { return VisitExprWithCleanups(cast<ExprWithCleanups>(S), asc); case Stmt::CXXDefaultArgExprClass: + case Stmt::CXXDefaultInitExprClass: // FIXME: The expression inside a CXXDefaultArgExpr is owned by the // called function's declaration, not by the caller. If we simply add // this expression to the CFG, we could end up with the same Expr // appearing multiple times. // PR13385 / <rdar://problem/12156507> + // + // It's likewise possible for multiple CXXDefaultInitExprs for the same + // expression to be used in the same function (through aggregate + // initialization). return VisitStmt(S, asc); case Stmt::CXXBindTemporaryExprClass: @@ -1653,6 +1658,21 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { bool IsReference = false; bool HasTemporaries = false; + // Guard static initializers under a branch. + CFGBlock *blockAfterStaticInit = 0; + + if (BuildOpts.AddStaticInitBranches && VD->isStaticLocal()) { + // For static variables, we need to create a branch to track + // whether or not they are initialized. + if (Block) { + Succ = Block; + Block = 0; + if (badCFG) + return 0; + } + blockAfterStaticInit = Succ; + } + // Destructors of temporaries in initialization expression should be called // after initialization finishes. Expr *Init = VD->getInit(); @@ -1700,7 +1720,17 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { if (ScopePos && VD == *ScopePos) ++ScopePos; - return Block ? Block : LastBlock; + CFGBlock *B = LastBlock; + if (blockAfterStaticInit) { + Succ = B; + Block = createBlock(false); + Block->setTerminator(DS); + addSuccessor(Block, blockAfterStaticInit); + addSuccessor(Block, B); + B = Block; + } + + return B; } CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) { @@ -3642,6 +3672,11 @@ public: Terminator->printPretty(OS, Helper, Policy); } + void VisitDeclStmt(DeclStmt *DS) { + VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); + OS << "static init " << VD->getName(); + } + void VisitForStmt(ForStmt *F) { OS << "for (" ; if (F->getInit()) diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp index 7bb54d6ad3..479d9a301f 100644 --- a/lib/Analysis/ThreadSafety.cpp +++ b/lib/Analysis/ThreadSafety.cpp @@ -784,7 +784,7 @@ struct LockData { /// \brief A FactEntry stores a single fact that is known at a particular point /// in the program execution. Currently, this is information regarding a lock -/// that is held at that point. +/// that is held at that point. struct FactEntry { SExpr MutID; LockData LDat; @@ -797,7 +797,7 @@ struct FactEntry { typedef unsigned short FactID; -/// \brief FactManager manages the memory for all facts that are created during +/// \brief FactManager manages the memory for all facts that are created during /// the analysis of a single routine. class FactManager { private: @@ -815,9 +815,9 @@ public: /// \brief A FactSet is the set of facts that are known to be true at a -/// particular program point. FactSets must be small, because they are +/// particular program point. FactSets must be small, because they are /// frequently copied, and are thus implemented as a set of indices into a -/// table maintained by a FactManager. A typical FactSet only holds 1 or 2 +/// table maintained by a FactManager. A typical FactSet only holds 1 or 2 /// locks, so we can get away with doing a linear search for lookup. Note /// that a hashtable or map is inappropriate in this case, because lookups /// may involve partial pattern matches, rather than exact matches. @@ -1858,13 +1858,11 @@ void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK) { return; } - if (Analyzer->Handler.issueBetaWarnings()) { - if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) { - if (ME->isArrow()) - checkPtAccess(ME->getBase(), AK); - else - checkAccess(ME->getBase(), AK); - } + if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) { + if (ME->isArrow()) + checkPtAccess(ME->getBase(), AK); + else + checkAccess(ME->getBase(), AK); } const ValueDecl *D = getValueDecl(Exp); @@ -2065,40 +2063,38 @@ void BuildLockset::VisitCastExpr(CastExpr *CE) { void BuildLockset::VisitCallExpr(CallExpr *Exp) { - if (Analyzer->Handler.issueBetaWarnings()) { - if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(Exp)) { - MemberExpr *ME = dyn_cast<MemberExpr>(CE->getCallee()); - // ME can be null when calling a method pointer - CXXMethodDecl *MD = CE->getMethodDecl(); - - if (ME && MD) { - if (ME->isArrow()) { - if (MD->isConst()) { - checkPtAccess(CE->getImplicitObjectArgument(), AK_Read); - } else { // FIXME -- should be AK_Written - checkPtAccess(CE->getImplicitObjectArgument(), AK_Read); - } - } else { - if (MD->isConst()) - checkAccess(CE->getImplicitObjectArgument(), AK_Read); - else // FIXME -- should be AK_Written - checkAccess(CE->getImplicitObjectArgument(), AK_Read); + if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(Exp)) { + MemberExpr *ME = dyn_cast<MemberExpr>(CE->getCallee()); + // ME can be null when calling a method pointer + CXXMethodDecl *MD = CE->getMethodDecl(); + + if (ME && MD) { + if (ME->isArrow()) { + if (MD->isConst()) { + checkPtAccess(CE->getImplicitObjectArgument(), AK_Read); + } else { // FIXME -- should be AK_Written + checkPtAccess(CE->getImplicitObjectArgument(), AK_Read); } + } else { + if (MD->isConst()) + checkAccess(CE->getImplicitObjectArgument(), AK_Read); + else // FIXME -- should be AK_Written + checkAccess(CE->getImplicitObjectArgument(), AK_Read); } - } else if (CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(Exp)) { - switch (OE->getOperator()) { - case OO_Equal: { - const Expr *Target = OE->getArg(0); - const Expr *Source = OE->getArg(1); - checkAccess(Target, AK_Written); - checkAccess(Source, AK_Read); - break; - } - default: { - const Expr *Source = OE->getArg(0); - checkAccess(Source, AK_Read); - break; - } + } + } else if (CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(Exp)) { + switch (OE->getOperator()) { + case OO_Equal: { + const Expr *Target = OE->getArg(0); + const Expr *Source = OE->getArg(1); + checkAccess(Target, AK_Written); + checkAccess(Source, AK_Read); + break; + } + default: { + const Expr *Source = OE->getArg(0); + checkAccess(Source, AK_Read); + break; } } } @@ -2109,12 +2105,10 @@ void BuildLockset::VisitCallExpr(CallExpr *Exp) { } void BuildLockset::VisitCXXConstructExpr(CXXConstructExpr *Exp) { - if (Analyzer->Handler.issueBetaWarnings()) { - const CXXConstructorDecl *D = Exp->getConstructor(); - if (D && D->isCopyConstructor()) { - const Expr* Source = Exp->getArg(0); - checkAccess(Source, AK_Read); - } + const CXXConstructorDecl *D = Exp->getConstructor(); + if (D && D->isCopyConstructor()) { + const Expr* Source = Exp->getArg(0); + checkAccess(Source, AK_Read); } // FIXME -- only handles constructors in DeclStmt below. } @@ -2285,6 +2279,10 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { // Fill in source locations for all CFGBlocks. findBlockLocations(CFGraph, SortedGraph, BlockInfo); + MutexIDList ExclusiveLocksAcquired; + MutexIDList SharedLocksAcquired; + MutexIDList LocksReleased; + // Add locks from exclusive_locks_required and shared_locks_required // to initial lockset. Also turn off checking for lock and unlock functions. // FIXME: is there a more intelligent way to check lock/unlock functions? @@ -2306,15 +2304,30 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { } else if (SharedLocksRequiredAttr *A = dyn_cast<SharedLocksRequiredAttr>(Attr)) { getMutexIDs(SharedLocksToAdd, A, (Expr*) 0, D); - } else if (isa<UnlockFunctionAttr>(Attr)) { - // Don't try to check unlock functions for now - return; - } else if (isa<ExclusiveLockFunctionAttr>(Attr)) { - // Don't try to check lock functions for now - return; - } else if (isa<SharedLockFunctionAttr>(Attr)) { - // Don't try to check lock functions for now - return; + } else if (UnlockFunctionAttr *A = dyn_cast<UnlockFunctionAttr>(Attr)) { + if (!Handler.issueBetaWarnings()) + return; + // UNLOCK_FUNCTION() is used to hide the underlying lock implementation. + // We must ignore such methods. + if (A->args_size() == 0) + return; + // FIXME -- deal with exclusive vs. shared unlock functions? + getMutexIDs(ExclusiveLocksToAdd, A, (Expr*) 0, D); + getMutexIDs(LocksReleased, A, (Expr*) 0, D); + } else if (ExclusiveLockFunctionAttr *A + = dyn_cast<ExclusiveLockFunctionAttr>(Attr)) { + if (!Handler.issueBetaWarnings()) + return; + if (A->args_size() == 0) + return; + getMutexIDs(ExclusiveLocksAcquired, A, (Expr*) 0, D); + } else if (SharedLockFunctionAttr *A + = dyn_cast<SharedLockFunctionAttr>(Attr)) { + if (!Handler.issueBetaWarnings()) + return; + if (A->args_size() == 0) + return; + getMutexIDs(SharedLocksAcquired, A, (Expr*) 0, D); } else if (isa<ExclusiveTrylockFunctionAttr>(Attr)) { // Don't try to check trylock functions for now return; @@ -2497,8 +2510,27 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { if (!Final->Reachable) return; + // By default, we expect all locks held on entry to be held on exit. + FactSet ExpectedExitSet = Initial->EntrySet; + + // Adjust the expected exit set by adding or removing locks, as declared + // by *-LOCK_FUNCTION and UNLOCK_FUNCTION. The intersect below will then + // issue the appropriate warning. + // FIXME: the location here is not quite right. + for (unsigned i=0,n=ExclusiveLocksAcquired.size(); i<n; ++i) { + ExpectedExitSet.addLock(FactMan, ExclusiveLocksAcquired[i], + LockData(D->getLocation(), LK_Exclusive)); + } + for (unsigned i=0,n=SharedLocksAcquired.size(); i<n; ++i) { + ExpectedExitSet.addLock(FactMan, SharedLocksAcquired[i], + LockData(D->getLocation(), LK_Shared)); + } + for (unsigned i=0,n=LocksReleased.size(); i<n; ++i) { + ExpectedExitSet.removeLock(FactMan, LocksReleased[i]); + } + // FIXME: Should we call this function for all blocks which exit the function? - intersectAndWarn(Initial->EntrySet, Final->ExitSet, + intersectAndWarn(ExpectedExitSet, Final->ExitSet, Final->ExitLoc, LEK_LockedAtEndOfFunction, LEK_NotLockedAtEndOfFunction, diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index 37efcb1220..34111691c8 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_library(clangBasic LangOptions.cpp Module.cpp ObjCRuntime.cpp + OpenMPKinds.cpp OperatorPrecedence.cpp SourceLocation.cpp SourceManager.cpp @@ -28,9 +29,25 @@ if( NOT IS_SYMLINK "${CLANG_SOURCE_DIR}" ) # See PR 8437 find_package(Subversion) endif() if (Subversion_FOUND AND EXISTS "${CLANG_SOURCE_DIR}/.svn") - Subversion_WC_INFO(${CLANG_SOURCE_DIR} CLANG) + # Create custom target to generate the Subversion version include. + add_custom_target(clang_revision_tag ALL + COMMAND ${CMAKE_COMMAND} -DFIRST_SOURCE_DIR=${LLVM_MAIN_SRC_DIR} + -DFIRST_REPOSITORY=LLVM_REPOSITORY + -DSECOND_SOURCE_DIR=${CLANG_SOURCE_DIR} + -DSECOND_REPOSITORY=SVN_REPOSITORY + -DHEADER_FILE=${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc + -P ${LLVM_MAIN_SRC_DIR}/cmake/modules/GetSVN.cmake) + + # Mark the generated header as being generated. +message(STATUS "Expecting header to go in ${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc") + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc + PROPERTIES GENERATED TRUE + HEADER_FILE_ONLY TRUE) + + # Tell Version.cpp that it needs to build with -DHAVE_SVN_VERSION_INC. set_source_files_properties(Version.cpp - PROPERTIES COMPILE_DEFINITIONS "SVN_REVISION=\"${CLANG_WC_REVISION}\"") + PROPERTIES COMPILE_DEFINITIONS "HAVE_SVN_VERSION_INC") + endif() add_dependencies(clangBasic @@ -49,3 +66,8 @@ add_dependencies(clangBasic ClangDiagnosticSema ClangDiagnosticSerialization ) + +# clangBasic depends on the version. +if (Subversion_FOUND AND EXISTS "${CLANG_SOURCE_DIR}/.svn") + add_dependencies(clangBasic clang_revision_tag) +endif()
\ No newline at end of file diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 842bacb9a5..45d4b539e8 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -971,6 +971,23 @@ bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; } void IgnoringDiagConsumer::anchor() { } +ForwardingDiagnosticConsumer::~ForwardingDiagnosticConsumer() {} + +void ForwardingDiagnosticConsumer::HandleDiagnostic( + DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) { + Target.HandleDiagnostic(DiagLevel, Info); +} + +void ForwardingDiagnosticConsumer::clear() { + DiagnosticConsumer::clear(); + Target.clear(); +} + +bool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const { + return Target.IncludeInDiagnosticCounts(); +} + PartialDiagnostic::StorageAllocator::StorageAllocator() { for (unsigned I = 0; I != NumCached; ++I) FreeList[I] = Cached + I; diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 429d9d8cb2..951c718d18 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -65,7 +65,7 @@ namespace { }; } -IdentifierIterator *IdentifierInfoLookup::getIdentifiers() const { +IdentifierIterator *IdentifierInfoLookup::getIdentifiers() { return new EmptyLookupIterator(); } diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index 65deac1b4a..13518cde66 100644 --- a/lib/Basic/Module.cpp +++ b/lib/Basic/Module.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" @@ -27,7 +28,8 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, Umbrella(), ASTFile(0), IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false), InferSubmodules(false), InferExplicitSubmodules(false), - InferExportWildcard(false), NameVisibility(Hidden) + InferExportWildcard(false), ConfigMacrosExhaustive(false), + NameVisibility(Hidden) { if (Parent) { if (!Parent->isAvailable()) @@ -45,7 +47,6 @@ Module::~Module() { I != IEnd; ++I) { delete *I; } - } /// \brief Determine whether a translation unit built using the current @@ -129,6 +130,19 @@ const DirectoryEntry *Module::getUmbrellaDir() const { return Umbrella.dyn_cast<const DirectoryEntry *>(); } +ArrayRef<const FileEntry *> Module::getTopHeaders(FileManager &FileMgr) { + if (!TopHeaderNames.empty()) { + for (std::vector<std::string>::iterator + I = TopHeaderNames.begin(), E = TopHeaderNames.end(); I != E; ++I) { + if (const FileEntry *FE = FileMgr.getFile(*I)) + TopHeaders.insert(FE); + } + TopHeaderNames.clear(); + } + + return llvm::makeArrayRef(TopHeaders.begin(), TopHeaders.end()); +} + void Module::addRequirement(StringRef Feature, const LangOptions &LangOpts, const TargetInfo &Target) { Requires.push_back(Feature); @@ -265,7 +279,20 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { OS.write_escaped(UmbrellaDir->getName()); OS << "\"\n"; } - + + if (!ConfigMacros.empty() || ConfigMacrosExhaustive) { + OS.indent(Indent + 2); + OS << "config_macros "; + if (ConfigMacrosExhaustive) + OS << "[exhaustive]"; + for (unsigned I = 0, N = ConfigMacros.size(); I != N; ++I) { + if (I) + OS << ", "; + OS << ConfigMacros[I]; + } + OS << "\n"; + } + for (unsigned I = 0, N = Headers.size(); I != N; ++I) { OS.indent(Indent + 2); OS << "header \""; @@ -320,6 +347,24 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { OS << "\""; } + for (unsigned I = 0, N = UnresolvedConflicts.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "conflict "; + printModuleId(OS, UnresolvedConflicts[I].Id); + OS << ", \""; + OS.write_escaped(UnresolvedConflicts[I].Message); + OS << "\"\n"; + } + + for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "conflict "; + OS << Conflicts[I].Other->getFullModuleName(); + OS << ", \""; + OS.write_escaped(Conflicts[I].Message); + OS << "\"\n"; + } + if (InferSubmodules) { OS.indent(Indent + 2); if (InferExplicitSubmodules) diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp new file mode 100644 index 0000000000..835908d2a1 --- /dev/null +++ b/lib/Basic/OpenMPKinds.cpp @@ -0,0 +1,43 @@ +//===--- OpenMPKinds.cpp - Token Kinds Support ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This file implements the OpenMP enum and support functions. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> + +using namespace clang; + +OpenMPDirectiveKind clang::getOpenMPDirectiveKind(StringRef Str) { + return llvm::StringSwitch<OpenMPDirectiveKind>(Str) +#define OPENMP_DIRECTIVE(Name) \ + .Case(#Name, OMPD_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPD_unknown); +} + +const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) { + assert(Kind < NUM_OPENMP_DIRECTIVES); + switch (Kind) { + case OMPD_unknown: + return ("unknown"); +#define OPENMP_DIRECTIVE(Name) \ + case OMPD_##Name : return #Name; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + llvm_unreachable("Invalid OpenMP directive kind"); +} diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 1b8383bc42..d6dc6d6328 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -1848,23 +1848,42 @@ SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) const { return Loc; } +std::pair<FileID, unsigned> +SourceManager::getDecomposedIncludedLoc(FileID FID) const { + // Uses IncludedLocMap to retrieve/cache the decomposed loc. + + typedef std::pair<FileID, unsigned> DecompTy; + typedef llvm::DenseMap<FileID, DecompTy> MapTy; + std::pair<MapTy::iterator, bool> + InsertOp = IncludedLocMap.insert(std::make_pair(FID, DecompTy())); + DecompTy &DecompLoc = InsertOp.first->second; + if (!InsertOp.second) + return DecompLoc; // already in map. + + SourceLocation UpperLoc; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID); + if (Entry.isExpansion()) + UpperLoc = Entry.getExpansion().getExpansionLocStart(); + else + UpperLoc = Entry.getFile().getIncludeLoc(); + + if (UpperLoc.isValid()) + DecompLoc = getDecomposedLoc(UpperLoc); + + return DecompLoc; +} + /// Given a decomposed source location, move it up the include/expansion stack /// to the parent source location. If this is possible, return the decomposed /// version of the parent in Loc and return false. If Loc is the top-level /// entry, return true and don't modify it. static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc, const SourceManager &SM) { - SourceLocation UpperLoc; - const SrcMgr::SLocEntry &Entry = SM.getSLocEntry(Loc.first); - if (Entry.isExpansion()) - UpperLoc = Entry.getExpansion().getExpansionLocStart(); - else - UpperLoc = Entry.getFile().getIncludeLoc(); - - if (UpperLoc.isInvalid()) + std::pair<FileID, unsigned> UpperLoc = SM.getDecomposedIncludedLoc(Loc.first); + if (UpperLoc.first.isInvalid()) return true; // We reached the top. - - Loc = SM.getDecomposedLoc(UpperLoc); + + Loc = UpperLoc; return false; } @@ -1929,7 +1948,7 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, // of the other looking for a match. // We use a map from FileID to Offset to store the chain. Easier than writing // a custom set hash info that only depends on the first part of a pair. - typedef llvm::DenseMap<FileID, unsigned> LocSet; + typedef llvm::SmallDenseMap<FileID, unsigned, 16> LocSet; LocSet LChain; do { LChain.insert(LOffs); diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 70ea2351ec..0d44dc010e 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -37,6 +37,7 @@ TargetInfo::TargetInfo(const std::string &T) : TargetOpts(), Triple(T) LongWidth = LongAlign = 32; LongLongWidth = LongLongAlign = 64; SuitableAlign = 64; + MinGlobalAlign = 0; HalfWidth = 16; HalfAlign = 16; FloatWidth = 32; @@ -373,7 +374,9 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { Name++; } - return true; + // If a constraint allows neither memory nor register operands it contains + // only modifiers. Reject it. + return Info.allowsMemory() || Info.allowsRegister(); } bool TargetInfo::resolveSymbolicName(const char *&Name, diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index b7cd3dce7c..a622a11aa5 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -621,7 +621,7 @@ class NaClTargetInfo : public OSTargetInfo<Target> { this->SizeType = TargetInfo::UnsignedInt; this->PtrDiffType = TargetInfo::SignedInt; this->IntPtrType = TargetInfo::SignedInt; - this->RegParmMax = 2; + // RegParmMax is inherited from the underlying architecture this->LongDoubleFormat = &llvm::APFloat::IEEEdouble; this->DescriptionString = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-" "f32:32:32-f64:64:64-p:32:32:32-v128:32:32"; @@ -1029,7 +1029,8 @@ void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { bool PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, bool Enabled) const { - if (Name == "altivec" || Name == "qpx") { + if (Name == "altivec" || Name == "fprnd" || Name == "mfocrf" || + Name == "popcntd" || Name == "qpx") { Features[Name] = Enabled; return true; } @@ -1301,7 +1302,14 @@ namespace { return TargetInfo::CharPtrBuiltinVaList; } virtual bool setCPU(const std::string &Name) { - return Name == "sm_10" || Name == "sm_13" || Name == "sm_20"; + bool Valid = llvm::StringSwitch<bool>(Name) + .Case("sm_20", true) + .Case("sm_21", true) + .Case("sm_30", true) + .Case("sm_35", true) + .Default(false); + + return Valid; } virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, @@ -1484,7 +1492,7 @@ public: .Case("caicos", GK_NORTHERN_ISLANDS) .Case("cayman", GK_CAYMAN) .Case("aruba", GK_CAYMAN) - .Case("SI", GK_SOUTHERN_ISLANDS) + .Case("tahiti", GK_SOUTHERN_ISLANDS) .Case("pitcairn", GK_SOUTHERN_ISLANDS) .Case("verde", GK_SOUTHERN_ISLANDS) .Case("oland", GK_SOUTHERN_ISLANDS) @@ -1701,6 +1709,8 @@ class X86TargetInfo : public TargetInfo { bool HasBMI2; bool HasPOPCNT; bool HasRTM; + bool HasPRFCHW; + bool HasRDSEED; bool HasSSE4a; bool HasFMA4; bool HasFMA; @@ -1825,6 +1835,7 @@ class X86TargetInfo : public TargetInfo { /// Bobcat architecture processors. //@{ CK_BTVER1, + CK_BTVER2, //@} /// \name Bulldozer @@ -1852,8 +1863,8 @@ public: : TargetInfo(triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow), HasAES(false), HasPCLMUL(false), HasLZCNT(false), HasRDRND(false), HasBMI(false), HasBMI2(false), HasPOPCNT(false), HasRTM(false), - HasSSE4a(false), HasFMA4(false), HasFMA(false), HasXOP(false), - HasF16C(false), CPU(CK_Generic) { + HasPRFCHW(false), HasRDSEED(false), HasSSE4a(false), HasFMA4(false), + HasFMA(false), HasXOP(false), HasF16C(false), CPU(CK_Generic) { BigEndian = false; LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } @@ -1949,6 +1960,7 @@ public: .Case("opteron-sse3", CK_OpteronSSE3) .Case("amdfam10", CK_AMDFAM10) .Case("btver1", CK_BTVER1) + .Case("btver2", CK_BTVER2) .Case("bdver1", CK_BDVER1) .Case("bdver2", CK_BDVER2) .Case("x86-64", CK_x86_64) @@ -2014,6 +2026,7 @@ public: case CK_OpteronSSE3: case CK_AMDFAM10: case CK_BTVER1: + case CK_BTVER2: case CK_BDVER1: case CK_BDVER2: case CK_x86_64: @@ -2059,6 +2072,8 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { Features["bmi2"] = false; Features["popcnt"] = false; Features["rtm"] = false; + Features["prfchw"] = false; + Features["rdseed"] = false; Features["fma4"] = false; Features["fma"] = false; Features["xop"] = false; @@ -2181,6 +2196,15 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { setFeatureEnabled(Features, "lzcnt", true); setFeatureEnabled(Features, "popcnt", true); break; + case CK_BTVER2: + setFeatureEnabled(Features, "avx", true); + setFeatureEnabled(Features, "sse4a", true); + setFeatureEnabled(Features, "lzcnt", true); + setFeatureEnabled(Features, "aes", true); + setFeatureEnabled(Features, "pclmul", true); + setFeatureEnabled(Features, "bmi", true); + setFeatureEnabled(Features, "f16c", true); + break; case CK_BDVER1: setFeatureEnabled(Features, "xop", true); setFeatureEnabled(Features, "lzcnt", true); @@ -2281,6 +2305,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, Features["f16c"] = true; else if (Name == "rtm") Features["rtm"] = true; + else if (Name == "prfchw") + Features["prfchw"] = true; + else if (Name == "rdseed") + Features["rdseed"] = true; } else { if (Name == "mmx") Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = false; @@ -2345,6 +2373,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, Features["f16c"] = false; else if (Name == "rtm") Features["rtm"] = false; + else if (Name == "prfchw") + Features["prfchw"] = false; + else if (Name == "rdseed") + Features["rdseed"] = false; } return true; @@ -2401,6 +2433,16 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) { continue; } + if (Feature == "prfchw") { + HasPRFCHW = true; + continue; + } + + if (Feature == "rdseed") { + HasRDSEED = true; + continue; + } + if (Feature == "sse4a") { HasSSE4a = true; continue; @@ -2581,6 +2623,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, case CK_BTVER1: defineCPUMacros(Builder, "btver1"); break; + case CK_BTVER2: + defineCPUMacros(Builder, "btver2"); + break; case CK_BDVER1: defineCPUMacros(Builder, "bdver1"); break; @@ -2625,6 +2670,12 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasRTM) Builder.defineMacro("__RTM__"); + if (HasPRFCHW) + Builder.defineMacro("__PRFCHW__"); + + if (HasRDSEED) + Builder.defineMacro("__RDSEED__"); + if (HasSSE4a) Builder.defineMacro("__SSE4A__"); @@ -2694,6 +2745,14 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, case NoMMX3DNow: break; } + + if (CPU >= CK_i486) { + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + } + if (CPU >= CK_i586) + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } bool X86TargetInfo::hasFeature(StringRef Feature) const { @@ -2713,6 +2772,8 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("pclmul", HasPCLMUL) .Case("popcnt", HasPOPCNT) .Case("rtm", HasRTM) + .Case("prfchw", HasPRFCHW) + .Case("rdseed", HasRDSEED) .Case("sse", SSELevel >= SSE1) .Case("sse2", SSELevel >= SSE2) .Case("sse3", SSELevel >= SSE3) @@ -3246,6 +3307,8 @@ namespace { class AArch64TargetInfo : public TargetInfo { static const char * const GCCRegNames[]; static const TargetInfo::GCCRegAlias GCCRegAliases[]; + + static const Builtin::Info BuiltinInfo[]; public: AArch64TargetInfo(const std::string& triple) : TargetInfo(triple) { BigEndian = false; @@ -3277,45 +3340,45 @@ public: // FIXME: these were written based on an unreleased version of a 32-bit ACLE // which was intended to be compatible with a 64-bit implementation. They // will need updating when a real 64-bit ACLE exists. Particularly pressing - // instances are: __AARCH_ISA_A32, __AARCH_ISA_T32, __ARCH_PCS. - Builder.defineMacro("__AARCH_ACLE", "101"); - Builder.defineMacro("__AARCH", "8"); - Builder.defineMacro("__AARCH_PROFILE", "'A'"); + // instances are: __ARM_ARCH_ISA_ARM, __ARM_ARCH_ISA_THUMB, __ARM_PCS. + Builder.defineMacro("__ARM_ACLE", "101"); + Builder.defineMacro("__ARM_ARCH", "8"); + Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'"); - Builder.defineMacro("__AARCH_FEATURE_UNALIGNED"); - Builder.defineMacro("__AARCH_FEATURE_CLZ"); - Builder.defineMacro("__AARCH_FEATURE_FMA"); + Builder.defineMacro("__ARM_FEATURE_UNALIGNED"); + Builder.defineMacro("__ARM_FEATURE_CLZ"); + Builder.defineMacro("__ARM_FEATURE_FMA"); // FIXME: ACLE 1.1 reserves bit 4. Will almost certainly come to mean // 128-bit LDXP present, at which point this becomes 0x1f. - Builder.defineMacro("__AARCH_FEATURE_LDREX", "0xf"); + Builder.defineMacro("__ARM_FEATURE_LDREX", "0xf"); // 0xe implies support for half, single and double precision operations. - Builder.defineMacro("__AARCH_FP", "0xe"); + Builder.defineMacro("__ARM_FP", "0xe"); // PCS specifies this for SysV variants, which is all we support. Other ABIs - // may choose __AARCH_FP16_FORMAT_ALTERNATIVE. - Builder.defineMacro("__AARCH_FP16_FORMAT_IEEE"); + // may choose __ARM_FP16_FORMAT_ALTERNATIVE. + Builder.defineMacro("__ARM_FP16_FORMAT_IEEE"); if (Opts.FastMath || Opts.FiniteMathOnly) - Builder.defineMacro("__AARCH_FP_FAST"); + Builder.defineMacro("__ARM_FP_FAST"); if ((Opts.C99 || Opts.C11) && !Opts.Freestanding) - Builder.defineMacro("__AARCH_FP_FENV_ROUNDING"); + Builder.defineMacro("__ARM_FP_FENV_ROUNDING"); - Builder.defineMacro("__AARCH_SIZEOF_WCHAR_T", + Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", Opts.ShortWChar ? "2" : "4"); - Builder.defineMacro("__AARCH_SIZEOF_MINIMAL_ENUM", + Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4"); if (BigEndian) - Builder.defineMacro("__AARCH_BIG_ENDIAN"); + Builder.defineMacro("__ARM_BIG_ENDIAN"); } virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const { - Records = 0; - NumRecords = 0; + Records = BuiltinInfo; + NumRecords = clang::AArch64::LastTSBuiltin-Builtin::FirstTSBuiltin; } virtual bool hasFeature(StringRef Feature) const { return Feature == "aarch64"; @@ -3424,6 +3487,14 @@ void AArch64TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, NumAliases = llvm::array_lengthof(GCCRegAliases); } + +const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\ + ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsAArch64.def" +}; + } // end anonymous namespace namespace { @@ -3456,6 +3527,34 @@ class ARMTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; + static bool shouldUseInlineAtomic(const llvm::Triple &T) { + // On linux, binaries targeting old cpus call functions in libgcc to + // perform atomic operations. The implementation in libgcc then calls into + // the kernel which on armv6 and newer uses ldrex and strex. The net result + // is that if we assume the kernel is at least as recent as the hardware, + // it is safe to use atomic instructions on armv6 and newer. + if (T.getOS() != llvm::Triple::Linux) + return false; + StringRef ArchName = T.getArchName(); + if (T.getArch() == llvm::Triple::arm) { + if (!ArchName.startswith("armv")) + return false; + StringRef VersionStr = ArchName.substr(4); + unsigned Version; + if (VersionStr.getAsInteger(10, Version)) + return false; + return Version >= 6; + } + assert(T.getArch() == llvm::Triple::thumb); + if (!ArchName.startswith("thumbv")) + return false; + StringRef VersionStr = ArchName.substr(6); + unsigned Version; + if (VersionStr.getAsInteger(10, Version)) + return false; + return Version >= 7; + } + public: ARMTargetInfo(const std::string &TripleStr) : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s"), IsAAPCS(true) @@ -3488,8 +3587,9 @@ public: TheCXXABI.set(TargetCXXABI::GenericARM); // ARM has atomics up to 8 bytes - // FIXME: Set MaxAtomicInlineWidth if we have the feature v6e MaxAtomicPromoteWidth = 64; + if (shouldUseInlineAtomic(getTriple())) + MaxAtomicInlineWidth = 64; // Do force alignment of members that follow zero length bitfields. If // the alignment of the zero-length bitfield is greater than the member @@ -4065,16 +4165,14 @@ const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = { namespace { -class SparcV8TargetInfo : public TargetInfo { +// Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit). +class SparcTargetInfo : public TargetInfo { static const TargetInfo::GCCRegAlias GCCRegAliases[]; static const char * const GCCRegNames[]; bool SoftFloat; public: - SparcV8TargetInfo(const std::string& triple) : TargetInfo(triple) { - // FIXME: Support Sparc quad-precision long double? - 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-n32"; - } + SparcTargetInfo(const std::string &triple) : TargetInfo(triple) {} + virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, bool Enabled) const { @@ -4094,7 +4192,6 @@ public: virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { DefineStd(Builder, "sparc", Opts); - Builder.defineMacro("__sparcv8"); Builder.defineMacro("__REGISTER_PREFIX__", ""); if (SoftFloat) @@ -4130,20 +4227,20 @@ public: } }; -const char * const SparcV8TargetInfo::GCCRegNames[] = { +const char * const SparcTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" }; -void SparcV8TargetInfo::getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { +void SparcTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { Names = GCCRegNames; NumNames = llvm::array_lengthof(GCCRegNames); } -const TargetInfo::GCCRegAlias SparcV8TargetInfo::GCCRegAliases[] = { +const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = { { { "g0" }, "r0" }, { { "g1" }, "r1" }, { { "g2" }, "r2" }, @@ -4178,11 +4275,53 @@ const TargetInfo::GCCRegAlias SparcV8TargetInfo::GCCRegAliases[] = { { { "i7" }, "r31" }, }; -void SparcV8TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const { +void SparcTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { Aliases = GCCRegAliases; NumAliases = llvm::array_lengthof(GCCRegAliases); } + +// SPARC v8 is the 32-bit mode selected by Triple::sparc. +class SparcV8TargetInfo : public SparcTargetInfo { +public: + SparcV8TargetInfo(const std::string& triple) : SparcTargetInfo(triple) { + // FIXME: Support Sparc quad-precision long double? + 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-n32-S64"; + } + + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SparcTargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__sparcv8"); + } +}; + +// SPARC v9 is the 64-bit mode selected by Triple::sparcv9. +class SparcV9TargetInfo : public SparcTargetInfo { +public: + SparcV9TargetInfo(const std::string& triple) : SparcTargetInfo(triple) { + // FIXME: Support Sparc quad-precision long double? + DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32:64-S128"; + } + + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SparcTargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__sparcv9"); + Builder.defineMacro("__arch64__"); + // Solaris and its derivative AuroraUX don't need these variants, but the + // BSDs do. + if (getTriple().getOS() != llvm::Triple::Solaris && + getTriple().getOS() != llvm::Triple::AuroraUX) { + Builder.defineMacro("__sparc64__"); + Builder.defineMacro("__sparc_v9__"); + Builder.defineMacro("__sparcv9__"); + } + } +}; + } // end anonymous namespace. namespace { @@ -4205,6 +4344,100 @@ public: } // end anonymous namespace. namespace { + class SystemZTargetInfo : public TargetInfo { + static const char *const GCCRegNames[]; + + public: + SystemZTargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = true; + IntWidth = IntAlign = 32; + LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64; + PointerWidth = PointerAlign = 64; + LongDoubleWidth = 128; + LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEquad; + MinGlobalAlign = 16; + DescriptionString = "E-p:64:64:64-i1:8:16-i8:8:16-i16:16-i32:32-i64:64" + "-f32:32-f64:64-f128:64-a0:8:16-n32:64"; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__s390__"); + Builder.defineMacro("__s390x__"); + Builder.defineMacro("__zarch__"); + Builder.defineMacro("__LONG_DOUBLE_128__"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + // FIXME: Implement. + Records = 0; + NumRecords = 0; + } + + virtual void getGCCRegNames(const char *const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + // No aliases. + Aliases = 0; + NumAliases = 0; + } + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const; + virtual const char *getClobbers() const { + // FIXME: Is this really right? + return ""; + } + virtual BuiltinVaListKind getBuiltinVaListKind() const { + return TargetInfo::SystemZBuiltinVaList; + } + }; + + const char *const SystemZTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7", + "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15" + }; + + void SystemZTargetInfo::getGCCRegNames(const char *const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + + bool SystemZTargetInfo:: + validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + return false; + + case 'a': // Address register + case 'd': // Data register (equivalent to 'r') + case 'f': // Floating-point register + Info.setAllowsRegister(); + return true; + + case 'I': // Unsigned 8-bit constant + case 'J': // Unsigned 12-bit constant + case 'K': // Signed 16-bit constant + case 'L': // Signed 20-bit displacement (on all targets we support) + case 'M': // 0x7fffffff + return true; + + case 'Q': // Memory with base and unsigned 12-bit displacement + case 'R': // Likewise, plus an index + case 'S': // Memory with base and signed 20-bit displacement + case 'T': // Likewise, plus an index + Info.setAllowsMemory(); + return true; + } + } +} + +namespace { class MSP430TargetInfo : public TargetInfo { static const char * const GCCRegNames[]; public: @@ -4359,8 +4592,10 @@ class MipsTargetInfoBase : public TargetInfo { static const Builtin::Info BuiltinInfo[]; std::string CPU; bool IsMips16; + bool IsMicromips; + bool IsSingleFloat; enum MipsFloatABI { - HardFloat, SingleFloat, SoftFloat + HardFloat, SoftFloat } FloatABI; enum DspRevEnum { NoDSP, DSP1, DSP2 @@ -4376,6 +4611,8 @@ public: : TargetInfo(triple), CPU(CPUStr), IsMips16(false), + IsMicromips(false), + IsSingleFloat(false), FloatABI(HardFloat), DspRev(NoDSP), ABI(ABIStr) @@ -4402,18 +4639,20 @@ public: case HardFloat: Builder.defineMacro("__mips_hard_float", Twine(1)); break; - case SingleFloat: - Builder.defineMacro("__mips_hard_float", Twine(1)); - Builder.defineMacro("__mips_single_float", Twine(1)); - break; case SoftFloat: Builder.defineMacro("__mips_soft_float", Twine(1)); break; } + if (IsSingleFloat) + Builder.defineMacro("__mips_single_float", Twine(1)); + if (IsMips16) Builder.defineMacro("__mips16", Twine(1)); + if (IsMicromips) + Builder.defineMacro("__mips_micromips", Twine(1)); + switch (DspRev) { default: break; @@ -4503,7 +4742,8 @@ public: Name == "o32" || Name == "n32" || Name == "n64" || Name == "eabi" || Name == "mips32" || Name == "mips32r2" || Name == "mips64" || Name == "mips64r2" || - Name == "mips16" || Name == "dsp" || Name == "dspr2") { + Name == "mips16" || Name == "micromips" || + Name == "dsp" || Name == "dspr2") { Features[Name] = Enabled; return true; } else if (Name == "32") { @@ -4518,17 +4758,21 @@ public: virtual void HandleTargetFeatures(std::vector<std::string> &Features) { IsMips16 = false; + IsMicromips = false; + IsSingleFloat = false; FloatABI = HardFloat; DspRev = NoDSP; for (std::vector<std::string>::iterator it = Features.begin(), ie = Features.end(); it != ie; ++it) { if (*it == "+single-float") - FloatABI = SingleFloat; + IsSingleFloat = true; else if (*it == "+soft-float") FloatABI = SoftFloat; else if (*it == "+mips16") IsMips16 = true; + else if (*it == "+micromips") + IsMicromips = true; else if (*it == "+dsp") DspRev = std::max(DspRev, DSP1); else if (*it == "+dspr2") @@ -4816,7 +5060,7 @@ public: this->SizeType = TargetInfo::UnsignedInt; this->PtrDiffType = TargetInfo::SignedInt; this->IntPtrType = TargetInfo::SignedInt; - this->RegParmMax = 2; + this->RegParmMax = 0; // Disallow regparm DescriptionString = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-" "f32:32:32-f64:64:64-p:32:32:32-v128:32:32"; } @@ -5142,6 +5386,32 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new SparcV8TargetInfo(T); } + case llvm::Triple::sparcv9: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SparcV9TargetInfo>(T); + case llvm::Triple::AuroraUX: + return new AuroraUXTargetInfo<SparcV9TargetInfo>(T); + case llvm::Triple::Solaris: + return new SolarisTargetInfo<SparcV9TargetInfo>(T); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<SparcV9TargetInfo>(T); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<SparcV9TargetInfo>(T); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<SparcV9TargetInfo>(T); + default: + return new SparcV9TargetInfo(T); + } + + case llvm::Triple::systemz: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SystemZTargetInfo>(T); + default: + return new SystemZTargetInfo(T); + } + case llvm::Triple::tce: return new TCETargetInfo(T); diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index cd8c10f215..e219a3def7 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -18,6 +18,10 @@ #include <cstdlib> #include <cstring> +#ifdef HAVE_SVN_VERSION_INC +# include "SVNVersion.inc" +#endif + namespace clang { std::string getClangRepositoryPath() { diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h index 35780f1556..df6dc7216a 100644 --- a/lib/CodeGen/ABIInfo.h +++ b/lib/CodeGen/ABIInfo.h @@ -22,6 +22,7 @@ namespace llvm { namespace clang { class ASTContext; + class TargetInfo; namespace CodeGen { class CGFunctionInfo; @@ -196,6 +197,7 @@ namespace clang { ASTContext &getContext() const; llvm::LLVMContext &getVMContext() const; const llvm::DataLayout &getDataLayout() const; + const TargetInfo &getTarget() const; /// Return the calling convention to use for system runtime /// functions. diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index ab65801ce5..45079c0989 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -302,14 +302,19 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) { // Set up the per-module pass manager. PassManager *MPM = getPerModulePasses(TM); - if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) { - MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes, - CodeGenOpts.EmitGcovArcs, - CodeGenOpts.CoverageVersion, - CodeGenOpts.CoverageExtraChecksum, - CodeGenOpts.DisableRedZone, - CodeGenOpts.CoverageFunctionNamesInData)); - + if (!CodeGenOpts.DisableGCov && + (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes)) { + // Not using 'GCOVOptions::getDefault' allows us to avoid exiting if + // LLVM's -default-gcov-version flag is set to something invalid. + GCOVOptions Options; + Options.EmitNotes = CodeGenOpts.EmitGcovNotes; + Options.EmitData = CodeGenOpts.EmitGcovArcs; + memcpy(Options.Version, CodeGenOpts.CoverageVersion, 4); + Options.UseCfgChecksum = CodeGenOpts.CoverageExtraChecksum; + Options.NoRedZone = CodeGenOpts.DisableRedZone; + Options.FunctionNamesInData = + !CodeGenOpts.CoverageNoFunctionNamesInData; + MPM->add(createGCOVProfilerPass(Options)); if (CodeGenOpts.getDebugInfo() == CodeGenOptions::NoDebugInfo) MPM->add(createStripSymbolsPass(true)); } @@ -452,6 +457,7 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) { Options.TrapFuncName = CodeGenOpts.TrapFuncName; Options.PositionIndependentExecutable = LangOpts.PIELevel != 0; Options.SSPBufferSize = CodeGenOpts.SSPBufferSize; + Options.EnableSegmentedStacks = CodeGenOpts.EnableSegmentedStacks; TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU, FeaturesStr, Options, @@ -522,6 +528,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) { Action != Backend_EmitBC && Action != Backend_EmitLL); TargetMachine *TM = CreateTargetMachine(UsesCodeGen); + if (UsesCodeGen && !TM) return; CreatePasses(TM); switch (Action) { diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp index 817d5c4cc6..0b48a5c664 100644 --- a/lib/CodeGen/CGAtomic.cpp +++ b/lib/CodeGen/CGAtomic.cpp @@ -327,7 +327,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy); unsigned Align = alignChars.getQuantity(); unsigned MaxInlineWidthInBits = - getContext().getTargetInfo().getMaxAtomicInlineWidth(); + getTarget().getMaxAtomicInlineWidth(); bool UseLibcall = (Size != Align || getContext().toBits(sizeChars) > MaxInlineWidthInBits); @@ -483,15 +483,6 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { Args.add(RValue::get(EmitCastToVoidPtr(Dest)), getContext().VoidPtrTy); break; -#if 0 - // These are only defined for 1-16 byte integers. It is not clear what - // their semantics would be on anything else... - case AtomicExpr::Add: LibCallName = "__atomic_fetch_add_generic"; break; - case AtomicExpr::Sub: LibCallName = "__atomic_fetch_sub_generic"; break; - case AtomicExpr::And: LibCallName = "__atomic_fetch_and_generic"; break; - case AtomicExpr::Or: LibCallName = "__atomic_fetch_or_generic"; break; - case AtomicExpr::Xor: LibCallName = "__atomic_fetch_xor_generic"; break; -#endif default: return EmitUnsupportedRValue(E, "atomic library call"); } // order is always the last parameter diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index b9f466117c..ded019e64a 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -695,8 +695,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda(); llvm::Constant *blockFn = CodeGenFunction(CGM, true).GenerateBlockFunction(CurGD, blockInfo, - CurFuncDecl, LocalDeclMap, - isLambdaConv); + LocalDeclMap, + isLambdaConv); blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy); // If there is nothing to capture, we can emit this as a global block. @@ -753,6 +753,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { if (capture.isConstant()) continue; QualType type = variable->getType(); + CharUnits align = getContext().getDeclAlign(variable); // This will be a [[type]]*, except that a byref entry will just be // an i8**. @@ -796,21 +797,21 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { if (ci->isByRef()) { // Get a void* that points to the byref struct. if (ci->isNested()) - src = Builder.CreateLoad(src, "byref.capture"); + src = Builder.CreateAlignedLoad(src, align.getQuantity(), + "byref.capture"); else src = Builder.CreateBitCast(src, VoidPtrTy); // Write that void* into the capture field. - Builder.CreateStore(src, blockField); + Builder.CreateAlignedStore(src, blockField, align.getQuantity()); // If we have a copy constructor, evaluate that into the block field. } else if (const Expr *copyExpr = ci->getCopyExpr()) { if (blockDecl->isConversionFromLambda()) { // If we have a lambda conversion, emit the expression // directly into the block instead. - CharUnits Align = getContext().getTypeAlignInChars(type); AggValueSlot Slot = - AggValueSlot::forAddr(blockField, Align, Qualifiers(), + AggValueSlot::forAddr(blockField, align, Qualifiers(), AggValueSlot::IsDestructed, AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased); @@ -821,7 +822,27 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { // If it's a reference variable, copy the reference into the block field. } else if (type->isReferenceType()) { - Builder.CreateStore(Builder.CreateLoad(src, "ref.val"), blockField); + llvm::Value *ref = + Builder.CreateAlignedLoad(src, align.getQuantity(), "ref.val"); + Builder.CreateAlignedStore(ref, blockField, align.getQuantity()); + + // If this is an ARC __strong block-pointer variable, don't do a + // block copy. + // + // TODO: this can be generalized into the normal initialization logic: + // we should never need to do a block-copy when initializing a local + // variable, because the local variable's lifetime should be strictly + // contained within the stack block's. + } else if (type.getObjCLifetime() == Qualifiers::OCL_Strong && + type->isBlockPointerType()) { + // Load the block and do a simple retain. + LValue srcLV = MakeAddrLValue(src, type, align); + llvm::Value *value = EmitLoadOfScalar(srcLV); + value = EmitARCRetainNonBlock(value); + + // Do a primitive store to the block field. + LValue destLV = MakeAddrLValue(blockField, type, align); + EmitStoreOfScalar(value, destLV, /*init*/ true); // Otherwise, fake up a POD copy into the block field. } else { @@ -839,8 +860,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue, &declRef, VK_RValue); EmitExprAsInit(&l2r, &blockFieldPseudoVar, - MakeAddrLValue(blockField, type, - getContext().getDeclAlign(variable)), + MakeAddrLValue(blockField, type, align), /*captured by init*/ false); } @@ -1014,7 +1034,7 @@ CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *blockExpr, llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; blockFn = CodeGenFunction(*this).GenerateBlockFunction(GlobalDecl(), blockInfo, - 0, LocalDeclMap, + LocalDeclMap, false); } blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy); @@ -1068,7 +1088,6 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, llvm::Function * CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const CGBlockInfo &blockInfo, - const Decl *outerFnDecl, const DeclMapTy &ldm, bool IsLambdaConversionToBlock) { const BlockDecl *blockDecl = blockInfo.getBlockDecl(); @@ -1128,7 +1147,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, // Begin generating the function. StartFunction(blockDecl, fnType->getResultType(), fn, fnInfo, args, blockInfo.getBlockExpr()->getBody()->getLocStart()); - CurFuncDecl = outerFnDecl; // StartFunction sets this to blockDecl // Okay. Undo some of what StartFunction did. @@ -1138,6 +1156,22 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, BlockPointer = Builder.CreateBitCast(blockAddr, blockInfo.StructureType->getPointerTo(), "block"); + // At -O0 we generate an explicit alloca for the BlockPointer, so the RA + // won't delete the dbg.declare intrinsics for captured variables. + llvm::Value *BlockPointerDbgLoc = BlockPointer; + if (CGM.getCodeGenOpts().OptimizationLevel == 0) { + // Allocate a stack slot for it, so we can point the debugger to it + llvm::AllocaInst *Alloca = CreateTempAlloca(BlockPointer->getType(), + "block.addr"); + unsigned Align = getContext().getDeclAlign(&selfDecl).getQuantity(); + Alloca->setAlignment(Align); + // Set the DebugLocation to empty, so the store is recognized as a + // frame setup instruction by llvm::DwarfDebug::beginFunction(). + Builder.DisableDebugLocations(); + Builder.CreateAlignedStore(BlockPointer, Alloca, Align); + Builder.EnableDebugLocations(); + BlockPointerDbgLoc = Alloca; + } // If we have a C++ 'this' reference, go ahead and force it into // existence now. @@ -1148,22 +1182,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, CXXThisValue = Builder.CreateLoad(addr, "this"); } - // LoadObjCSelf() expects there to be an entry for 'self' in LocalDeclMap; - // appease it. - if (const ObjCMethodDecl *method - = dyn_cast_or_null<ObjCMethodDecl>(CurFuncDecl)) { - const VarDecl *self = method->getSelfDecl(); - - // There might not be a capture for 'self', but if there is... - if (blockInfo.Captures.count(self)) { - const CGBlockInfo::Capture &capture = blockInfo.getCapture(self); - llvm::Value *selfAddr = Builder.CreateStructGEP(BlockPointer, - capture.getIndex(), - "block.captured-self"); - LocalDeclMap[self] = selfAddr; - } - } - // Also force all the constant captures. for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(), ce = blockDecl->capture_end(); ci != ce; ++ci) { @@ -1177,7 +1195,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, CreateMemTemp(variable->getType(), "block.captured-const"); alloca->setAlignment(align); - Builder.CreateStore(capture.getConstant(), alloca, align); + Builder.CreateAlignedStore(capture.getConstant(), alloca, align); LocalDeclMap[variable] = alloca; } @@ -1216,13 +1234,13 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, continue; } - DI->EmitDeclareOfBlockDeclRefVariable(variable, BlockPointer, + DI->EmitDeclareOfBlockDeclRefVariable(variable, BlockPointerDbgLoc, Builder, blockInfo); } } // Recover location if it was changed in the above loop. DI->EmitLocation(Builder, - cast<CompoundStmt>(blockDecl->getBody())->getRBracLoc()); + cast<CompoundStmt>(blockDecl->getBody())->getRBracLoc()); } // And resume where we left off. @@ -1297,7 +1315,6 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { SourceLocation(), SourceLocation(), II, C.VoidTy, 0, SC_Static, - SC_None, false, false); StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation()); @@ -1472,7 +1489,6 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { SourceLocation(), SourceLocation(), II, C.VoidTy, 0, SC_Static, - SC_None, false, false); StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation()); @@ -1547,7 +1563,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { // Destroy strong objects with a call if requested. } else if (useARCStrongDestroy) { - EmitARCDestroyStrong(srcField, /*precise*/ false); + EmitARCDestroyStrong(srcField, ARCImpreciseLifetime); // Otherwise we call _Block_object_dispose. It wouldn't be too // hard to just emit this as a cleanup if we wanted to make sure @@ -1656,7 +1672,7 @@ public: } void emitDispose(CodeGenFunction &CGF, llvm::Value *field) { - CGF.EmitARCDestroyStrong(field, /*precise*/ false); + CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime); } void profileImpl(llvm::FoldingSetNodeID &id) const { @@ -1686,7 +1702,7 @@ public: } void emitDispose(CodeGenFunction &CGF, llvm::Value *field) { - CGF.EmitARCDestroyStrong(field, /*precise*/ false); + CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime); } void profileImpl(llvm::FoldingSetNodeID &id) const { @@ -1763,7 +1779,6 @@ generateByrefCopyHelper(CodeGenFunction &CGF, SourceLocation(), SourceLocation(), II, R, 0, SC_Static, - SC_None, false, false); // Initialize debug info if necessary. @@ -1838,7 +1853,6 @@ generateByrefDisposeHelper(CodeGenFunction &CGF, SourceLocation(), SourceLocation(), II, R, 0, SC_Static, - SC_None, false, false); // Initialize debug info if necessary. CGF.maybeInitializeDebugInfo(); @@ -2047,7 +2061,8 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { bool Packed = false; CharUnits Align = getContext().getDeclAlign(D); - if (Align > getContext().toCharUnitsFromBits(Target.getPointerAlign(0))) { + if (Align > + getContext().toCharUnitsFromBits(getTarget().getPointerAlign(0))) { // We have to insert padding. // The struct above has 2 32-bit integers. diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index e9c1431d30..a655966d6e 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -296,7 +296,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType); llvm::Type *ResultType = ConvertType(E->getType()); - Value *ZeroUndef = Builder.getInt1(Target.isCLZForZeroUndef()); + Value *ZeroUndef = Builder.getInt1(getTarget().isCLZForZeroUndef()); Value *Result = Builder.CreateCall2(F, ArgValue, ZeroUndef); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, @@ -313,7 +313,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType); llvm::Type *ResultType = ConvertType(E->getType()); - Value *ZeroUndef = Builder.getInt1(Target.isCLZForZeroUndef()); + Value *ZeroUndef = Builder.getInt1(getTarget().isCLZForZeroUndef()); Value *Result = Builder.CreateCall2(F, ArgValue, ZeroUndef); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, @@ -1434,7 +1434,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, const char *Name = getContext().BuiltinInfo.GetName(BuiltinID); Intrinsic::ID IntrinsicID = Intrinsic::not_intrinsic; if (const char *Prefix = - llvm::Triple::getArchTypePrefix(Target.getTriple().getArch())) + llvm::Triple::getArchTypePrefix(getTarget().getTriple().getArch())) IntrinsicID = Intrinsic::getIntrinsicForGCCBuiltin(Prefix, Name); if (IntrinsicID != Intrinsic::not_intrinsic) { @@ -1505,7 +1505,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { - switch (Target.getTriple().getArch()) { + switch (getTarget().getTriple().getArch()) { + case llvm::Triple::aarch64: + return EmitAArch64BuiltinExpr(BuiltinID, E); case llvm::Triple::arm: case llvm::Triple::thumb: return EmitARMBuiltinExpr(BuiltinID, E); @@ -1625,6 +1627,25 @@ CodeGenFunction::EmitPointerWithAlignment(const Expr *Addr) { return std::make_pair(EmitScalarExpr(Addr), Align); } +Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, + const CallExpr *E) { + if (BuiltinID == AArch64::BI__clear_cache) { + assert(E->getNumArgs() == 2 && + "Variadic __clear_cache slipped through on AArch64"); + + const FunctionDecl *FD = E->getDirectCallee(); + SmallVector<Value *, 2> Ops; + for (unsigned i = 0; i < E->getNumArgs(); i++) + Ops.push_back(EmitScalarExpr(E->getArg(i))); + llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType()); + llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty); + StringRef Name = FD->getName(); + return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops); + } + + return 0; +} + Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { if (BuiltinID == ARM::BI__clear_cache) { @@ -1856,7 +1877,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, // Generate target-independent intrinsic; also need to add second argument // for whether or not clz of zero is undefined; on ARM it isn't. Function *F = CGM.getIntrinsic(Intrinsic::ctlz, Ty); - Ops.push_back(Builder.getInt1(Target.isCLZForZeroUndef())); + Ops.push_back(Builder.getInt1(getTarget().isCLZForZeroUndef())); return EmitNeonCall(F, Ops, "vclz"); } case ARM::BI__builtin_neon_vcnt_v: @@ -2713,7 +2734,10 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, } case X86::BI__builtin_ia32_rdrand16_step: case X86::BI__builtin_ia32_rdrand32_step: - case X86::BI__builtin_ia32_rdrand64_step: { + case X86::BI__builtin_ia32_rdrand64_step: + case X86::BI__builtin_ia32_rdseed16_step: + case X86::BI__builtin_ia32_rdseed32_step: + case X86::BI__builtin_ia32_rdseed64_step: { Intrinsic::ID ID; switch (BuiltinID) { default: llvm_unreachable("Unsupported intrinsic!"); @@ -2726,6 +2750,15 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_rdrand64_step: ID = Intrinsic::x86_rdrand_64; break; + case X86::BI__builtin_ia32_rdseed16_step: + ID = Intrinsic::x86_rdseed_16; + break; + case X86::BI__builtin_ia32_rdseed32_step: + ID = Intrinsic::x86_rdseed_32; + break; + case X86::BI__builtin_ia32_rdseed64_step: + ID = Intrinsic::x86_rdseed_64; + break; } Value *Call = Builder.CreateCall(CGM.getIntrinsic(ID)); diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index f9fea57ea6..68fecb2d0c 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -19,8 +19,7 @@ using namespace CodeGen; CGCXXABI::~CGCXXABI() { } -static void ErrorUnsupportedABI(CodeGenFunction &CGF, - StringRef S) { +void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) { DiagnosticsEngine &Diags = CGF.CGM.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot yet compile %0 in this ABI"); @@ -29,8 +28,7 @@ static void ErrorUnsupportedABI(CodeGenFunction &CGF, << S; } -static llvm::Constant *GetBogusMemberPointer(CodeGenModule &CGM, - QualType T) { +llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) { return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T)); } @@ -67,12 +65,12 @@ llvm::Value *CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, const CastExpr *E, llvm::Value *Src) { ErrorUnsupportedABI(CGF, "member function pointer conversions"); - return GetBogusMemberPointer(CGM, E->getType()); + return GetBogusMemberPointer(E->getType()); } llvm::Constant *CGCXXABI::EmitMemberPointerConversion(const CastExpr *E, llvm::Constant *Src) { - return GetBogusMemberPointer(CGM, E->getType()); + return GetBogusMemberPointer(E->getType()); } llvm::Value * @@ -95,22 +93,22 @@ CGCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, llvm::Constant * CGCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { - return GetBogusMemberPointer(CGM, QualType(MPT, 0)); + return GetBogusMemberPointer(QualType(MPT, 0)); } llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { - return GetBogusMemberPointer(CGM, + return GetBogusMemberPointer( CGM.getContext().getMemberPointerType(MD->getType(), MD->getParent()->getTypeForDecl())); } llvm::Constant *CGCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, CharUnits offset) { - return GetBogusMemberPointer(CGM, QualType(MPT, 0)); + return GetBogusMemberPointer(QualType(MPT, 0)); } llvm::Constant *CGCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) { - return GetBogusMemberPointer(CGM, MPT); + return GetBogusMemberPointer(MPT); } bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) { @@ -222,8 +220,12 @@ void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF, } void CGCXXABI::registerGlobalDtor(CodeGenFunction &CGF, + const VarDecl &D, llvm::Constant *dtor, llvm::Constant *addr) { + if (D.getTLSKind()) + CGM.ErrorUnsupported(&D, "non-trivial TLS destruction"); + // The default behavior is to use atexit. CGF.registerGlobalDtorWithAtExit(dtor, addr); } @@ -257,3 +259,14 @@ llvm::BasicBlock *CGCXXABI::EmitCtorCompleteObjectHandler( ErrorUnsupportedABI(CGF, "complete object detection in ctor"); return 0; } + +void CGCXXABI::EmitThreadLocalInitFuncs( + llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls, + llvm::Function *InitFunc) { +} + +LValue CGCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, + const DeclRefExpr *DRE) { + ErrorUnsupportedABI(CGF, "odr-use of thread_local global"); + return LValue(); +} diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index cdc87b70e5..1e4da631d6 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -54,6 +54,12 @@ protected: return CGF.CXXABIThisValue; } + /// Issue a diagnostic about unsupported features in the ABI. + void ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S); + + /// Get a null value for unsupported member pointers. + llvm::Constant *GetBogusMemberPointer(QualType T); + // FIXME: Every place that calls getVTT{Decl,Value} is something // that needs to be abstracted properly. ImplicitParamDecl *&getVTTDecl(CodeGenFunction &CGF) { @@ -91,6 +97,31 @@ public: return *MangleCtx; } + /// Returns true if the given instance method is one of the + /// kinds that the ABI says returns 'this'. + virtual bool HasThisReturn(GlobalDecl GD) const { return false; } + + /// Returns true if the given record type should be returned indirectly. + virtual bool isReturnTypeIndirect(const CXXRecordDecl *RD) const = 0; + + /// Specify how one should pass an argument of a record type. + enum RecordArgABI { + /// Pass it using the normal C aggregate rules for the ABI, potentially + /// introducing extra copies and passing some or all of it in registers. + RAA_Default = 0, + + /// Pass it on the stack using its defined layout. The argument must be + /// evaluated directly into the correct stack position in the arguments area, + /// and the call machinery must not move it or introduce extra copies. + RAA_DirectInMemory, + + /// Pass it as a pointer to temporary memory. + RAA_Indirect + }; + + /// Returns how an argument of the given record type should be passed. + virtual RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const = 0; + /// Find the LLVM type used to represent the given member pointer /// type. virtual llvm::Type * @@ -209,7 +240,8 @@ public: /// Emit the ABI-specific prolog for the function. virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0; - virtual void EmitConstructorCall(CodeGenFunction &CGF, + /// Emit the constructor call. Return the function that is called. + virtual llvm::Value *EmitConstructorCall(CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, bool Delegating, @@ -319,8 +351,27 @@ public: /// /// \param dtor - a function taking a single pointer argument /// \param addr - a pointer to pass to the destructor function. - virtual void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor, - llvm::Constant *addr); + virtual void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, + llvm::Constant *dtor, llvm::Constant *addr); + + /*************************** thread_local initialization ********************/ + + /// Emits ABI-required functions necessary to initialize thread_local + /// variables in this translation unit. + /// + /// \param Decls The thread_local declarations in this translation unit. + /// \param InitFunc If this translation unit contains any non-constant + /// initialization or non-trivial destruction for thread_local + /// variables, a function to perform the initialization. Otherwise, 0. + virtual void EmitThreadLocalInitFuncs( + llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls, + llvm::Function *InitFunc); + + /// Emit a reference to a non-local thread_local variable (including + /// triggering the initialization of all thread_local variables in its + /// translation unit). + virtual LValue EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, + const DeclRefExpr *DRE); }; // Create an instance of a C++ ABI class: diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index fa5ce7fdca..b0f460ec0e 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -77,9 +77,7 @@ CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> FTNP) { // When translating an unprototyped function type, always use a // variadic type. return arrangeLLVMFunctionInfo(FTNP->getResultType().getUnqualifiedType(), - ArrayRef<CanQualType>(), - FTNP->getExtInfo(), - RequiredArgs(0)); + None, FTNP->getExtInfo(), RequiredArgs(0)); } /// Arrange the LLVM function layout for a value of the given function @@ -257,10 +255,8 @@ CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) { // non-variadic type. if (isa<FunctionNoProtoType>(FTy)) { CanQual<FunctionNoProtoType> noProto = FTy.getAs<FunctionNoProtoType>(); - return arrangeLLVMFunctionInfo(noProto->getResultType(), - ArrayRef<CanQualType>(), - noProto->getExtInfo(), - RequiredArgs::All); + return arrangeLLVMFunctionInfo(noProto->getResultType(), None, + noProto->getExtInfo(), RequiredArgs::All); } assert(isa<FunctionProtoType>(FTy)); @@ -420,7 +416,7 @@ CodeGenTypes::arrangeFunctionDeclaration(QualType resultType, } const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() { - return arrangeLLVMFunctionInfo(getContext().VoidTy, ArrayRef<CanQualType>(), + return arrangeLLVMFunctionInfo(getContext().VoidTy, None, FunctionType::ExtInfo(), RequiredArgs::All); } @@ -837,12 +833,11 @@ bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) { default: return false; case BuiltinType::Float: - return getContext().getTargetInfo().useObjCFPRetForRealType(TargetInfo::Float); + return getTarget().useObjCFPRetForRealType(TargetInfo::Float); case BuiltinType::Double: - return getContext().getTargetInfo().useObjCFPRetForRealType(TargetInfo::Double); + return getTarget().useObjCFPRetForRealType(TargetInfo::Double); case BuiltinType::LongDouble: - return getContext().getTargetInfo().useObjCFPRetForRealType( - TargetInfo::LongDouble); + return getTarget().useObjCFPRetForRealType(TargetInfo::LongDouble); } } @@ -853,7 +848,7 @@ bool CodeGenModule::ReturnTypeUsesFP2Ret(QualType ResultType) { if (const ComplexType *CT = ResultType->getAs<ComplexType>()) { if (const BuiltinType *BT = CT->getElementType()->getAs<BuiltinType>()) { if (BT->getKind() == BuiltinType::LongDouble) - return getContext().getTargetInfo().useObjCFP2RetForComplexLongDouble(); + return getTarget().useObjCFP2RetForComplexLongDouble(); } } @@ -1027,63 +1022,27 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, FuncAttrs.addAttribute(llvm::Attribute::NoBuiltin); } else { // Attributes that should go on the function, but not the call site. - if (!CodeGenOpts.CodeModel.empty()) - FuncAttrs.addAttribute("code-model", CodeGenOpts.CodeModel); - if (!CodeGenOpts.RelocationModel.empty()) - FuncAttrs.addAttribute("relocation-model", CodeGenOpts.RelocationModel); - - if (CodeGenOpts.FloatABI == "soft" || CodeGenOpts.FloatABI == "softfp") - FuncAttrs.addAttribute("float-abi", "soft"); - else if (CodeGenOpts.FloatABI == "hard") - FuncAttrs.addAttribute("float-abi", "hard"); - if (!CodeGenOpts.DisableFPElim) { - /* ignore */ ; + FuncAttrs.addAttribute("no-frame-pointer-elim", "false"); + FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf", "false"); } else if (CodeGenOpts.OmitLeafFramePointer) { - FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf"); + FuncAttrs.addAttribute("no-frame-pointer-elim", "false"); + FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf", "true"); } else { - FuncAttrs.addAttribute("no-frame-pointer-elim"); - FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf"); + FuncAttrs.addAttribute("no-frame-pointer-elim", "true"); + FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf", "true"); } - switch (CodeGenOpts.getFPContractMode()) { - case CodeGenOptions::FPC_Off: - FuncAttrs.addAttribute("fp-contract-model", "strict"); - break; - case CodeGenOptions::FPC_On: - FuncAttrs.addAttribute("fp-contract-model", "standard"); - break; - case CodeGenOptions::FPC_Fast: - FuncAttrs.addAttribute("fp-contract-model", "fast"); - break; - } - - if (CodeGenOpts.LessPreciseFPMAD) - FuncAttrs.addAttribute("less-precise-fpmad"); - if (CodeGenOpts.NoInfsFPMath) - FuncAttrs.addAttribute("no-infs-fp-math"); - if (CodeGenOpts.NoNaNsFPMath) - FuncAttrs.addAttribute("no-nans-fp-math"); - if (CodeGenOpts.NoZeroInitializedInBSS) - FuncAttrs.addAttribute("no-zero-init-in-bss"); - if (CodeGenOpts.UnsafeFPMath) - FuncAttrs.addAttribute("unsafe-fp-math"); - if (CodeGenOpts.SoftFloat) - FuncAttrs.addAttribute("use-soft-float"); - if (CodeGenOpts.StackAlignment) - FuncAttrs.addAttribute("stack-align-override", - llvm::utostr(CodeGenOpts.StackAlignment)); - if (CodeGenOpts.StackRealignment) - FuncAttrs.addAttribute("realign-stack"); - if (CodeGenOpts.DisableTailCalls) - FuncAttrs.addAttribute("disable-tail-calls"); - if (!CodeGenOpts.TrapFuncName.empty()) - FuncAttrs.addAttribute("trap-func-name", CodeGenOpts.TrapFuncName); - if (LangOpts.PIELevel != 0) - FuncAttrs.addAttribute("pie"); - if (CodeGenOpts.SSPBufferSize) - FuncAttrs.addAttribute("ssp-buffers-size", - llvm::utostr(CodeGenOpts.SSPBufferSize)); + FuncAttrs.addAttribute("less-precise-fpmad", + CodeGenOpts.LessPreciseFPMAD ? "true" : "false"); + FuncAttrs.addAttribute("no-infs-fp-math", + CodeGenOpts.NoInfsFPMath ? "true" : "false"); + FuncAttrs.addAttribute("no-nans-fp-math", + CodeGenOpts.NoNaNsFPMath ? "true" : "false"); + FuncAttrs.addAttribute("unsafe-fp-math", + CodeGenOpts.UnsafeFPMath ? "true" : "false"); + FuncAttrs.addAttribute("use-soft-float", + CodeGenOpts.SoftFloat ? "true" : "false"); } QualType RetTy = FI.getReturnType(); @@ -1233,7 +1192,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // initialize the return value. TODO: it might be nice to have // a more general mechanism for this that didn't require synthesized // return statements. - if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) { + if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl)) { if (FD->hasImplicitReturnZero()) { QualType RetTy = FD->getResultType().getUnqualifiedType(); llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy); @@ -1650,7 +1609,20 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) { return store; } -void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) { +/// Check whether 'this' argument of a callsite matches 'this' of the caller. +static bool checkThisPointer(llvm::Value *ThisArg, llvm::Value *This) { + if (ThisArg == This) + return true; + // Check whether ThisArg is a bitcast of This. + llvm::BitCastInst *Bitcast; + if ((Bitcast = dyn_cast<llvm::BitCastInst>(ThisArg)) && + Bitcast->getOperand(0) == This) + return true; + return false; +} + +void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, + bool EmitRetDbgLoc) { // Functions with no result always return void. if (ReturnValue == 0) { Builder.CreateRetVoid(); @@ -1695,8 +1667,10 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) { // If there is a dominating store to ReturnValue, we can elide // the load, zap the store, and usually zap the alloca. if (llvm::StoreInst *SI = findDominatingStoreToReturnValue(*this)) { + // Reuse the debug location from the store unless we're told not to. + if (EmitRetDbgLoc) + RetDbgLoc = SI->getDebugLoc(); // Get the stored value and nuke the now-dead store. - RetDbgLoc = SI->getDebugLoc(); RV = SI->getValueOperand(); SI->eraseFromParent(); @@ -1741,6 +1715,19 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) { llvm_unreachable("Invalid ABI kind for return argument"); } + // If this function returns 'this', the last instruction is a CallInst + // that returns 'this', and 'this' argument of the CallInst points to + // the same object as CXXThisValue, use the return value from the CallInst. + // We will not need to keep 'this' alive through the callsite. It also enables + // optimizations in the backend, such as tail call optimization. + if (CalleeWithThisReturn && CGM.getCXXABI().HasThisReturn(CurGD)) { + llvm::BasicBlock *IP = Builder.GetInsertBlock(); + llvm::CallInst *Callsite; + if (!IP->empty() && (Callsite = dyn_cast<llvm::CallInst>(&IP->back())) && + Callsite->getCalledFunction() == CalleeWithThisReturn && + checkThisPointer(Callsite->getOperand(0), CXXThisValue)) + RV = Builder.CreateBitCast(Callsite, RetAI.getCoerceToType()); + } llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid(); if (!RetDbgLoc.isUnknown()) Ret->setDebugLoc(RetDbgLoc); @@ -1782,7 +1769,8 @@ static bool isProvablyNonNull(llvm::Value *addr) { /// Emit the actual writing-back of a writeback. static void emitWriteback(CodeGenFunction &CGF, const CallArgList::Writeback &writeback) { - llvm::Value *srcAddr = writeback.Address; + const LValue &srcLV = writeback.Source; + llvm::Value *srcAddr = srcLV.getAddress(); assert(!isProvablyNull(srcAddr) && "shouldn't have writeback for provably null argument"); @@ -1809,9 +1797,35 @@ static void emitWriteback(CodeGenFunction &CGF, "icr.writeback-cast"); // Perform the writeback. - QualType srcAddrType = writeback.AddressType; - CGF.EmitStoreThroughLValue(RValue::get(value), - CGF.MakeAddrLValue(srcAddr, srcAddrType)); + + // If we have a "to use" value, it's something we need to emit a use + // of. This has to be carefully threaded in: if it's done after the + // release it's potentially undefined behavior (and the optimizer + // will ignore it), and if it happens before the retain then the + // optimizer could move the release there. + if (writeback.ToUse) { + assert(srcLV.getObjCLifetime() == Qualifiers::OCL_Strong); + + // Retain the new value. No need to block-copy here: the block's + // being passed up the stack. + value = CGF.EmitARCRetainNonBlock(value); + + // Emit the intrinsic use here. + CGF.EmitARCIntrinsicUse(writeback.ToUse); + + // Load the old value (primitively). + llvm::Value *oldValue = CGF.EmitLoadOfScalar(srcLV); + + // Put the new value in place (primitively). + CGF.EmitStoreOfScalar(value, srcLV, /*init*/ false); + + // Release the old value. + CGF.EmitARCRelease(oldValue, srcLV.isARCPreciseLifetime()); + + // Otherwise, we can just do a normal lvalue store. + } else { + CGF.EmitStoreThroughLValue(RValue::get(value), srcLV); + } // Jump to the continuation block. if (!provablyNonNull) @@ -1825,11 +1839,33 @@ static void emitWritebacks(CodeGenFunction &CGF, emitWriteback(CGF, *i); } +static const Expr *maybeGetUnaryAddrOfOperand(const Expr *E) { + if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E->IgnoreParens())) + if (uop->getOpcode() == UO_AddrOf) + return uop->getSubExpr(); + return 0; +} + /// Emit an argument that's being passed call-by-writeback. That is, /// we are passing the address of static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, const ObjCIndirectCopyRestoreExpr *CRE) { - llvm::Value *srcAddr = CGF.EmitScalarExpr(CRE->getSubExpr()); + LValue srcLV; + + // Make an optimistic effort to emit the address as an l-value. + // This can fail if the the argument expression is more complicated. + if (const Expr *lvExpr = maybeGetUnaryAddrOfOperand(CRE->getSubExpr())) { + srcLV = CGF.EmitLValue(lvExpr); + + // Otherwise, just emit it as a scalar. + } else { + llvm::Value *srcAddr = CGF.EmitScalarExpr(CRE->getSubExpr()); + + QualType srcAddrType = + CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType(); + srcLV = CGF.MakeNaturalAlignAddrLValue(srcAddr, srcAddrType); + } + llvm::Value *srcAddr = srcLV.getAddress(); // The dest and src types don't necessarily match in LLVM terms // because of the crazy ObjC compatibility rules. @@ -1844,9 +1880,6 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, return; } - QualType srcAddrType = - CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType(); - // Create the temporary. llvm::Value *temp = CGF.CreateTempAlloca(destType->getElementType(), "icr.temp"); @@ -1866,6 +1899,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, } llvm::BasicBlock *contBB = 0; + llvm::BasicBlock *originBB = 0; // If the address is *not* known to be non-null, we need to switch. llvm::Value *finalArgument; @@ -1883,6 +1917,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, // If we need to copy, then the load has to be conditional, which // means we need control flow. if (shouldCopy) { + originBB = CGF.Builder.GetInsertBlock(); contBB = CGF.createBasicBlock("icr.cont"); llvm::BasicBlock *copyBB = CGF.createBasicBlock("icr.copy"); CGF.Builder.CreateCondBr(isNull, contBB, copyBB); @@ -1891,9 +1926,10 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, } } + llvm::Value *valueToUse = 0; + // Perform a copy if necessary. if (shouldCopy) { - LValue srcLV = CGF.MakeAddrLValue(srcAddr, srcAddrType); RValue srcRV = CGF.EmitLoadOfLValue(srcLV); assert(srcRV.isScalar()); @@ -1903,15 +1939,37 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, // Use an ordinary store, not a store-to-lvalue. CGF.Builder.CreateStore(src, temp); + + // If optimization is enabled, and the value was held in a + // __strong variable, we need to tell the optimizer that this + // value has to stay alive until we're doing the store back. + // This is because the temporary is effectively unretained, + // and so otherwise we can violate the high-level semantics. + if (CGF.CGM.getCodeGenOpts().OptimizationLevel != 0 && + srcLV.getObjCLifetime() == Qualifiers::OCL_Strong) { + valueToUse = src; + } } // Finish the control flow if we needed it. if (shouldCopy && !provablyNonNull) { + llvm::BasicBlock *copyBB = CGF.Builder.GetInsertBlock(); CGF.EmitBlock(contBB); + + // Make a phi for the value to intrinsically use. + if (valueToUse) { + llvm::PHINode *phiToUse = CGF.Builder.CreatePHI(valueToUse->getType(), 2, + "icr.to-use"); + phiToUse->addIncoming(valueToUse, copyBB); + phiToUse->addIncoming(llvm::UndefValue::get(valueToUse->getType()), + originBB); + valueToUse = phiToUse; + } + condEval.end(CGF); } - args.addWriteback(srcAddr, srcAddrType, temp); + args.addWriteback(srcLV, temp, valueToUse); args.add(RValue::get(finalArgument), CRE->getType()); } diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h index 0b68617f3d..85c3320ec0 100644 --- a/lib/CodeGen/CGCall.h +++ b/lib/CodeGen/CGCall.h @@ -56,14 +56,15 @@ namespace CodeGen { public SmallVector<CallArg, 16> { public: struct Writeback { - /// The original argument. - llvm::Value *Address; - - /// The pointee type of the original argument. - QualType AddressType; + /// The original argument. Note that the argument l-value + /// is potentially null. + LValue Source; /// The temporary alloca. llvm::Value *Temporary; + + /// A value to "use" after the writeback, or null. + llvm::Value *ToUse; }; void add(RValue rvalue, QualType type, bool needscopy = false) { @@ -76,12 +77,12 @@ namespace CodeGen { other.Writebacks.begin(), other.Writebacks.end()); } - void addWriteback(llvm::Value *address, QualType addressType, - llvm::Value *temporary) { + void addWriteback(LValue srcLV, llvm::Value *temporary, + llvm::Value *toUse) { Writeback writeback; - writeback.Address = address; - writeback.AddressType = addressType; + writeback.Source = srcLV; writeback.Temporary = temporary; + writeback.ToUse = toUse; Writebacks.push_back(writeback); } diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 287d164cb9..3fd075701d 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -290,7 +290,7 @@ llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD, return 0; } - const CXXRecordDecl *RD = cast<CXXMethodDecl>(CurFuncDecl)->getParent(); + const CXXRecordDecl *RD = cast<CXXMethodDecl>(CurCodeDecl)->getParent(); const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent(); llvm::Value *VTT; @@ -710,7 +710,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { // Before we go any further, try the complete->base constructor // delegation optimization. if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) && - CGM.getContext().getTargetInfo().getCXXABI().hasConstructorVariants()) { + CGM.getTarget().getCXXABI().hasConstructorVariants()) { if (CGDebugInfo *DI = getDebugInfo()) DI->EmitLocation(Builder, Ctor->getLocEnd()); EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args); @@ -1139,6 +1139,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, InitializeVTablePointers(ClassDecl); // And finally, initialize class members. + FieldConstructionScope FCS(*this, CXXThisValue); ConstructorMemcpyizer CM(*this, CD, Args); for (; B != E; B++) { CXXCtorInitializer *Member = (*B); @@ -1278,7 +1279,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { EnterDtorCleanups(Dtor, Dtor_Complete); if (!isTryBody && - CGM.getContext().getTargetInfo().getCXXABI().hasDestructorVariants()) { + CGM.getTarget().getCXXABI().hasDestructorVariants()) { EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false, /*Delegating=*/false, LoadCXXThis()); break; @@ -1666,8 +1667,11 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, } // Non-trivial constructors are handled in an ABI-specific manner. - CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase, - Delegating, This, ArgBeg, ArgEnd); + llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type, + ForVirtualBase, Delegating, This, ArgBeg, ArgEnd); + if (CGM.getCXXABI().HasThisReturn(CurGD) && + CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type))) + CalleeWithThisReturn = Callee; } void @@ -1756,9 +1760,12 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, EmitDelegateCallArg(DelegateArgs, param); } + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType); EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType), - CGM.GetAddrOfCXXConstructor(Ctor, CtorType), - ReturnValueSlot(), DelegateArgs, Ctor); + Callee, ReturnValueSlot(), DelegateArgs, Ctor); + if (CGM.getCXXABI().HasThisReturn(CurGD) && + CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType))) + CalleeWithThisReturn = Callee; } namespace { @@ -1825,6 +1832,9 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This, VTT, getContext().getPointerType(getContext().VoidPtrTy), 0, 0); + if (CGM.getCXXABI().HasThisReturn(CurGD) && + CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type))) + CalleeWithThisReturn = Callee; } namespace { @@ -2222,10 +2232,10 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() { } void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) { - if (cast<CXXMethodDecl>(CurFuncDecl)->isVariadic()) { + if (cast<CXXMethodDecl>(CurCodeDecl)->isVariadic()) { // FIXME: Making this work correctly is nasty because it requires either // cloning the body of the call operator or making the call operator forward. - CGM.ErrorUnsupported(CurFuncDecl, "lambda conversion to variadic function"); + CGM.ErrorUnsupported(CurCodeDecl, "lambda conversion to variadic function"); return; } diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp index 861d31fb7f..ba6b56c267 100644 --- a/lib/CodeGen/CGCleanup.cpp +++ b/lib/CodeGen/CGCleanup.cpp @@ -371,7 +371,8 @@ void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) { } /// Pops cleanup blocks until the given savepoint is reached. -void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) { +void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old, + SourceLocation EHLoc) { assert(Old.isValid()); while (EHStack.stable_begin() != Old) { @@ -383,7 +384,7 @@ void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) { bool FallThroughIsBranchThrough = Old.strictlyEncloses(Scope.getEnclosingNormalCleanup()); - PopCleanupBlock(FallThroughIsBranchThrough); + PopCleanupBlock(FallThroughIsBranchThrough, EHLoc); } } @@ -532,7 +533,8 @@ static void destroyOptimisticNormalEntry(CodeGenFunction &CGF, /// Pops a cleanup block. If the block includes a normal cleanup, the /// current insertion point is threaded through the cleanup, as are /// any branch fixups on the cleanup. -void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { +void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough, + SourceLocation EHLoc) { assert(!EHStack.empty() && "cleanup stack is empty!"); assert(isa<EHCleanupScope>(*EHStack.begin()) && "top not a cleanup!"); EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin()); @@ -833,6 +835,9 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // Emit the EH cleanup if required. if (RequiresEHCleanup) { + if (CGDebugInfo *DI = getDebugInfo()) + DI->EmitLocation(Builder, EHLoc); + CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); EmitBlock(EHEntry); @@ -840,6 +845,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // We only actually emit the cleanup code if the cleanup is either // active or was used before it was deactivated. if (EHActiveFlag || IsActive) { + cleanupFlags.setIsForEHCleanup(); EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag); } diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index a139597c26..ddcb931e46 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -89,7 +89,7 @@ void CGDebugInfo::setLocation(SourceLocation Loc) { } /// getContextDescriptor - Get context info for the decl. -llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context) { +llvm::DIScope CGDebugInfo::getContextDescriptor(const Decl *Context) { if (!Context) return TheCU; @@ -97,20 +97,17 @@ llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context) { I = RegionMap.find(Context); if (I != RegionMap.end()) { llvm::Value *V = I->second; - return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V)); + return llvm::DIScope(dyn_cast_or_null<llvm::MDNode>(V)); } // Check namespace. if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context)) - return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl)); + return getOrCreateNameSpace(NSDecl); - if (const RecordDecl *RDecl = dyn_cast<RecordDecl>(Context)) { - if (!RDecl->isDependentType()) { - llvm::DIType Ty = getOrCreateType(CGM.getContext().getTypeDeclType(RDecl), + if (const RecordDecl *RDecl = dyn_cast<RecordDecl>(Context)) + if (!RDecl->isDependentType()) + return getOrCreateType(CGM.getContext().getTypeDeclType(RDecl), getOrCreateMainFile()); - return llvm::DIDescriptor(Ty); - } - } return TheCU; } @@ -262,9 +259,9 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { } /// getColumnNumber - Get column number for the location. -unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) { +unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) { // We may not want column information at all. - if (!CGM.getCodeGenOpts().DebugColumnInfo) + if (!Force && !CGM.getCodeGenOpts().DebugColumnInfo) return 0; // If the location is invalid then use the current column. @@ -392,21 +389,12 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) { llvm::DIType ISATy = DBuilder.createPointerType(ClassTy, Size); - llvm::DIType FwdTy = + ObjTy = DBuilder.createStructType(TheCU, "objc_object", getOrCreateMainFile(), 0, 0, 0, 0, llvm::DIType(), llvm::DIArray()); - llvm::TrackingVH<llvm::MDNode> ObjNode(FwdTy); - SmallVector<llvm::Value *, 1> EltTys; - llvm::DIType FieldTy = - DBuilder.createMemberType(llvm::DIDescriptor(ObjNode), "isa", - getOrCreateMainFile(), 0, Size, - 0, 0, 0, ISATy); - EltTys.push_back(FieldTy); - llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); - - ObjNode->replaceOperandWith(10, Elements); - ObjTy = llvm::DIType(ObjNode); + ObjTy.setTypeArray(DBuilder.getOrCreateArray(&*DBuilder.createMemberType( + ObjTy, "isa", getOrCreateMainFile(), 0, Size, 0, 0, 0, ISATy))); return ObjTy; } case BuiltinType::ObjCSel: { @@ -651,7 +639,7 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag, // Size is always the size of a pointer. We can't use getTypeSize here // because that does not return the correct value for references. unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); - uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS); + uint64_t Size = CGM.getTarget().getPointerWidth(AS); uint64_t Align = CGM.getContext().getTypeAlign(Ty); return DBuilder.createPointerType(CreatePointeeType(PointeeTy, Unit), @@ -993,7 +981,7 @@ llvm::DIType CGDebugInfo::getOrCreateInstanceMethodType( const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr); QualType PointeeTy = ThisPtrTy->getPointeeType(); unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); - uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS); + uint64_t Size = CGM.getTarget().getPointerWidth(AS); uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy); llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit); llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align); @@ -1332,15 +1320,16 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. - llvm::DIType FwdDecl = getOrCreateLimitedType(QualType(Ty, 0), DefUnit); + llvm::DICompositeType FwdDecl( + getOrCreateLimitedType(QualType(Ty, 0), DefUnit)); + assert(FwdDecl.Verify() && + "The debug type of a RecordType should be a DICompositeType"); if (FwdDecl.isForwardDecl()) return FwdDecl; - llvm::TrackingVH<llvm::MDNode> FwdDeclNode(FwdDecl); - // Push the struct on region stack. - LexicalBlockStack.push_back(FwdDeclNode); + LexicalBlockStack.push_back(&*FwdDecl); RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl); // Add this to the completed-type cache while we're completing it recursively. @@ -1374,19 +1363,10 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { RegionMap.erase(Ty->getDecl()); llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); - // FIXME: Magic numbers ahoy! These should be changed when we - // get some enums in llvm/Analysis/DebugInfo.h to refer to - // them. - if (RD->isUnion()) - FwdDeclNode->replaceOperandWith(10, Elements); - else if (CXXDecl) { - FwdDeclNode->replaceOperandWith(10, Elements); - FwdDeclNode->replaceOperandWith(13, TParamsArray); - } else - FwdDeclNode->replaceOperandWith(10, Elements); + FwdDecl.setTypeArray(Elements, TParamsArray); - RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDeclNode); - return llvm::DIType(FwdDeclNode); + RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl); + return FwdDecl; } /// CreateType - get objective-c object type. @@ -1429,7 +1409,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, if (ID->getImplementation()) Flags |= llvm::DIDescriptor::FlagObjcClassComplete; - llvm::DIType RealDecl = + llvm::DICompositeType RealDecl = DBuilder.createStructType(Unit, ID->getName(), DefUnit, Line, Size, Align, Flags, llvm::DIType(), llvm::DIArray(), RuntimeLang); @@ -1439,9 +1419,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, QualType QualTy = QualType(Ty, 0); CompletedTypeCache[QualTy.getAsOpaquePtr()] = RealDecl; // Push the struct on region stack. - llvm::TrackingVH<llvm::MDNode> FwdDeclNode(RealDecl); - LexicalBlockStack.push_back(FwdDeclNode); + LexicalBlockStack.push_back(static_cast<llvm::MDNode*>(RealDecl)); RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl); // Convert all the elements. @@ -1561,7 +1540,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, } llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); - FwdDeclNode->replaceOperandWith(10, Elements); + RealDecl.setTypeArray(Elements); // If the implementation is not yet set, we do not want to mark it // as complete. An implementation may declare additional @@ -1570,7 +1549,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, CompletedTypeCache.erase(QualTy.getAsOpaquePtr()); LexicalBlockStack.pop_back(); - return llvm::DIType(FwdDeclNode); + return RealDecl; } llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile Unit) { @@ -1717,7 +1696,7 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) { unsigned Line = getLineNumber(ED->getLocation()); llvm::DIDescriptor EnumContext = getContextDescriptor(cast<Decl>(ED->getDeclContext())); - llvm::DIType ClassTy = ED->isScopedUsingClassTag() ? + llvm::DIType ClassTy = ED->isFixed() ? getOrCreateType(ED->getIntegerType(), DefUnit) : llvm::DIType(); llvm::DIType DbgTy = DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line, @@ -1872,9 +1851,9 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) { TC = llvm::DIType(cast<llvm::MDNode>(it->second.first)); else TC = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, - Decl->getName(), TheCU, Unit, - getLineNumber(Decl->getLocation()), - TheCU.getLanguage()); + Decl->getName(), TheCU, Unit, + getLineNumber(Decl->getLocation()), + TheCU.getLanguage()); // Store the forward declaration in the cache. ObjCInterfaceCache[TyPtr] = std::make_pair(TC, Checksum(Decl)); @@ -1891,7 +1870,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) { /// Currently the checksum merely consists of the number of ivars. unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl - *InterfaceDecl) { + *InterfaceDecl) { unsigned IvarNo = 0; for (const ObjCIvarDecl *Ivar = InterfaceDecl->all_declared_ivar_begin(); Ivar != 0; Ivar = Ivar->getNextIvar()) ++IvarNo; @@ -2041,7 +2020,7 @@ llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) { uint64_t Size = CGM.getContext().getTypeSize(Ty); uint64_t Align = CGM.getContext().getTypeAlign(Ty); const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD); - llvm::TrackingVH<llvm::MDNode> RealDecl; + llvm::DICompositeType RealDecl; if (RD->isUnion()) RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line, @@ -2055,14 +2034,14 @@ llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) { llvm::DIArray()); } else RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line, - Size, Align, 0, llvm::DIType(), llvm::DIArray()); + Size, Align, 0, llvm::DIType(), llvm::DIArray()); RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl); - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = llvm::DIType(RealDecl); + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl; if (CXXDecl) { // A class's primary base or the class itself contains the vtable. - llvm::MDNode *ContainingType = NULL; + llvm::DICompositeType ContainingType; const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) { // Seek non virtual primary base root. @@ -2074,13 +2053,12 @@ llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) { else break; } - ContainingType = - getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit); - } - else if (CXXDecl->isDynamicClass()) + ContainingType = llvm::DICompositeType( + getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit)); + } else if (CXXDecl->isDynamicClass()) ContainingType = RealDecl; - RealDecl->replaceOperandWith(12, ContainingType); + RealDecl.setContainingType(ContainingType); } return llvm::DIType(RealDecl); } @@ -2167,8 +2145,9 @@ llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D, // First element is always return type. For 'void' functions it is NULL. Elts.push_back(getOrCreateType(OMethod->getResultType(), F)); // "self" pointer is always first argument. - llvm::DIType SelfTy = getOrCreateType(OMethod->getSelfDecl()->getType(), F); - Elts.push_back(DBuilder.createObjectPointerType(SelfTy)); + QualType SelfDeclTy = OMethod->getSelfDecl()->getType(); + llvm::DIType SelfTy = getOrCreateType(SelfDeclTy, F); + Elts.push_back(CreateSelfType(SelfDeclTy, SelfTy)); // "_cmd" pointer is always second argument. llvm::DIType CmdTy = getOrCreateType(OMethod->getCmdDecl()->getType(), F); Elts.push_back(DBuilder.createArtificialType(CmdTy)); @@ -2224,13 +2203,18 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, } } Name = getFunctionName(FD); - // Use mangled name as linkage name for c/c++ functions. + // Use mangled name as linkage name for C/C++ functions. if (FD->hasPrototype()) { LinkageName = CGM.getMangledName(GD); Flags |= llvm::DIDescriptor::FlagPrototyped; } + // No need to replicate the linkage name if it isn't different from the + // subprogram name, no need to have it at all unless coverage is enabled or + // debug is set to more than just line tables. if (LinkageName == Name || - CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly) + (!CGM.getCodeGenOpts().EmitGcovArcs && + !CGM.getCodeGenOpts().EmitGcovNotes && + CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly)) LinkageName = StringRef(); if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) { @@ -2291,7 +2275,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, /// EmitLocation - Emit metadata to indicate a change in line/column /// information in the source file. -void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { +void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc, + bool ForceColumnInfo) { // Update our current location setLocation(Loc); @@ -2312,9 +2297,10 @@ void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { PrevLoc = CurLoc; llvm::MDNode *Scope = LexicalBlockStack.back(); - Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(CurLoc), - getColumnNumber(CurLoc), - Scope)); + Builder.SetCurrentDebugLocation(llvm::DebugLoc::get + (getLineNumber(CurLoc), + getColumnNumber(CurLoc, ForceColumnInfo), + Scope)); } /// CreateLexicalBlock - Creates a new lexical block node and pushes it on @@ -2409,7 +2395,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, CharUnits Align = CGM.getContext().getDeclAlign(VD); if (Align > CGM.getContext().toCharUnitsFromBits( - CGM.getContext().getTargetInfo().getPointerAlign(0))) { + CGM.getTarget().getPointerAlign(0))) { CharUnits FieldOffsetInBytes = CGM.getContext().toCharUnitsFromBits(FieldOffset); CharUnits AlignedOffsetInBytes @@ -2505,7 +2491,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); // offset of __forwarding field offset = CGM.getContext().toCharUnitsFromBits( - CGM.getContext().getTargetInfo().getPointerWidth(0)); + CGM.getTarget().getPointerWidth(0)); addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); @@ -2593,6 +2579,19 @@ void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder); } +/// Look up the completed type for a self pointer in the TypeCache and +/// create a copy of it with the ObjectPointer and Artificial flags +/// set. If the type is not cached, a new one is created. This should +/// never happen though, since creating a type for the implicit self +/// argument implies that we already parsed the interface definition +/// and the ivar declarations in the implementation. +llvm::DIType CGDebugInfo::CreateSelfType(const QualType &QualTy, llvm::DIType Ty) { + llvm::DIType CachedTy = getTypeOrNull(QualTy); + if (CachedTy.Verify()) Ty = CachedTy; + else DEBUG(llvm::dbgs() << "No cached type for self."); + return DBuilder.createObjectPointerType(Ty); +} + void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder, @@ -2616,7 +2615,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD, // Self is passed along as an implicit non-arg variable in a // block. Mark it as the object pointer. if (isa<ImplicitParamDecl>(VD) && VD->getName() == "self") - Ty = DBuilder.createObjectPointerType(Ty); + Ty = CreateSelfType(VD->getType(), Ty); // Get location information. unsigned Line = getLineNumber(VD->getLocation()); @@ -2630,6 +2629,8 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD, SmallVector<llvm::Value *, 9> addr; llvm::Type *Int64Ty = CGM.Int64Ty; + if (isa<llvm::AllocaInst>(Storage)) + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); if (isByRef) { @@ -2651,6 +2652,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD, DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable, llvm::DIDescriptor(LexicalBlockStack.back()), VD->getName(), Unit, Line, Ty, addr); + // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = DBuilder.insertDeclare(Storage, D, Builder.GetInsertPoint()); @@ -2678,7 +2680,8 @@ namespace { } void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, - llvm::Value *addr, + llvm::Value *Arg, + llvm::Value *LocalAddr, CGBuilderTy &Builder) { assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); ASTContext &C = CGM.getContext(); @@ -2805,21 +2808,27 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, // Get overall information about the block. unsigned flags = llvm::DIDescriptor::FlagArtificial; llvm::MDNode *scope = LexicalBlockStack.back(); - StringRef name = ".block_descriptor"; // Create the descriptor for the parameter. llvm::DIVariable debugVar = DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, llvm::DIDescriptor(scope), - name, tunit, line, type, + Arg->getName(), tunit, line, type, CGM.getLangOpts().Optimize, flags, - cast<llvm::Argument>(addr)->getArgNo() + 1); - - // Insert an llvm.dbg.value into the current block. - llvm::Instruction *declare = - DBuilder.insertDbgValueIntrinsic(addr, 0, debugVar, - Builder.GetInsertBlock()); - declare->setDebugLoc(llvm::DebugLoc::get(line, column, scope)); + cast<llvm::Argument>(Arg)->getArgNo() + 1); + + if (LocalAddr) { + // Insert an llvm.dbg.value into the current block. + llvm::Instruction *DbgVal = + DBuilder.insertDbgValueIntrinsic(LocalAddr, 0, debugVar, + Builder.GetInsertBlock()); + DbgVal->setDebugLoc(llvm::DebugLoc::get(line, column, scope)); + } + + // Insert an llvm.dbg.declare into the current block. + llvm::Instruction *DbgDecl = + DBuilder.insertDeclare(Arg, debugVar, Builder.GetInsertBlock()); + DbgDecl->setDebugLoc(llvm::DebugLoc::get(line, column, scope)); } /// getStaticDataMemberDeclaration - If D is an out-of-class definition of @@ -2920,6 +2929,16 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, getStaticDataMemberDeclaration(VD)); } +void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) { + llvm::DIScope Scope = + LexicalBlockStack.empty() + ? getContextDescriptor(cast<Decl>(UD.getDeclContext())) + : llvm::DIScope(LexicalBlockStack.back()); + DBuilder.createImportedModule( + Scope, getOrCreateNameSpace(UD.getNominatedNamespace()), + getLineNumber(UD.getLocation())); +} + /// getOrCreateNamesSpace - Return namespace descriptor for the given /// namespace decl. llvm::DINameSpace @@ -2955,9 +2974,8 @@ void CGDebugInfo::finalize() { RepTy = llvm::DIType(cast<llvm::MDNode>(V)); } - if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify()) { + if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify()) Ty.replaceAllUsesWith(RepTy); - } } // We keep our own list of retained types, because we need to look diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 2e896cfe22..4080492a1c 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -51,7 +51,7 @@ class CGDebugInfo { SourceLocation CurLoc, PrevLoc; llvm::DIType VTablePtrType; llvm::DIType ClassTy; - llvm::DIType ObjTy; + llvm::DICompositeType ObjTy; llvm::DIType SelTy; llvm::DIType OCLImage1dDITy, OCLImage1dArrayDITy, OCLImage1dBufferDITy; llvm::DIType OCLImage2dDITy, OCLImage2dArrayDITy; @@ -119,6 +119,7 @@ class CGDebugInfo { llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F); llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F); llvm::DIType CreateEnumType(const EnumDecl *ED); + llvm::DIType CreateSelfType(const QualType &QualTy, llvm::DIType Ty); llvm::DIType getTypeOrNull(const QualType); llvm::DIType getCompletedTypeOrNull(const QualType); llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method, @@ -207,7 +208,9 @@ public: /// EmitLocation - Emit metadata to indicate a change in line/column /// information in the source file. - void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc); + /// \param ForceColumnInfo Assume DebugColumnInfo option is true. + void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc, + bool ForceColumnInfo = false); /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate /// start of a new function. @@ -246,7 +249,8 @@ public: /// llvm.dbg.declare for the block-literal argument to a block /// invocation function. void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, - llvm::Value *addr, + llvm::Value *Arg, + llvm::Value *LocalAddr, CGBuilderTy &Builder); /// EmitGlobalVariable - Emit information about a global variable. @@ -258,6 +262,9 @@ public: /// EmitGlobalVariable - Emit global variable's debug info. void EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init); + /// \brief - Emit C++ using directive. + void EmitUsingDirective(const UsingDirectiveDecl &UD); + /// getOrCreateRecordType - Emit record type's standalone debug info. llvm::DIType getOrCreateRecordType(QualType Ty, SourceLocation L); @@ -277,7 +284,7 @@ private: uint64_t *OffSet); /// getContextDescriptor - Get context info for the decl. - llvm::DIDescriptor getContextDescriptor(const Decl *Decl); + llvm::DIScope getContextDescriptor(const Decl *Decl); /// createRecordFwdDecl - Create a forward decl for a RecordType in a given /// context. @@ -356,7 +363,8 @@ private: /// getColumnNumber - Get column number for the location. If location is /// invalid then use current location. - unsigned getColumnNumber(SourceLocation Loc); + /// \param Force Assume DebugColumnInfo option is true. + unsigned getColumnNumber(SourceLocation Loc, bool Force=false); }; } // namespace CodeGen } // namespace clang diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 0e001301ae..3ce6dec6a5 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -45,6 +45,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::CXXDestructor: case Decl::CXXConversion: case Decl::Field: + case Decl::MSProperty: case Decl::IndirectField: case Decl::ObjCIvar: case Decl::ObjCAtDefsField: @@ -69,6 +70,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Friend: case Decl::FriendTemplate: case Decl::Block: + case Decl::Captured: case Decl::ClassScopeFunctionSpecialization: llvm_unreachable("Declaration should not be in declstmts!"); case Decl::Function: // void X(); @@ -78,15 +80,19 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::CXXRecord: // struct/union/class X; [C++] case Decl::Using: // using X; [C++] case Decl::UsingShadow: - case Decl::UsingDirective: // using namespace X; [C++] case Decl::NamespaceAlias: case Decl::StaticAssert: // static_assert(X, ""); [C++0x] case Decl::Label: // __label__ x; case Decl::Import: + case Decl::OMPThreadPrivate: case Decl::Empty: // None of these decls require codegen support. return; + case Decl::UsingDirective: // using namespace X; [C++] + if (CGDebugInfo *DI = getDebugInfo()) + DI->EmitUsingDirective(cast<UsingDirectiveDecl>(D)); + return; case Decl::Var: { const VarDecl &VD = cast<VarDecl>(D); assert(VD.isLocalVarDecl() && @@ -108,7 +114,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { /// EmitVarDecl - This method handles emission of any variable declaration /// inside a function, including static vars etc. void CodeGenFunction::EmitVarDecl(const VarDecl &D) { - switch (D.getStorageClassAsWritten()) { + switch (D.getStorageClass()) { case SC_None: case SC_Auto: case SC_Register: @@ -197,7 +203,7 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, if (Linkage != llvm::GlobalValue::InternalLinkage) GV->setVisibility(CurFn->getVisibility()); - if (D.isThreadSpecified()) + if (D.getTLSKind()) CGM.setTLSMode(GV, D); return GV; @@ -451,6 +457,22 @@ namespace { CGF.EmitCall(FnInfo, CleanupFn, ReturnValueSlot(), Args); } }; + + /// A cleanup to call @llvm.lifetime.end. + class CallLifetimeEnd : public EHScopeStack::Cleanup { + llvm::Value *Addr; + llvm::Value *Size; + public: + CallLifetimeEnd(llvm::Value *addr, llvm::Value *size) + : Addr(addr), Size(size) {} + + void Emit(CodeGenFunction &CGF, Flags flags) { + llvm::Value *castAddr = CGF.Builder.CreateBitCast(Addr, CGF.Int8PtrTy); + CGF.Builder.CreateCall2(CGF.CGM.getLLVMLifetimeEndFn(), + Size, castAddr) + ->setDoesNotThrow(); + } + }; } /// EmitAutoVarWithLifetime - Does the setup required for an automatic @@ -627,7 +649,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, if (accessedByInit && lifetime == Qualifiers::OCL_Strong) { llvm::Value *oldValue = EmitLoadOfScalar(lvalue); EmitStoreOfScalar(value, lvalue, /* isInitialization */ true); - EmitARCRelease(oldValue, /*precise*/ false); + EmitARCRelease(oldValue, ARCImpreciseLifetime); return; } @@ -755,7 +777,6 @@ static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init, // If a global is all zeros, always use a memset. if (isa<llvm::ConstantAggregateZero>(Init)) return true; - // If a non-zero global is <= 32 bytes, always use a memcpy. If it is large, // do it if it will require 6 or fewer scalar stores. // TODO: Should budget depends on the size? Avoiding a large global warrants @@ -767,6 +788,23 @@ static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init, canEmitInitWithFewStoresAfterMemset(Init, StoreBudget); } +/// Should we use the LLVM lifetime intrinsics for the given local variable? +static bool shouldUseLifetimeMarkers(CodeGenFunction &CGF, const VarDecl &D, + unsigned Size) { + // Always emit lifetime markers in -fsanitize=use-after-scope mode. + if (CGF.getLangOpts().Sanitize.UseAfterScope) + return true; + // For now, only in optimized builds. + if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) + return false; + + // Limit the size of marked objects to 32 bytes. We don't want to increase + // compile time by marking tiny objects. + unsigned SizeThreshold = 32; + + return Size > SizeThreshold; +} + /// EmitAutoVarDecl - Emit code and set up an entry in LocalDeclMap for a /// variable declaration with auto, register, or no storage class specifier. @@ -797,85 +835,91 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { llvm::Value *DeclPtr; if (Ty->isConstantSizeType()) { - if (!Target.useGlobalsForAutomaticVariables()) { - bool NRVO = getLangOpts().ElideConstructors && - D.isNRVOVariable(); - - // If this value is a POD array or struct with a statically - // determinable constant initializer, there are optimizations we can do. - // - // TODO: We should constant-evaluate the initializer of any variable, - // as long as it is initialized by a constant expression. Currently, - // isConstantInitializer produces wrong answers for structs with - // reference or bitfield members, and a few other cases, and checking - // for POD-ness protects us from some of these. - if (D.getInit() && - (Ty->isArrayType() || Ty->isRecordType()) && - (Ty.isPODType(getContext()) || - getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) && - D.getInit()->isConstantInitializer(getContext(), false)) { - - // If the variable's a const type, and it's neither an NRVO - // candidate nor a __block variable and has no mutable members, - // emit it as a global instead. - if (CGM.getCodeGenOpts().MergeAllConstants && !NRVO && !isByRef && - CGM.isTypeConstant(Ty, true)) { - EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage); - - emission.Address = 0; // signal this condition to later callbacks - assert(emission.wasEmittedAsGlobal()); - return emission; - } - - // Otherwise, tell the initialization code that we're in this case. - emission.IsConstantAggregate = true; + bool NRVO = getLangOpts().ElideConstructors && + D.isNRVOVariable(); + + // If this value is a POD array or struct with a statically + // determinable constant initializer, there are optimizations we can do. + // + // TODO: We should constant-evaluate the initializer of any variable, + // as long as it is initialized by a constant expression. Currently, + // isConstantInitializer produces wrong answers for structs with + // reference or bitfield members, and a few other cases, and checking + // for POD-ness protects us from some of these. + if (D.getInit() && + (Ty->isArrayType() || Ty->isRecordType()) && + (Ty.isPODType(getContext()) || + getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) && + D.getInit()->isConstantInitializer(getContext(), false)) { + + // If the variable's a const type, and it's neither an NRVO + // candidate nor a __block variable and has no mutable members, + // emit it as a global instead. + if (CGM.getCodeGenOpts().MergeAllConstants && !NRVO && !isByRef && + CGM.isTypeConstant(Ty, true)) { + EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage); + + emission.Address = 0; // signal this condition to later callbacks + assert(emission.wasEmittedAsGlobal()); + return emission; } - // A normal fixed sized variable becomes an alloca in the entry block, - // unless it's an NRVO variable. - llvm::Type *LTy = ConvertTypeForMem(Ty); + // Otherwise, tell the initialization code that we're in this case. + emission.IsConstantAggregate = true; + } - if (NRVO) { - // The named return value optimization: allocate this variable in the - // return slot, so that we can elide the copy when returning this - // variable (C++0x [class.copy]p34). - DeclPtr = ReturnValue; - - if (const RecordType *RecordTy = Ty->getAs<RecordType>()) { - if (!cast<CXXRecordDecl>(RecordTy->getDecl())->hasTrivialDestructor()) { - // Create a flag that is used to indicate when the NRVO was applied - // to this variable. Set it to zero to indicate that NRVO was not - // applied. - llvm::Value *Zero = Builder.getFalse(); - llvm::Value *NRVOFlag = CreateTempAlloca(Zero->getType(), "nrvo"); - EnsureInsertPoint(); - Builder.CreateStore(Zero, NRVOFlag); - - // Record the NRVO flag for this variable. - NRVOFlags[&D] = NRVOFlag; - emission.NRVOFlag = NRVOFlag; - } + // A normal fixed sized variable becomes an alloca in the entry block, + // unless it's an NRVO variable. + llvm::Type *LTy = ConvertTypeForMem(Ty); + + if (NRVO) { + // The named return value optimization: allocate this variable in the + // return slot, so that we can elide the copy when returning this + // variable (C++0x [class.copy]p34). + DeclPtr = ReturnValue; + + if (const RecordType *RecordTy = Ty->getAs<RecordType>()) { + if (!cast<CXXRecordDecl>(RecordTy->getDecl())->hasTrivialDestructor()) { + // Create a flag that is used to indicate when the NRVO was applied + // to this variable. Set it to zero to indicate that NRVO was not + // applied. + llvm::Value *Zero = Builder.getFalse(); + llvm::Value *NRVOFlag = CreateTempAlloca(Zero->getType(), "nrvo"); + EnsureInsertPoint(); + Builder.CreateStore(Zero, NRVOFlag); + + // Record the NRVO flag for this variable. + NRVOFlags[&D] = NRVOFlag; + emission.NRVOFlag = NRVOFlag; } - } else { - if (isByRef) - LTy = BuildByRefType(&D); - - llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); - Alloc->setName(D.getName()); - - CharUnits allocaAlignment = alignment; - if (isByRef) - allocaAlignment = std::max(allocaAlignment, - getContext().toCharUnitsFromBits(Target.getPointerAlign(0))); - Alloc->setAlignment(allocaAlignment.getQuantity()); - DeclPtr = Alloc; } } else { - // Targets that don't support recursion emit locals as globals. - const char *Class = - D.getStorageClass() == SC_Register ? ".reg." : ".auto."; - DeclPtr = CreateStaticVarDecl(D, Class, - llvm::GlobalValue::InternalLinkage); + if (isByRef) + LTy = BuildByRefType(&D); + + llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); + Alloc->setName(D.getName()); + + CharUnits allocaAlignment = alignment; + if (isByRef) + allocaAlignment = std::max(allocaAlignment, + getContext().toCharUnitsFromBits(getTarget().getPointerAlign(0))); + Alloc->setAlignment(allocaAlignment.getQuantity()); + DeclPtr = Alloc; + + // Emit a lifetime intrinsic if meaningful. There's no point + // in doing this if we don't have a valid insertion point (?). + uint64_t size = CGM.getDataLayout().getTypeAllocSize(LTy); + if (HaveInsertPoint() && shouldUseLifetimeMarkers(*this, D, size)) { + llvm::Value *sizeV = llvm::ConstantInt::get(Int64Ty, size); + + emission.SizeForLifetimeMarkers = sizeV; + llvm::Value *castAddr = Builder.CreateBitCast(Alloc, Int8PtrTy); + Builder.CreateCall2(CGM.getLLVMLifetimeStartFn(), sizeV, castAddr) + ->setDoesNotThrow(); + } else { + assert(!emission.useLifetimeMarkers()); + } } } else { EnsureInsertPoint(); @@ -920,11 +964,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) { DI->setLocation(D.getLocation()); - if (Target.useGlobalsForAutomaticVariables()) { - DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr), - &D); - } else - DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder); + DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder); } } @@ -1214,6 +1254,14 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) { const VarDecl &D = *emission.Variable; + // Make sure we call @llvm.lifetime.end. This needs to happen + // *last*, so the cleanup needs to be pushed *first*. + if (emission.useLifetimeMarkers()) { + EHStack.pushCleanup<CallLifetimeEnd>(NormalCleanup, + emission.getAllocatedAddress(), + emission.getSizeForLifetimeMarkers()); + } + // Check the type for a cleanup. if (QualType::DestructionKind dtorKind = D.getType().isDestructedType()) emitAutoVarTypeCleanup(emission, dtorKind); @@ -1484,18 +1532,37 @@ void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin, elementType, destroyer); } +/// Lazily declare the @llvm.lifetime.start intrinsic. +llvm::Constant *CodeGenModule::getLLVMLifetimeStartFn() { + if (LifetimeStartFn) return LifetimeStartFn; + LifetimeStartFn = llvm::Intrinsic::getDeclaration(&getModule(), + llvm::Intrinsic::lifetime_start); + return LifetimeStartFn; +} + +/// Lazily declare the @llvm.lifetime.end intrinsic. +llvm::Constant *CodeGenModule::getLLVMLifetimeEndFn() { + if (LifetimeEndFn) return LifetimeEndFn; + LifetimeEndFn = llvm::Intrinsic::getDeclaration(&getModule(), + llvm::Intrinsic::lifetime_end); + return LifetimeEndFn; +} + namespace { /// A cleanup to perform a release of an object at the end of a /// function. This is used to balance out the incoming +1 of a /// ns_consumed argument when we can't reasonably do that just by /// not doing the initial retain for a __block argument. struct ConsumeARCParameter : EHScopeStack::Cleanup { - ConsumeARCParameter(llvm::Value *param) : Param(param) {} + ConsumeARCParameter(llvm::Value *param, + ARCPreciseLifetime_t precise) + : Param(param), Precise(precise) {} llvm::Value *Param; + ARCPreciseLifetime_t Precise; void Emit(CodeGenFunction &CGF, Flags flags) { - CGF.EmitARCRelease(Param, /*precise*/ false); + CGF.EmitARCRelease(Param, Precise); } }; } @@ -1510,17 +1577,29 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg, Arg->setName(D.getName()); + QualType Ty = D.getType(); + // Use better IR generation for certain implicit parameters. if (isa<ImplicitParamDecl>(D)) { // The only implicit argument a block has is its literal. if (BlockInfo) { LocalDeclMap[&D] = Arg; + llvm::Value *LocalAddr = 0; + if (CGM.getCodeGenOpts().OptimizationLevel == 0) { + // Allocate a stack slot to let the debug info survive the RA. + llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty), + D.getName() + ".addr"); + Alloc->setAlignment(getContext().getDeclAlign(&D).getQuantity()); + LValue lv = MakeAddrLValue(Alloc, Ty, getContext().getDeclAlign(&D)); + EmitStoreOfScalar(Arg, lv, /* isInitialization */ true); + LocalAddr = Builder.CreateLoad(Alloc); + } if (CGDebugInfo *DI = getDebugInfo()) { if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) { DI->setLocation(D.getLocation()); - DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, Builder); + DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, LocalAddr, Builder); } } @@ -1528,8 +1607,6 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg, } } - QualType Ty = D.getType(); - llvm::Value *DeclPtr; // If this is an aggregate or variable sized value, reuse the input pointer. if (!Ty->isConstantSizeType() || @@ -1585,8 +1662,12 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg, } } else { // Push the cleanup for a consumed parameter. - if (isConsumed) - EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg); + if (isConsumed) { + ARCPreciseLifetime_t precise = (D.hasAttr<ObjCPreciseLifetimeAttr>() + ? ARCPreciseLifetime : ARCImpreciseLifetime); + EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg, + precise); + } if (lt == Qualifiers::OCL_Weak) { EmitARCInitWeak(DeclPtr, Arg); diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 0448d31f40..9ffcff2766 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -39,7 +39,7 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, CodeGenModule &CGM = CGF.CGM; if (lv.isObjCStrong()) CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, CGF.EmitScalarExpr(Init), - DeclPtr, D.isThreadSpecified()); + DeclPtr, D.getTLSKind()); else if (lv.isObjCWeak()) CGM.getObjCRuntime().EmitObjCWeakAssign(CGF, CGF.EmitScalarExpr(Init), DeclPtr); @@ -80,6 +80,7 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D, case QualType::DK_objc_strong_lifetime: case QualType::DK_objc_weak_lifetime: // We don't care about releasing objects during process teardown. + assert(!D.getTLSKind() && "should have rejected this"); return; } @@ -105,7 +106,7 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D, argument = llvm::Constant::getNullValue(CGF.Int8PtrTy); } - CGM.getCXXABI().registerGlobalDtor(CGF, function, argument); + CGM.getCXXABI().registerGlobalDtor(CGF, D, function, argument); } /// Emit code to cause the variable at the given address to be considered as @@ -155,7 +156,8 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, static llvm::Function * CreateGlobalInitOrDestructFunction(CodeGenModule &CGM, llvm::FunctionType *ty, - const Twine &name); + const Twine &name, + bool TLS = false); /// Create a stub function, suitable for being passed to atexit, /// which passes the given address to the given destructor function. @@ -224,14 +226,14 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, static llvm::Function * CreateGlobalInitOrDestructFunction(CodeGenModule &CGM, llvm::FunctionType *FTy, - const Twine &Name) { + const Twine &Name, bool TLS) { llvm::Function *Fn = llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, Name, &CGM.getModule()); - if (!CGM.getLangOpts().AppleKext) { + if (!CGM.getLangOpts().AppleKext && !TLS) { // Set the section if needed. if (const char *Section = - CGM.getContext().getTargetInfo().getStaticInitSectionSpecifier()) + CGM.getTarget().getStaticInitSectionSpecifier()) Fn->setSection(Section); } @@ -263,12 +265,20 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr, PerformInit); - if (D->hasAttr<InitPriorityAttr>()) { + if (D->getTLSKind()) { + // FIXME: Should we support init_priority for thread_local? + // FIXME: Ideally, initialization of instantiated thread_local static data + // members of class templates should not trigger initialization of other + // entities in the TU. + // FIXME: We only need to register one __cxa_thread_atexit function for the + // entire TU. + CXXThreadLocalInits.push_back(Fn); + } else if (D->hasAttr<InitPriorityAttr>()) { unsigned int order = D->getAttr<InitPriorityAttr>()->getPriority(); OrderGlobalInits Key(order, PrioritizedCXXGlobalInits.size()); PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn)); DelayedCXXInitPosition.erase(D); - } else { + } else { llvm::DenseMap<const Decl *, unsigned>::iterator I = DelayedCXXInitPosition.find(D); if (I == DelayedCXXInitPosition.end()) { @@ -281,6 +291,27 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, } } +void CodeGenModule::EmitCXXThreadLocalInitFunc() { + llvm::Function *InitFn = 0; + if (!CXXThreadLocalInits.empty()) { + // Generate a guarded initialization function. + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); + InitFn = CreateGlobalInitOrDestructFunction(*this, FTy, "__tls_init", + /*TLS*/ true); + llvm::GlobalVariable *Guard = new llvm::GlobalVariable( + getModule(), Int8Ty, false, llvm::GlobalVariable::InternalLinkage, + llvm::ConstantInt::get(Int8Ty, 0), "__tls_guard"); + Guard->setThreadLocal(true); + CodeGenFunction(*this) + .GenerateCXXGlobalInitFunc(InitFn, CXXThreadLocalInits, Guard); + } + + getCXXABI().EmitThreadLocalInitFuncs(CXXThreadLocals, InitFn); + + CXXThreadLocalInits.clear(); + CXXThreadLocals.clear(); +} + void CodeGenModule::EmitCXXGlobalInitFunc() { while (!CXXGlobalInits.empty() && !CXXGlobalInits.back()) @@ -320,9 +351,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() { for (; I < PrioE; ++I) LocalCXXGlobalInits.push_back(I->second); - CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, - &LocalCXXGlobalInits[0], - LocalCXXGlobalInits.size()); + CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, LocalCXXGlobalInits); AddGlobalCtor(Fn, Priority); } } @@ -330,9 +359,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() { llvm::Function *Fn = CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a"); - CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, - &CXXGlobalInits[0], - CXXGlobalInits.size()); + CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits); AddGlobalCtor(Fn); CXXGlobalInits.clear(); @@ -379,9 +406,10 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, FinishFunction(); } -void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, - llvm::Constant **Decls, - unsigned NumDecls) { +void +CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, + ArrayRef<llvm::Constant *> Decls, + llvm::GlobalVariable *Guard) { // Initialize debug info if needed. maybeInitializeDebugInfo(); @@ -389,6 +417,22 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, getTypes().arrangeNullaryFunction(), FunctionArgList(), SourceLocation()); + llvm::BasicBlock *ExitBlock = 0; + if (Guard) { + // If we have a guard variable, check whether we've already performed these + // initializations. This happens for TLS initialization functions. + llvm::Value *GuardVal = Builder.CreateLoad(Guard); + llvm::Value *Uninit = Builder.CreateIsNull(GuardVal, "guard.uninitialized"); + // Mark as initialized before initializing anything else. If the + // initializers use previously-initialized thread_local vars, that's + // probably supposed to be OK, but the standard doesn't say. + Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(), 1), Guard); + llvm::BasicBlock *InitBlock = createBasicBlock("init"); + ExitBlock = createBasicBlock("exit"); + Builder.CreateCondBr(Uninit, InitBlock, ExitBlock); + EmitBlock(InitBlock); + } + RunCleanupsScope Scope(*this); // When building in Objective-C++ ARC mode, create an autorelease pool @@ -397,13 +441,18 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, llvm::Value *token = EmitObjCAutoreleasePoolPush(); EmitObjCAutoreleasePoolCleanup(token); } - - for (unsigned i = 0; i != NumDecls; ++i) + + for (unsigned i = 0, e = Decls.size(); i != e; ++i) if (Decls[i]) EmitRuntimeCall(Decls[i]); Scope.ForceCleanup(); - + + if (ExitBlock) { + Builder.CreateBr(ExitBlock); + EmitBlock(ExitBlock); + } + FinishFunction(); } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 36642bcc48..a088d78641 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -419,14 +419,16 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() { return Builder.CreateLoad(getEHSelectorSlot(), "sel"); } -void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { +void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E, + bool KeepInsertionPoint) { if (!E->getSubExpr()) { EmitNoreturnRuntimeCallOrInvoke(getReThrowFn(CGM), ArrayRef<llvm::Value*>()); // throw is an expression, and the expression emitters expect us // to leave ourselves at a valid insertion point. - EmitBlock(createBasicBlock("throw.cont")); + if (KeepInsertionPoint) + EmitBlock(createBasicBlock("throw.cont")); return; } @@ -440,7 +442,8 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { CGM.getObjCRuntime().EmitThrowStmt(*this, S, false); // This will clear insertion point which was not cleared in // call to EmitThrowStmt. - EmitBlock(createBasicBlock("throw.cont")); + if (KeepInsertionPoint) + EmitBlock(createBasicBlock("throw.cont")); return; } @@ -478,7 +481,8 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { // throw is an expression, and the expression emitters expect us // to leave ourselves at a valid insertion point. - EmitBlock(createBasicBlock("throw.cont")); + if (KeepInsertionPoint) + EmitBlock(createBasicBlock("throw.cont")); } void CodeGenFunction::EmitStartEHSpec(const Decl *D) { diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 830b1218c1..64670c5e81 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -184,12 +184,16 @@ CreateReferenceTemporary(CodeGenFunction &CGF, QualType Type, llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type); // Create the reference temporary. - llvm::GlobalValue *RefTemp = + llvm::GlobalVariable *RefTemp = new llvm::GlobalVariable(CGF.CGM.getModule(), RefTempTy, /*isConstant=*/false, llvm::GlobalValue::InternalLinkage, llvm::Constant::getNullValue(RefTempTy), Name.str()); + // If we're binding to a thread_local variable, the temporary is also + // thread local. + if (VD->getTLSKind()) + CGF.CGM.setTLSMode(RefTemp, *VD); return RefTemp; } } @@ -201,6 +205,7 @@ static llvm::Value * EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, llvm::Value *&ReferenceTemporary, const CXXDestructorDecl *&ReferenceTemporaryDtor, + const InitListExpr *&ReferenceInitializerList, QualType &ObjCARCReferenceLifetimeType, const NamedDecl *InitializedDecl) { const MaterializeTemporaryExpr *M = NULL; @@ -222,156 +227,157 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, return EmitExprForReferenceBinding(CGF, EWC->getSubExpr(), ReferenceTemporary, ReferenceTemporaryDtor, + ReferenceInitializerList, ObjCARCReferenceLifetimeType, InitializedDecl); } - RValue RV; if (E->isGLValue()) { // Emit the expression as an lvalue. LValue LV = CGF.EmitLValue(E); + assert(LV.isSimple()); + return LV.getAddress(); + } + + if (!ObjCARCReferenceLifetimeType.isNull()) { + ReferenceTemporary = CreateReferenceTemporary(CGF, + ObjCARCReferenceLifetimeType, + InitializedDecl); - if (LV.isSimple()) - return LV.getAddress(); - // We have to load the lvalue. - RV = CGF.EmitLoadOfLValue(LV); - } else { - if (!ObjCARCReferenceLifetimeType.isNull()) { - ReferenceTemporary = CreateReferenceTemporary(CGF, - ObjCARCReferenceLifetimeType, - InitializedDecl); - - - LValue RefTempDst = CGF.MakeAddrLValue(ReferenceTemporary, - ObjCARCReferenceLifetimeType); + LValue RefTempDst = CGF.MakeAddrLValue(ReferenceTemporary, + ObjCARCReferenceLifetimeType); - CGF.EmitScalarInit(E, dyn_cast_or_null<ValueDecl>(InitializedDecl), - RefTempDst, false); - - bool ExtendsLifeOfTemporary = false; - if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(InitializedDecl)) { - if (Var->extendsLifetimeOfTemporary()) - ExtendsLifeOfTemporary = true; - } else if (InitializedDecl && isa<FieldDecl>(InitializedDecl)) { + CGF.EmitScalarInit(E, dyn_cast_or_null<ValueDecl>(InitializedDecl), + RefTempDst, false); + + bool ExtendsLifeOfTemporary = false; + if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(InitializedDecl)) { + if (Var->extendsLifetimeOfTemporary()) ExtendsLifeOfTemporary = true; - } - - if (!ExtendsLifeOfTemporary) { - // Since the lifetime of this temporary isn't going to be extended, - // we need to clean it up ourselves at the end of the full expression. - switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) { - case Qualifiers::OCL_None: - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Autoreleasing: - break; - - case Qualifiers::OCL_Strong: { - assert(!ObjCARCReferenceLifetimeType->isArrayType()); - CleanupKind cleanupKind = CGF.getARCCleanupKind(); - CGF.pushDestroy(cleanupKind, - ReferenceTemporary, - ObjCARCReferenceLifetimeType, - CodeGenFunction::destroyARCStrongImprecise, - cleanupKind & EHCleanup); - break; - } + } else if (InitializedDecl && isa<FieldDecl>(InitializedDecl)) { + ExtendsLifeOfTemporary = true; + } + + if (!ExtendsLifeOfTemporary) { + // Since the lifetime of this temporary isn't going to be extended, + // we need to clean it up ourselves at the end of the full expression. + switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + break; - case Qualifiers::OCL_Weak: - assert(!ObjCARCReferenceLifetimeType->isArrayType()); - CGF.pushDestroy(NormalAndEHCleanup, - ReferenceTemporary, - ObjCARCReferenceLifetimeType, - CodeGenFunction::destroyARCWeak, - /*useEHCleanupForArray*/ true); - break; - } + case Qualifiers::OCL_Strong: { + assert(!ObjCARCReferenceLifetimeType->isArrayType()); + CleanupKind cleanupKind = CGF.getARCCleanupKind(); + CGF.pushDestroy(cleanupKind, + ReferenceTemporary, + ObjCARCReferenceLifetimeType, + CodeGenFunction::destroyARCStrongImprecise, + cleanupKind & EHCleanup); + break; + } - ObjCARCReferenceLifetimeType = QualType(); + case Qualifiers::OCL_Weak: + assert(!ObjCARCReferenceLifetimeType->isArrayType()); + CGF.pushDestroy(NormalAndEHCleanup, + ReferenceTemporary, + ObjCARCReferenceLifetimeType, + CodeGenFunction::destroyARCWeak, + /*useEHCleanupForArray*/ true); + break; } - return ReferenceTemporary; + ObjCARCReferenceLifetimeType = QualType(); } + + return ReferenceTemporary; + } - SmallVector<SubobjectAdjustment, 2> Adjustments; - E = E->skipRValueSubobjectAdjustments(Adjustments); - if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E)) - if (opaque->getType()->isRecordType()) - return CGF.EmitOpaqueValueLValue(opaque).getAddress(); - - // Create a reference temporary if necessary. - AggValueSlot AggSlot = AggValueSlot::ignored(); - if (CGF.hasAggregateEvaluationKind(E->getType())) { - ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(), - InitializedDecl); - CharUnits Alignment = CGF.getContext().getTypeAlignInChars(E->getType()); - AggValueSlot::IsDestructed_t isDestructed - = AggValueSlot::IsDestructed_t(InitializedDecl != 0); - AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Alignment, - Qualifiers(), isDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased); + SmallVector<SubobjectAdjustment, 2> Adjustments; + E = E->skipRValueSubobjectAdjustments(Adjustments); + if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E)) + if (opaque->getType()->isRecordType()) + return CGF.EmitOpaqueValueLValue(opaque).getAddress(); + + // Create a reference temporary if necessary. + AggValueSlot AggSlot = AggValueSlot::ignored(); + if (CGF.hasAggregateEvaluationKind(E->getType())) { + ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(), + InitializedDecl); + CharUnits Alignment = CGF.getContext().getTypeAlignInChars(E->getType()); + AggValueSlot::IsDestructed_t isDestructed + = AggValueSlot::IsDestructed_t(InitializedDecl != 0); + AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Alignment, + Qualifiers(), isDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); + } + + if (InitializedDecl) { + if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) { + if (ILE->initializesStdInitializerList()) { + ReferenceInitializerList = ILE; + } } - - if (InitializedDecl) { + else if (const RecordType *RT = + E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()){ // Get the destructor for the reference temporary. - if (const RecordType *RT = - E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) { - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (!ClassDecl->hasTrivialDestructor()) - ReferenceTemporaryDtor = ClassDecl->getDestructor(); - } + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (!ClassDecl->hasTrivialDestructor()) + ReferenceTemporaryDtor = ClassDecl->getDestructor(); } + } - RV = CGF.EmitAnyExpr(E, AggSlot); - - // Check if need to perform derived-to-base casts and/or field accesses, to - // get from the temporary object we created (and, potentially, for which we - // extended the lifetime) to the subobject we're binding the reference to. - if (!Adjustments.empty()) { - llvm::Value *Object = RV.getAggregateAddr(); - for (unsigned I = Adjustments.size(); I != 0; --I) { - SubobjectAdjustment &Adjustment = Adjustments[I-1]; - switch (Adjustment.Kind) { - case SubobjectAdjustment::DerivedToBaseAdjustment: - Object = - CGF.GetAddressOfBaseClass(Object, - Adjustment.DerivedToBase.DerivedClass, - Adjustment.DerivedToBase.BasePath->path_begin(), - Adjustment.DerivedToBase.BasePath->path_end(), - /*NullCheckValue=*/false); - break; - - case SubobjectAdjustment::FieldAdjustment: { - LValue LV = CGF.MakeAddrLValue(Object, E->getType()); - LV = CGF.EmitLValueForField(LV, Adjustment.Field); - if (LV.isSimple()) { - Object = LV.getAddress(); - break; - } + RValue RV = CGF.EmitAnyExpr(E, AggSlot); + + // Check if need to perform derived-to-base casts and/or field accesses, to + // get from the temporary object we created (and, potentially, for which we + // extended the lifetime) to the subobject we're binding the reference to. + if (!Adjustments.empty()) { + llvm::Value *Object = RV.getAggregateAddr(); + for (unsigned I = Adjustments.size(); I != 0; --I) { + SubobjectAdjustment &Adjustment = Adjustments[I-1]; + switch (Adjustment.Kind) { + case SubobjectAdjustment::DerivedToBaseAdjustment: + Object = + CGF.GetAddressOfBaseClass(Object, + Adjustment.DerivedToBase.DerivedClass, + Adjustment.DerivedToBase.BasePath->path_begin(), + Adjustment.DerivedToBase.BasePath->path_end(), + /*NullCheckValue=*/false); + break; - // For non-simple lvalues, we actually have to create a copy of - // the object we're binding to. - QualType T = Adjustment.Field->getType().getNonReferenceType() - .getUnqualifiedType(); - Object = CreateReferenceTemporary(CGF, T, InitializedDecl); - LValue TempLV = CGF.MakeAddrLValue(Object, - Adjustment.Field->getType()); - CGF.EmitStoreThroughLValue(CGF.EmitLoadOfLValue(LV), TempLV); + case SubobjectAdjustment::FieldAdjustment: { + LValue LV = CGF.MakeAddrLValue(Object, E->getType()); + LV = CGF.EmitLValueForField(LV, Adjustment.Field); + if (LV.isSimple()) { + Object = LV.getAddress(); break; } - - case SubobjectAdjustment::MemberPointerAdjustment: { - llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS); - Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress( - CGF, Object, Ptr, Adjustment.Ptr.MPT); - break; - } - } + + // For non-simple lvalues, we actually have to create a copy of + // the object we're binding to. + QualType T = Adjustment.Field->getType().getNonReferenceType() + .getUnqualifiedType(); + Object = CreateReferenceTemporary(CGF, T, InitializedDecl); + LValue TempLV = CGF.MakeAddrLValue(Object, + Adjustment.Field->getType()); + CGF.EmitStoreThroughLValue(CGF.EmitLoadOfLValue(LV), TempLV); + break; } - return Object; + case SubobjectAdjustment::MemberPointerAdjustment: { + llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS); + Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress( + CGF, Object, Ptr, Adjustment.Ptr.MPT); + break; + } + } } + + return Object; } if (RV.isAggregate()) @@ -396,9 +402,11 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E, const NamedDecl *InitializedDecl) { llvm::Value *ReferenceTemporary = 0; const CXXDestructorDecl *ReferenceTemporaryDtor = 0; + const InitListExpr *ReferenceInitializerList = 0; QualType ObjCARCReferenceLifetimeType; llvm::Value *Value = EmitExprForReferenceBinding(*this, E, ReferenceTemporary, ReferenceTemporaryDtor, + ReferenceInitializerList, ObjCARCReferenceLifetimeType, InitializedDecl); if (SanitizePerformTypeCheck && !E->getType()->isFunctionType()) { @@ -410,7 +418,8 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E, QualType Ty = E->getType(); EmitTypeCheck(TCK_ReferenceBinding, E->getExprLoc(), Value, Ty); } - if (!ReferenceTemporaryDtor && ObjCARCReferenceLifetimeType.isNull()) + if (!ReferenceTemporaryDtor && !ReferenceInitializerList && + ObjCARCReferenceLifetimeType.isNull()) return RValue::get(Value); // Make sure to call the destructor for the reference temporary. @@ -429,9 +438,15 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E, CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete); CleanupArg = cast<llvm::Constant>(ReferenceTemporary); } - CGM.getCXXABI().registerGlobalDtor(*this, CleanupFn, CleanupArg); + CGM.getCXXABI().registerGlobalDtor(*this, *VD, CleanupFn, CleanupArg); + } else if (ReferenceInitializerList) { + // FIXME: This is wrong. We need to register a global destructor to clean + // up the initializer_list object, rather than adding it as a local + // cleanup. + EmitStdInitializerListCleanup(ReferenceTemporary, + ReferenceInitializerList); } else { - assert(!ObjCARCReferenceLifetimeType.isNull()); + assert(!ObjCARCReferenceLifetimeType.isNull() && !VD->getTLSKind()); // Note: We intentionally do not register a global "destructor" to // release the object. } @@ -445,6 +460,9 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E, destroyCXXObject, getLangOpts().Exceptions); else PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary); + } else if (ReferenceInitializerList) { + EmitStdInitializerListCleanup(ReferenceTemporary, + ReferenceInitializerList); } else { switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) { case Qualifiers::OCL_None: @@ -885,6 +903,10 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitNullInitializationLValue(cast<CXXScalarValueInitExpr>(E)); case Expr::CXXDefaultArgExprClass: return EmitLValue(cast<CXXDefaultArgExpr>(E)->getExpr()); + case Expr::CXXDefaultInitExprClass: { + CXXDefaultInitExprScope Scope(*this); + return EmitLValue(cast<CXXDefaultInitExpr>(E)->getExpr()); + } case Expr::CXXTypeidExprClass: return EmitCXXTypeidLValue(cast<CXXTypeidExpr>(E)); @@ -1044,7 +1066,8 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) { llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue) { return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(), lvalue.getAlignment().getQuantity(), - lvalue.getType(), lvalue.getTBAAInfo()); + lvalue.getType(), lvalue.getTBAAInfo(), + lvalue.getTBAABaseType(), lvalue.getTBAAOffset()); } static bool hasBooleanRepresentation(QualType Ty) { @@ -1106,7 +1129,9 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) { llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, unsigned Alignment, QualType Ty, - llvm::MDNode *TBAAInfo) { + llvm::MDNode *TBAAInfo, + QualType TBAABaseType, + uint64_t TBAAOffset) { // For better performance, handle vector loads differently. if (Ty->isVectorType()) { llvm::Value *V; @@ -1158,8 +1183,11 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, Load->setVolatile(true); if (Alignment) Load->setAlignment(Alignment); - if (TBAAInfo) - CGM.DecorateInstruction(Load, TBAAInfo); + if (TBAAInfo) { + llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, + TBAAOffset); + CGM.DecorateInstruction(Load, TBAAPath, false/*ConvertTypeToTag*/); + } if ((SanOpts->Bool && hasBooleanRepresentation(Ty)) || (SanOpts->Enum && Ty->getAs<EnumType>())) { @@ -1217,7 +1245,8 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr, bool Volatile, unsigned Alignment, QualType Ty, llvm::MDNode *TBAAInfo, - bool isInit) { + bool isInit, QualType TBAABaseType, + uint64_t TBAAOffset) { // Handle vectors differently to get better performance. if (Ty->isVectorType()) { @@ -1268,15 +1297,19 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr, llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile); if (Alignment) Store->setAlignment(Alignment); - if (TBAAInfo) - CGM.DecorateInstruction(Store, TBAAInfo); + if (TBAAInfo) { + llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, + TBAAOffset); + CGM.DecorateInstruction(Store, TBAAPath, false/*ConvertTypeToTag*/); + } } void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue, bool isInit) { EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(), lvalue.getAlignment().getQuantity(), lvalue.getType(), - lvalue.getTBAAInfo(), isInit); + lvalue.getTBAAInfo(), isInit, lvalue.getTBAABaseType(), + lvalue.getTBAAOffset()); } /// EmitLoadOfLValue - Given an expression that represents a value lvalue, this @@ -1645,7 +1678,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, if (const VarDecl *VD = dyn_cast<VarDecl>(Exp->getDecl())) { if (VD->hasGlobalStorage()) { LV.setGlobalObjCRef(true); - LV.setThreadLocalRef(VD->isThreadSpecified()); + LV.setThreadLocalRef(VD->getTLSKind() != VarDecl::TLS_None); } } LV.setObjCArray(E->getType()->isArrayType()); @@ -1795,15 +1828,15 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { // Check if this is a global variable. - if (VD->hasLinkage() || VD->isStaticDataMember()) + if (VD->hasLinkage() || VD->isStaticDataMember()) { + // If it's thread_local, emit a call to its wrapper function instead. + if (VD->getTLSKind() == VarDecl::TLS_Dynamic) + return CGM.getCXXABI().EmitThreadLocalDeclRefExpr(*this, E); return EmitGlobalVarDeclLValue(*this, E, VD); + } bool isBlockVariable = VD->hasAttr<BlocksAttr>(); - bool NonGCable = VD->hasLocalStorage() && - !VD->getType()->isReferenceType() && - !isBlockVariable; - llvm::Value *V = LocalDeclMap.lookup(VD); if (!V && VD->isStaticLocal()) V = CGM.getStaticLocalDeclAddress(VD); @@ -1837,10 +1870,20 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { LV = MakeAddrLValue(V, T, Alignment); } + bool isLocalStorage = VD->hasLocalStorage(); + + bool NonGCable = isLocalStorage && + !VD->getType()->isReferenceType() && + !isBlockVariable; if (NonGCable) { LV.getQuals().removeObjCGCAttr(); LV.setNonGC(true); } + + bool isImpreciseLifetime = + (isLocalStorage && !VD->hasAttr<ObjCPreciseLifetimeAttr>()); + if (isImpreciseLifetime) + LV.setARCPreciseLifetime(ARCImpreciseLifetime); setObjCGCLValueClass(getContext(), E, LV); return LV; } @@ -2072,6 +2115,15 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) { llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) { llvm::Type *TargetTy = IntPtrTy; + // Floating-point types which fit into intptr_t are bitcast to integers + // and then passed directly (after zero-extension, if necessary). + if (V->getType()->isFloatingPointTy()) { + unsigned Bits = V->getType()->getPrimitiveSizeInBits(); + if (Bits <= TargetTy->getIntegerBitWidth()) + V = Builder.CreateBitCast(V, llvm::Type::getIntNTy(getLLVMContext(), + Bits)); + } + // Integers which fit in intptr_t are zero-extended and passed directly. if (V->getType()->isIntegerTy() && V->getType()->getIntegerBitWidth() <= TargetTy->getIntegerBitWidth()) @@ -2079,7 +2131,7 @@ llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) { // Pointers are passed directly, everything else is passed by address. if (!V->getType()->isPointerTy()) { - llvm::Value *Ptr = Builder.CreateAlloca(V->getType()); + llvm::Value *Ptr = CreateTempAlloca(V->getType()); Builder.CreateStore(V, Ptr); V = Ptr; } @@ -2443,6 +2495,17 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { llvm_unreachable("Unhandled member declaration!"); } +/// Given that we are currently emitting a lambda, emit an l-value for +/// one of its members. +LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field) { + assert(cast<CXXMethodDecl>(CurCodeDecl)->getParent()->isLambda()); + assert(cast<CXXMethodDecl>(CurCodeDecl)->getParent() == Field->getParent()); + QualType LambdaTagType = + getContext().getTagDeclType(Field->getParent()); + LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue, LambdaTagType); + return EmitLValueForField(LambdaLV, Field); +} + LValue CodeGenFunction::EmitLValueForField(LValue base, const FieldDecl *field) { if (field->isBitField()) { @@ -2479,9 +2542,12 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, llvm::Value *addr = base.getAddress(); unsigned cvr = base.getVRQualifiers(); + bool TBAAPath = CGM.getCodeGenOpts().StructPathTBAA; if (rec->isUnion()) { // For unions, there is no pointer adjustment. assert(!type->isReferenceType() && "union has reference member"); + // TODO: handle path-aware TBAA for union. + TBAAPath = false; } else { // For structs, we GEP to the field that the record layout suggests. unsigned idx = CGM.getTypes().getCGRecordLayout(rec).getLLVMFieldNo(field); @@ -2493,6 +2559,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, if (cvr & Qualifiers::Volatile) load->setVolatile(true); load->setAlignment(alignment.getQuantity()); + // Loading the reference will disable path-aware TBAA. + TBAAPath = false; if (CGM.shouldUseTBAA()) { llvm::MDNode *tbaa; if (mayAlias) @@ -2526,6 +2594,16 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, LValue LV = MakeAddrLValue(addr, type, alignment); LV.getQuals().addCVRQualifiers(cvr); + if (TBAAPath) { + const ASTRecordLayout &Layout = + getContext().getASTRecordLayout(field->getParent()); + // Set the base type to be the base type of the base LValue and + // update offset to be relative to the base type. + LV.setTBAABaseType(mayAlias ? getContext().CharTy : base.getTBAABaseType()); + LV.setTBAAOffset(mayAlias ? 0 : base.getTBAAOffset() + + Layout.getFieldOffset(field->getFieldIndex()) / + getContext().getCharWidth()); + } // __weak attribute on a field is ignored. if (LV.getQuals().getObjCGCAttr() == Qualifiers::Weak) @@ -2849,8 +2927,14 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV, RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue) { - if (CGDebugInfo *DI = getDebugInfo()) - DI->EmitLocation(Builder, E->getLocStart()); + if (CGDebugInfo *DI = getDebugInfo()) { + SourceLocation Loc = E->getLocStart(); + // Force column info to be generated so we can differentiate + // multiple call sites on the same line in the debug info. + const FunctionDecl* Callee = E->getDirectCallee(); + bool ForceColumnInfo = Callee && Callee->isInlineSpecified(); + DI->EmitLocation(Builder, Loc, ForceColumnInfo); + } // Builtins never have block type. if (E->getCallee()->getType()->isBlockPointerType()) @@ -2907,7 +2991,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, case Qualifiers::OCL_Strong: EmitARCRelease(Builder.CreateLoad(BaseValue, PseudoDtor->getDestroyedType().isVolatileQualified()), - /*precise*/ true); + ARCPreciseLifetime); break; case Qualifiers::OCL_Weak: diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 1ac13c01ed..b974e1dcc6 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -170,6 +170,10 @@ public: void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { Visit(DAE->getExpr()); } + void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + CodeGenFunction::CXXDefaultInitExprScope Scope(CGF); + Visit(DIE->getExpr()); + } void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); void VisitCXXConstructExpr(const CXXConstructExpr *E); void VisitLambdaExpr(LambdaExpr *E); @@ -1189,7 +1193,10 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // the optimizer, especially with bitfields. unsigned NumInitElements = E->getNumInits(); RecordDecl *record = E->getType()->castAs<RecordType>()->getDecl(); - + + // Prepare a 'this' for CXXDefaultInitExprs. + CodeGenFunction::FieldConstructionScope FCS(CGF, Dest.getAddr()); + if (record->isUnion()) { // Only initialize one field of a union. The field itself is // specified by the initializer list. @@ -1341,7 +1348,7 @@ static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) { // Reference values are always non-null and have the width of a pointer. if (Field->getType()->isReferenceType()) NumNonZeroBytes += CGF.getContext().toCharUnitsFromBits( - CGF.getContext().getTargetInfo().getPointerWidth(0)); + CGF.getTarget().getPointerWidth(0)); else NumNonZeroBytes += GetNumNonZeroBytesInInit(E, CGF); } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 13ae8bb01a..83c8ace98c 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -1451,7 +1451,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF, llvm::Value *PtrValue = CGF.Builder.CreateLoad(Ptr, ElementType.isVolatileQualified()); - CGF.EmitARCRelease(PtrValue, /*precise*/ true); + CGF.EmitARCRelease(PtrValue, ARCPreciseLifetime); break; } diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 5fc73aa790..36f974a313 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -182,6 +182,10 @@ public: ComplexPairTy VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); } + ComplexPairTy VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + CodeGenFunction::CXXDefaultInitExprScope Scope(CGF); + return Visit(DIE->getExpr()); + } ComplexPairTy VisitExprWithCleanups(ExprWithCleanups *E) { CGF.enterFullExpression(E); CodeGenFunction::RunCleanupsScope Scope(CGF); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index e3e5d66605..f5c8187c26 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -757,6 +757,12 @@ public: return Visit(DAE->getExpr()); } + llvm::Constant *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + // No need for a DefaultInitExprScope: we don't handle 'this' in a + // constant expression. + return Visit(DIE->getExpr()); + } + llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { return Visit(E->GetTemporaryExpr()); } @@ -1018,8 +1024,7 @@ llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D, if (const CXXConstructExpr *E = dyn_cast_or_null<CXXConstructExpr>(D.getInit())) { const CXXConstructorDecl *CD = E->getConstructor(); - if (CD->isTrivial() && CD->isDefaultConstructor() && - Ty->getAsCXXRecordDecl()->hasTrivialDestructor()) + if (CD->isTrivial() && CD->isDefaultConstructor()) return EmitNullConstant(D.getType()); } } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 56b150ad38..c1c252d12b 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -344,6 +344,10 @@ public: Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); } + Value *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + CodeGenFunction::CXXDefaultInitExprScope Scope(CGF); + return Visit(DIE->getExpr()); + } Value *VisitCXXThisExpr(CXXThisExpr *TE) { return CGF.LoadCXXThis(); } @@ -583,62 +587,93 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc, Check = Builder.CreateAnd(GE, LE); } } else { - // Floating-point to integer or floating-point to floating-point. This has - // undefined behavior if the source is +-Inf, NaN, or doesn't fit into the - // destination type. const llvm::fltSemantics &SrcSema = CGF.getContext().getFloatTypeSemantics(OrigSrcType); - APFloat MaxSrc(SrcSema, APFloat::uninitialized); - APFloat MinSrc(SrcSema, APFloat::uninitialized); - if (isa<llvm::IntegerType>(DstTy)) { + // Floating-point to integer. This has undefined behavior if the source is + // +-Inf, NaN, or doesn't fit into the destination type (after truncation + // to an integer). unsigned Width = CGF.getContext().getIntWidth(DstType); bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType(); APSInt Min = APSInt::getMinValue(Width, Unsigned); + APFloat MinSrc(SrcSema, APFloat::uninitialized); if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) & APFloat::opOverflow) // Don't need an overflow check for lower bound. Just check for // -Inf/NaN. - MinSrc = APFloat::getLargest(SrcSema, true); + MinSrc = APFloat::getInf(SrcSema, true); + else + // Find the largest value which is too small to represent (before + // truncation toward zero). + MinSrc.subtract(APFloat(SrcSema, 1), APFloat::rmTowardNegative); APSInt Max = APSInt::getMaxValue(Width, Unsigned); + APFloat MaxSrc(SrcSema, APFloat::uninitialized); if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) & APFloat::opOverflow) // Don't need an overflow check for upper bound. Just check for // +Inf/NaN. - MaxSrc = APFloat::getLargest(SrcSema, false); + MaxSrc = APFloat::getInf(SrcSema, false); + else + // Find the smallest value which is too large to represent (before + // truncation toward zero). + MaxSrc.add(APFloat(SrcSema, 1), APFloat::rmTowardPositive); + + // If we're converting from __half, convert the range to float to match + // the type of src. + if (OrigSrcType->isHalfType()) { + const llvm::fltSemantics &Sema = + CGF.getContext().getFloatTypeSemantics(SrcType); + bool IsInexact; + MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact); + MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact); + } + + llvm::Value *GE = + Builder.CreateFCmpOGT(Src, llvm::ConstantFP::get(VMContext, MinSrc)); + llvm::Value *LE = + Builder.CreateFCmpOLT(Src, llvm::ConstantFP::get(VMContext, MaxSrc)); + Check = Builder.CreateAnd(GE, LE); } else { + // FIXME: Maybe split this sanitizer out from float-cast-overflow. + // + // Floating-point to floating-point. This has undefined behavior if the + // source is not in the range of representable values of the destination + // type. The C and C++ standards are spectacularly unclear here. We + // diagnose finite out-of-range conversions, but allow infinities and NaNs + // to convert to the corresponding value in the smaller type. + // + // C11 Annex F gives all such conversions defined behavior for IEC 60559 + // conforming implementations. Unfortunately, LLVM's fptrunc instruction + // does not. + + // Converting from a lower rank to a higher rank can never have + // undefined behavior, since higher-rank types must have a superset + // of values of lower-rank types. + if (CGF.getContext().getFloatingTypeOrder(OrigSrcType, DstType) != 1) + return; + + assert(!OrigSrcType->isHalfType() && + "should not check conversion from __half, it has the lowest rank"); + const llvm::fltSemantics &DstSema = CGF.getContext().getFloatTypeSemantics(DstType); - bool IsInexact; - - MinSrc = APFloat::getLargest(DstSema, true); - if (MinSrc.convert(SrcSema, APFloat::rmTowardZero, &IsInexact) & - APFloat::opOverflow) - MinSrc = APFloat::getLargest(SrcSema, true); + APFloat MinBad = APFloat::getLargest(DstSema, false); + APFloat MaxBad = APFloat::getInf(DstSema, false); - MaxSrc = APFloat::getLargest(DstSema, false); - if (MaxSrc.convert(SrcSema, APFloat::rmTowardZero, &IsInexact) & - APFloat::opOverflow) - MaxSrc = APFloat::getLargest(SrcSema, false); - } - - // If we're converting from __half, convert the range to float to match - // the type of src. - if (OrigSrcType->isHalfType()) { - const llvm::fltSemantics &Sema = - CGF.getContext().getFloatTypeSemantics(SrcType); bool IsInexact; - MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact); - MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact); + MinBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact); + MaxBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact); + + Value *AbsSrc = CGF.EmitNounwindRuntimeCall( + CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Src->getType()), Src); + llvm::Value *GE = + Builder.CreateFCmpOGT(AbsSrc, llvm::ConstantFP::get(VMContext, MinBad)); + llvm::Value *LE = + Builder.CreateFCmpOLT(AbsSrc, llvm::ConstantFP::get(VMContext, MaxBad)); + Check = Builder.CreateNot(Builder.CreateAnd(GE, LE)); } - - llvm::Value *GE = - Builder.CreateFCmpOGE(Src, llvm::ConstantFP::get(VMContext, MinSrc)); - llvm::Value *LE = - Builder.CreateFCmpOLE(Src, llvm::ConstantFP::get(VMContext, MaxSrc)); - Check = Builder.CreateAnd(GE, LE); } // FIXME: Provide a SourceLocation. @@ -1603,8 +1638,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, else { llvm::APFloat F(static_cast<float>(amount)); bool ignored; - F.convert(CGF.Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero, - &ignored); + F.convert(CGF.getTarget().getLongDoubleFormat(), + llvm::APFloat::rmTowardZero, &ignored); amt = llvm::ConstantFP::get(VMContext, F); } value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec"); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index ad7d62951a..713509bf67 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -21,6 +21,7 @@ #include "clang/AST/StmtObjC.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/CallSite.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" using namespace clang; @@ -109,32 +110,50 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E, if (DLE) Keys = CreateMemTemp(ElementArrayType, "keys"); + // In ARC, we may need to do extra work to keep all the keys and + // values alive until after the call. + SmallVector<llvm::Value *, 16> NeededObjects; + bool TrackNeededObjects = + (getLangOpts().ObjCAutoRefCount && + CGM.getCodeGenOpts().OptimizationLevel != 0); + // Perform the actual initialialization of the array(s). for (uint64_t i = 0; i < NumElements; i++) { if (ALE) { - // Emit the initializer. + // Emit the element and store it to the appropriate array slot. const Expr *Rhs = ALE->getElement(i); LValue LV = LValue::MakeAddr(Builder.CreateStructGEP(Objects, i), ElementType, Context.getTypeAlignInChars(Rhs->getType()), Context); - EmitScalarInit(Rhs, /*D=*/0, LV, /*capturedByInit=*/false); + + llvm::Value *value = EmitScalarExpr(Rhs); + EmitStoreThroughLValue(RValue::get(value), LV, true); + if (TrackNeededObjects) { + NeededObjects.push_back(value); + } } else { - // Emit the key initializer. + // Emit the key and store it to the appropriate array slot. const Expr *Key = DLE->getKeyValueElement(i).Key; LValue KeyLV = LValue::MakeAddr(Builder.CreateStructGEP(Keys, i), ElementType, Context.getTypeAlignInChars(Key->getType()), Context); - EmitScalarInit(Key, /*D=*/0, KeyLV, /*capturedByInit=*/false); + llvm::Value *keyValue = EmitScalarExpr(Key); + EmitStoreThroughLValue(RValue::get(keyValue), KeyLV, /*isInit=*/true); - // Emit the value initializer. + // Emit the value and store it to the appropriate array slot. const Expr *Value = DLE->getKeyValueElement(i).Value; LValue ValueLV = LValue::MakeAddr(Builder.CreateStructGEP(Objects, i), ElementType, Context.getTypeAlignInChars(Value->getType()), Context); - EmitScalarInit(Value, /*D=*/0, ValueLV, /*capturedByInit=*/false); + llvm::Value *valueValue = EmitScalarExpr(Value); + EmitStoreThroughLValue(RValue::get(valueValue), ValueLV, /*isInit=*/true); + if (TrackNeededObjects) { + NeededObjects.push_back(keyValue); + NeededObjects.push_back(valueValue); + } } } @@ -172,6 +191,15 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E, Sel, Receiver, Args, Class, MethodWithObjects); + + // The above message send needs these objects, but in ARC they are + // passed in a buffer that is essentially __unsafe_unretained. + // Therefore we must prevent the optimizer from releasing them until + // after the call. + if (TrackNeededObjects) { + EmitARCIntrinsicUse(NeededObjects); + } + return Builder.CreateBitCast(result.getScalarVal(), ConvertType(E->getType())); } @@ -686,7 +714,7 @@ PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM, } llvm::Triple::ArchType arch = - CGM.getContext().getTargetInfo().getTriple().getArch(); + CGM.getTarget().getTriple().getArch(); // Most architectures require memory to fit within a single cache // line, so the alignment has to be at least the size of the access. @@ -1189,7 +1217,8 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl, selfDecl->getType(), CK_LValueToRValue, &self, VK_RValue); ObjCIvarRefExpr ivarRef(ivar, ivar->getType().getNonReferenceType(), - SourceLocation(), &selfLoad, true, true); + SourceLocation(), SourceLocation(), + &selfLoad, true, true); ParmVarDecl *argDecl = *setterMethod->param_begin(); QualType argType = argDecl->getType().getNonReferenceType(); @@ -1372,8 +1401,10 @@ bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) { } llvm::Value *CodeGenFunction::LoadObjCSelf() { - const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); - return Builder.CreateLoad(LocalDeclMap[OMD->getSelfDecl()], "self"); + VarDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl(); + DeclRefExpr DRE(Self, /*is enclosing local*/ (CurFuncDecl != CurCodeDecl), + Self->getType(), VK_LValue, SourceLocation()); + return EmitLoadOfScalar(EmitDeclRefLValue(&DRE)); } QualType CodeGenFunction::TypeOfSelfObject() { @@ -1686,7 +1717,8 @@ namespace { llvm::Value *object; void Emit(CodeGenFunction &CGF, Flags flags) { - CGF.EmitARCRelease(object, /*precise*/ true); + // Releases at the end of the full-expression are imprecise. + CGF.EmitARCRelease(object, ARCImpreciseLifetime); } }; } @@ -1706,6 +1738,21 @@ llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type, return EmitARCRetainAutorelease(type, value); } +/// Given a number of pointers, inform the optimizer that they're +/// being intrinsically used up until this point in the program. +void CodeGenFunction::EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values) { + llvm::Constant *&fn = CGM.getARCEntrypoints().clang_arc_use; + if (!fn) { + llvm::FunctionType *fnType = + llvm::FunctionType::get(CGM.VoidTy, ArrayRef<llvm::Type*>(), true); + fn = CGM.CreateRuntimeFunction(fnType, "clang.arc.use"); + } + + // This isn't really a "runtime" function, but as an intrinsic it + // doesn't really matter as long as we align things up. + EmitNounwindRuntimeCall(fn, values); +} + static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM, llvm::FunctionType *type, @@ -1940,7 +1987,8 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) { /// Release the given object. /// call void \@objc_release(i8* %value) -void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) { +void CodeGenFunction::EmitARCRelease(llvm::Value *value, + ARCPreciseLifetime_t precise) { if (isa<llvm::ConstantPointerNull>(value)) return; llvm::Constant *&fn = CGM.getARCEntrypoints().objc_release; @@ -1956,7 +2004,7 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) { // Call objc_release. llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value); - if (!precise) { + if (precise == ARCImpreciseLifetime) { SmallVector<llvm::Value*,1> args; call->setMetadata("clang.imprecise_release", llvm::MDNode::get(Builder.getContext(), args)); @@ -1972,7 +2020,8 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) { /// At -O1 and above, just load and call objc_release. /// /// call void \@objc_storeStrong(i8** %addr, i8* null) -void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr, bool precise) { +void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr, + ARCPreciseLifetime_t precise) { if (CGM.getCodeGenOpts().OptimizationLevel == 0) { llvm::PointerType *addrTy = cast<llvm::PointerType>(addr->getType()); llvm::Value *null = llvm::ConstantPointerNull::get( @@ -2042,7 +2091,7 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst, EmitStoreOfScalar(newValue, dst); // Finally, release the old value. - EmitARCRelease(oldValue, /*precise*/ false); + EmitARCRelease(oldValue, dst.isARCPreciseLifetime()); return newValue; } @@ -2210,7 +2259,8 @@ void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) { fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPop"); } - EmitNounwindRuntimeCall(fn, value); + // objc_autoreleasePoolPop can throw. + EmitRuntimeCallOrInvoke(fn, value); } /// Produce the code to do an MRR version objc_autoreleasepool_push. @@ -2254,13 +2304,13 @@ void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) { void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF, llvm::Value *addr, QualType type) { - CGF.EmitARCDestroyStrong(addr, /*precise*/ true); + CGF.EmitARCDestroyStrong(addr, ARCPreciseLifetime); } void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF, llvm::Value *addr, QualType type) { - CGF.EmitARCDestroyStrong(addr, /*precise*/ false); + CGF.EmitARCDestroyStrong(addr, ARCImpreciseLifetime); } void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF, @@ -2737,7 +2787,7 @@ CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e, llvm::Value *oldValue = EmitLoadOfScalar(lvalue); EmitStoreOfScalar(value, lvalue); - EmitARCRelease(oldValue, /*precise*/ false); + EmitARCRelease(oldValue, lvalue.isARCPreciseLifetime()); } else { value = EmitARCStoreStrong(lvalue, value, ignored); } @@ -2829,7 +2879,6 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction( SourceLocation(), SourceLocation(), II, C.VoidTy, 0, SC_Static, - SC_None, false, false); @@ -2914,7 +2963,6 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( SourceLocation(), SourceLocation(), II, C.VoidTy, 0, SC_Static, - SC_None, false, false); diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 975f9ac4af..e8498b06ad 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -1617,7 +1617,7 @@ struct NullReturnState { RValue RV = I->RV; assert(RV.isScalar() && "NullReturnState::complete - arg not on object"); - CGF.EmitARCRelease(RV.getScalarVal(), true); + CGF.EmitARCRelease(RV.getScalarVal(), ARCImpreciseLifetime); } } } @@ -1949,8 +1949,8 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, bool hasUnion = false; SkipIvars.clear(); IvarsInfo.clear(); - unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); - unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getTarget().getCharWidth(); // __isa is the first field in block descriptor and must assume by runtime's // convention that it is GC'able. @@ -2077,7 +2077,7 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, if (RecFields.empty()) return; - unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned ByteSizeInBits = CGM.getTarget().getCharWidth(); for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { const FieldDecl *Field = RecFields[i]; @@ -2316,8 +2316,8 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) { llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy); if (RunSkipBlockVars.empty()) return nullPtr; - unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); - unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getTarget().getCharWidth(); unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits; // Sort on byte position; captures might not be allocated in order, @@ -2393,7 +2393,7 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) { printf("\n Inline instruction for BYREF variable layout: "); else printf("\n Inline instruction for block variable layout: "); - printf("0x0%llx\n", (unsigned long long)Result); + printf("0x0%" PRIx64 "\n", Result); } if (WordSizeInBytes == 8) { const llvm::APInt Instruction(64, Result); @@ -2468,8 +2468,8 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, RunSkipBlockVars.clear(); bool hasUnion = false; - unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); - unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getTarget().getCharWidth(); unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits; const BlockDecl *blockDecl = blockInfo.getBlockDecl(); @@ -3519,6 +3519,9 @@ namespace { if (isa<ObjCAtTryStmt>(S)) { if (const ObjCAtFinallyStmt* FinallyStmt = cast<ObjCAtTryStmt>(S).getFinallyStmt()) { + // Don't try to do the @finally if this is an EH cleanup. + if (flags.isForEHCleanup()) return; + // Save the current cleanup destination in case there's // control flow inside the finally statement. llvm::Value *CurCleanupDest = @@ -3860,7 +3863,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::Value *PropagatingExnVar = 0; // Push a normal cleanup to leave the try scope. - CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalCleanup, &S, + CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalAndEHCleanup, &S, SyncArgSlot, CallTryExitVar, ExceptionData, @@ -4534,8 +4537,8 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, if (RecFields.empty()) return; - unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); - unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getTarget().getCharWidth(); if (!RD && CGM.getLangOpts().ObjCAutoRefCount) { const FieldDecl *FirstField = RecFields[0]; FirstFieldDelta = diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp index abd10a29c9..9c0d5189f8 100644 --- a/lib/CodeGen/CGObjCRuntime.cpp +++ b/lib/CodeGen/CGObjCRuntime.cpp @@ -117,7 +117,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, // a synthesized ivar can never be a bit-field, so this is safe. uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar); uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth(); - uint64_t AlignmentBits = CGF.CGM.getContext().getTargetInfo().getCharAlign(); + uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign(); uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext()); CharUnits StorageSize = CGF.CGM.getContext().toCharUnitsFromBits( diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 869843cbd4..40dc6bfa3b 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -412,6 +412,9 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) { case Type::RValueReference: llvm_unreachable("References shouldn't get here"); + case Type::Auto: + llvm_unreachable("Undeduced auto type shouldn't get here"); + case Type::Builtin: // GCC treats vector and complex types as fundamental types. case Type::Vector: @@ -619,6 +622,9 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { case Type::RValueReference: llvm_unreachable("References shouldn't get here"); + case Type::Auto: + llvm_unreachable("Undeduced auto type shouldn't get here"); + case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 2c6438b0b6..30ab528ffb 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -276,7 +276,7 @@ bool CGRecordLayoutBuilder::LayoutBitfields(const ASTRecordLayout &Layout, uint64_t FirstFieldOffset = Layout.getFieldOffset(FirstFieldNo); uint64_t NextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset); - unsigned CharAlign = Types.getContext().getTargetInfo().getCharAlign(); + unsigned CharAlign = Types.getTarget().getCharAlign(); assert(FirstFieldOffset % CharAlign == 0 && "First field offset is misaligned"); CharUnits FirstFieldOffsetInBytes @@ -352,7 +352,7 @@ bool CGRecordLayoutBuilder::LayoutBitfields(const ASTRecordLayout &Layout, assert(EndOffset >= (FirstFieldOffset + TotalBits) && "End offset is not past the end of the known storage bits."); uint64_t SpaceBits = EndOffset - FirstFieldOffset; - uint64_t LongBits = Types.getContext().getTargetInfo().getLongWidth(); + uint64_t LongBits = Types.getTarget().getLongWidth(); uint64_t WidenedBits = (StorageBits / LongBits) * LongBits + llvm::NextPowerOf2(StorageBits % LongBits - 1); assert(WidenedBits >= StorageBits && "Widening shrunk the bits!"); @@ -455,7 +455,7 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field, return 0; unsigned StorageBits = llvm::RoundUpToAlignment( - FieldSize, Types.getContext().getTargetInfo().getCharAlign()); + FieldSize, Types.getTarget().getCharAlign()); CharUnits NumBytesToAppend = Types.getContext().toCharUnitsFromBits(StorageBits); @@ -814,7 +814,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { // Lay out the virtual bases. The MS ABI uses a different // algorithm here due to the lack of primary virtual bases. - if (Types.getContext().getTargetInfo().getCXXABI().hasPrimaryVBases()) { + if (Types.getTarget().getCXXABI().hasPrimaryVBases()) { RD->getIndirectPrimaryBases(IndirectPrimaryBases); if (Layout.isPrimaryBaseVirtual()) IndirectPrimaryBases.insert(Layout.getPrimaryBase()); diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 9e7ddfbdc1..5e2ebe0d9c 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -37,6 +37,9 @@ void CodeGenFunction::EmitStopPoint(const Stmt *S) { else Loc = S->getLocStart(); DI->EmitLocation(Builder, Loc); + + //if (++NumStopPoints == 1) + LastStopPoint = Loc; } } @@ -134,7 +137,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break; case Stmt::GCCAsmStmtClass: // Intentional fall-through. case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break; - + case Stmt::CapturedStmtClass: + EmitCapturedStmt(cast<CapturedStmt>(*S)); + break; case Stmt::ObjCAtTryStmtClass: EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S)); break; @@ -319,6 +324,12 @@ CodeGenFunction::getJumpDestForLabel(const LabelDecl *D) { } void CodeGenFunction::EmitLabel(const LabelDecl *D) { + // Add this label to the current lexical scope if we're within any + // normal cleanups. Jumps "in" to this label --- when permitted by + // the language --- may need to be routed around such cleanups. + if (EHStack.hasNormalCleanups() && CurLexicalScope) + CurLexicalScope->addLabel(D); + JumpDest &Dest = LabelMap[D]; // If we didn't need a forward reference to this label, just go @@ -330,16 +341,36 @@ void CodeGenFunction::EmitLabel(const LabelDecl *D) { // it from the branch-fixups list. } else { assert(!Dest.getScopeDepth().isValid() && "already emitted label!"); - Dest = JumpDest(Dest.getBlock(), - EHStack.stable_begin(), - Dest.getDestIndex()); - + Dest.setScopeDepth(EHStack.stable_begin()); ResolveBranchFixups(Dest.getBlock()); } EmitBlock(Dest.getBlock()); } +/// Change the cleanup scope of the labels in this lexical scope to +/// match the scope of the enclosing context. +void CodeGenFunction::LexicalScope::rescopeLabels() { + assert(!Labels.empty()); + EHScopeStack::stable_iterator innermostScope + = CGF.EHStack.getInnermostNormalCleanup(); + + // Change the scope depth of all the labels. + for (SmallVectorImpl<const LabelDecl*>::const_iterator + i = Labels.begin(), e = Labels.end(); i != e; ++i) { + assert(CGF.LabelMap.count(*i)); + JumpDest &dest = CGF.LabelMap.find(*i)->second; + assert(dest.getScopeDepth().isValid()); + assert(innermostScope.encloses(dest.getScopeDepth())); + dest.setScopeDepth(innermostScope); + } + + // Reparent the labels if the new scope also has cleanups. + if (innermostScope != EHScopeStack::stable_end() && ParentScope) { + ParentScope->Labels.append(Labels.begin(), Labels.end()); + } +} + void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) { EmitLabel(S.getDecl()); @@ -768,8 +799,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { // FIXME: Clean this up by using an LValue for ReturnTemp, // EmitStoreThroughLValue, and EmitAnyExpr. - if (S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable() && - !Target.useGlobalsForAutomaticVariables()) { + if (S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable()) { // Apply the named return value optimization for this return statement, // which means doing nothing: the appropriate result has already been // constructed into the NRVO variable. @@ -812,6 +842,10 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { } } + NumReturnExprs += 1; + if (RV == 0 || RV->isEvaluatable(getContext())) + NumSimpleReturnExprs += 1; + cleanupScope.ForceCleanup(); EmitBranchThroughCleanup(ReturnBlock); } @@ -1424,7 +1458,7 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str, for (unsigned i = 0, e = StrVal.size()-1; i != e; ++i) { if (StrVal[i] != '\n') continue; SourceLocation LineLoc = Str->getLocationOfByte(i+1, SM, LangOpts, - CGF.Target); + CGF.getTarget()); Locs.push_back(llvm::ConstantInt::get(CGF.Int32Ty, LineLoc.getRawEncoding())); } @@ -1442,18 +1476,23 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) { - TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i), - S.getOutputName(i)); - bool IsValid = Target.validateOutputConstraint(Info); (void)IsValid; + StringRef Name; + if (const GCCAsmStmt *GAS = dyn_cast<GCCAsmStmt>(&S)) + Name = GAS->getOutputName(i); + TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i), Name); + bool IsValid = getTarget().validateOutputConstraint(Info); (void)IsValid; assert(IsValid && "Failed to parse output constraint"); OutputConstraintInfos.push_back(Info); } for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) { - TargetInfo::ConstraintInfo Info(S.getInputConstraint(i), - S.getInputName(i)); - bool IsValid = Target.validateInputConstraint(OutputConstraintInfos.data(), - S.getNumOutputs(), Info); + StringRef Name; + if (const GCCAsmStmt *GAS = dyn_cast<GCCAsmStmt>(&S)) + Name = GAS->getInputName(i); + TargetInfo::ConstraintInfo Info(S.getInputConstraint(i), Name); + bool IsValid = + getTarget().validateInputConstraint(OutputConstraintInfos.data(), + S.getNumOutputs(), Info); assert(IsValid && "Failed to parse input constraint"); (void)IsValid; InputConstraintInfos.push_back(Info); } @@ -1477,13 +1516,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // Simplify the output constraint. std::string OutputConstraint(S.getOutputConstraint(i)); - OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1, Target); + OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1, + getTarget()); const Expr *OutExpr = S.getOutputExpr(i); OutExpr = OutExpr->IgnoreParenNoopCasts(getContext()); OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr, - Target, CGM, S); + getTarget(), CGM, S); LValue Dest = EmitLValue(OutExpr); if (!Constraints.empty()) @@ -1564,13 +1604,13 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // Simplify the input constraint. std::string InputConstraint(S.getInputConstraint(i)); - InputConstraint = SimplifyConstraint(InputConstraint.c_str(), Target, + InputConstraint = SimplifyConstraint(InputConstraint.c_str(), getTarget(), &OutputConstraintInfos); InputConstraint = AddVariableConstraints(InputConstraint, *InputExpr->IgnoreParenNoopCasts(getContext()), - Target, CGM, S); + getTarget(), CGM, S); llvm::Value *Arg = EmitAsmInput(Info, InputExpr, Constraints); @@ -1622,7 +1662,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { StringRef Clobber = S.getClobber(i); if (Clobber != "memory" && Clobber != "cc") - Clobber = Target.getNormalizedGCCRegisterName(Clobber); + Clobber = getTarget().getNormalizedGCCRegisterName(Clobber); if (i != 0 || NumConstraints != 0) Constraints += ','; @@ -1633,7 +1673,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { } // Add machine specific clobbers - std::string MachineClobbers = Target.getClobbers(); + std::string MachineClobbers = getTarget().getClobbers(); if (!MachineClobbers.empty()) { if (!Constraints.empty()) Constraints += ','; @@ -1710,3 +1750,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i]); } } + +void CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S) { + llvm_unreachable("not implemented yet"); +} diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index 6b0c271a08..b625b866c0 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -97,6 +97,10 @@ public: } }; +/// Does an ARC strong l-value have precise lifetime? +enum ARCPreciseLifetime_t { + ARCImpreciseLifetime, ARCPreciseLifetime +}; /// LValue - This represents an lvalue references. Because C/C++ allow /// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a @@ -147,8 +151,17 @@ class LValue { // Lvalue is a thread local reference bool ThreadLocalRef : 1; + // Lvalue has ARC imprecise lifetime. We store this inverted to try + // to make the default bitfield pattern all-zeroes. + bool ImpreciseLifetime : 1; + Expr *BaseIvarExp; + /// Used by struct-path-aware TBAA. + QualType TBAABaseType; + /// Offset relative to the base type. + uint64_t TBAAOffset; + /// TBAAInfo - TBAA information to attach to dereferences of this LValue. llvm::MDNode *TBAAInfo; @@ -164,8 +177,13 @@ private: // Initialize Objective-C flags. this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false; + this->ImpreciseLifetime = false; this->ThreadLocalRef = false; this->BaseIvarExp = 0; + + // Initialize fields for TBAA. + this->TBAABaseType = Type; + this->TBAAOffset = 0; this->TBAAInfo = TBAAInfo; } @@ -202,6 +220,13 @@ public: bool isThreadLocalRef() const { return ThreadLocalRef; } void setThreadLocalRef(bool Value) { ThreadLocalRef = Value;} + ARCPreciseLifetime_t isARCPreciseLifetime() const { + return ARCPreciseLifetime_t(!ImpreciseLifetime); + } + void setARCPreciseLifetime(ARCPreciseLifetime_t value) { + ImpreciseLifetime = (value == ARCImpreciseLifetime); + } + bool isObjCWeak() const { return Quals.getObjCGCAttr() == Qualifiers::Weak; } @@ -216,6 +241,12 @@ public: Expr *getBaseIvarExp() const { return BaseIvarExp; } void setBaseIvarExp(Expr *V) { BaseIvarExp = V; } + QualType getTBAABaseType() const { return TBAABaseType; } + void setTBAABaseType(QualType T) { TBAABaseType = T; } + + uint64_t getTBAAOffset() const { return TBAAOffset; } + void setTBAAOffset(uint64_t O) { TBAAOffset = O; } + llvm::MDNode *getTBAAInfo() const { return TBAAInfo; } void setTBAAInfo(llvm::MDNode *N) { TBAAInfo = N; } diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 98008ccde6..9ca2295a92 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS asmparser bitreader bitwriter + irreader instrumentation ipo linker diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp index 8591961928..679cfeb6ed 100644 --- a/lib/CodeGen/CodeGenAction.cpp +++ b/lib/CodeGen/CodeGenAction.cpp @@ -23,9 +23,9 @@ #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/Linker.h" #include "llvm/Pass.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/Timer.h" diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 27ef65fa94..75c60edbba 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -20,6 +20,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/StmtCXX.h" +#include "clang/Basic/OpenCL.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/IR/DataLayout.h" @@ -30,8 +31,7 @@ using namespace clang; using namespace CodeGen; CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) - : CodeGenTypeCache(cgm), CGM(cgm), - Target(CGM.getContext().getTargetInfo()), + : CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()), Builder(cgm.getModule().getContext()), SanitizePerformTypeCheck(CGM.getSanOpts().Null | CGM.getSanOpts().Alignment | @@ -41,11 +41,14 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) AutoreleaseResult(false), BlockInfo(0), BlockPointer(0), LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1), FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0), - DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false), + DebugInfo(0), DisableDebugInfo(false), CalleeWithThisReturn(0), + DidCallStackSave(false), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0), + NumReturnExprs(0), NumSimpleReturnExprs(0), CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), + CXXDefaultInitExprThis(0), CXXStructorImplicitParamDecl(0), CXXStructorImplicitParamValue(0), - OutermostConditional(0), TerminateLandingPad(0), + OutermostConditional(0), CurLexicalScope(0), TerminateLandingPad(0), TerminateHandler(0), TrapBB(0) { if (!suppressNewContext) CGM.getCXXABI().getMangleContext().startNewFunction(); @@ -89,6 +92,9 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) { #include "clang/AST/TypeNodes.def" llvm_unreachable("non-canonical or dependent type in IR-generation"); + case Type::Auto: + llvm_unreachable("undeduced auto type in IR-generation"); + // Various scalar types. case Type::Builtin: case Type::Pointer: @@ -182,15 +188,36 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { assert(BreakContinueStack.empty() && "mismatched push/pop in break/continue stack!"); - if (CGDebugInfo *DI = getDebugInfo()) - DI->EmitLocation(Builder, EndLoc); + bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0 + && NumSimpleReturnExprs == NumReturnExprs; + // If the function contains only a simple return statement, the + // cleanup code may become the first breakpoint in the function. To + // be safe, set the debug location for it to the location of the + // return statement. Otherwise point it to end of the function's + // lexical scope. + if (CGDebugInfo *DI = getDebugInfo()) { + if (OnlySimpleReturnStmts) + DI->EmitLocation(Builder, LastStopPoint); + else + DI->EmitLocation(Builder, EndLoc); + } // Pop any cleanups that might have been associated with the // parameters. Do this in whatever block we're currently in; it's // important to do this before we enter the return block or return // edges will be *really* confused. - if (EHStack.stable_begin() != PrologueCleanupDepth) - PopCleanupBlocks(PrologueCleanupDepth); + bool EmitRetDbgLoc = true; + if (EHStack.stable_begin() != PrologueCleanupDepth) { + PopCleanupBlocks(PrologueCleanupDepth, EndLoc); + + // Make sure the line table doesn't jump back into the body for + // the ret after it's been at EndLoc. + EmitRetDbgLoc = false; + + if (CGDebugInfo *DI = getDebugInfo()) + if (OnlySimpleReturnStmts) + DI->EmitLocation(Builder, EndLoc); + } // Emit function epilog (to return). EmitReturnBlock(); @@ -203,7 +230,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { DI->EmitFunctionEnd(Builder); } - EmitFunctionEpilog(*CurFnInfo); + EmitFunctionEpilog(*CurFnInfo, EmitRetDbgLoc); EmitEndEHSpec(CurCodeDecl); assert(EHStack.empty() && @@ -277,35 +304,112 @@ void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) { void CodeGenFunction::EmitMCountInstrumentation() { llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); - llvm::Constant *MCountFn = CGM.CreateRuntimeFunction(FTy, - Target.getMCountName()); + llvm::Constant *MCountFn = + CGM.CreateRuntimeFunction(FTy, getTarget().getMCountName()); EmitNounwindRuntimeCall(MCountFn); } // OpenCL v1.2 s5.6.4.6 allows the compiler to store kernel argument // information in the program executable. The argument information stored // includes the argument name, its type, the address and access qualifiers used. -// FIXME: Add type, address, and access qualifiers. static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn, CodeGenModule &CGM,llvm::LLVMContext &Context, - SmallVector <llvm::Value*, 5> &kernelMDArgs) { - - // Create MDNodes that represents the kernel arg metadata. + SmallVector <llvm::Value*, 5> &kernelMDArgs, + CGBuilderTy& Builder, ASTContext &ASTCtx) { + // Create MDNodes that represent the kernel arg metadata. // Each MDNode is a list in the form of "key", N number of values which is // the same number of values as their are kernel arguments. + // MDNode for the kernel argument address space qualifiers. + SmallVector<llvm::Value*, 8> addressQuals; + addressQuals.push_back(llvm::MDString::get(Context, "kernel_arg_addr_space")); + + // MDNode for the kernel argument access qualifiers (images only). + SmallVector<llvm::Value*, 8> accessQuals; + accessQuals.push_back(llvm::MDString::get(Context, "kernel_arg_access_qual")); + + // MDNode for the kernel argument type names. + SmallVector<llvm::Value*, 8> argTypeNames; + argTypeNames.push_back(llvm::MDString::get(Context, "kernel_arg_type")); + + // MDNode for the kernel argument type qualifiers. + SmallVector<llvm::Value*, 8> argTypeQuals; + argTypeQuals.push_back(llvm::MDString::get(Context, "kernel_arg_type_qual")); + // MDNode for the kernel argument names. SmallVector<llvm::Value*, 8> argNames; argNames.push_back(llvm::MDString::get(Context, "kernel_arg_name")); for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) { const ParmVarDecl *parm = FD->getParamDecl(i); + QualType ty = parm->getType(); + std::string typeQuals; + + if (ty->isPointerType()) { + QualType pointeeTy = ty->getPointeeType(); + + // Get address qualifier. + addressQuals.push_back(Builder.getInt32(ASTCtx.getTargetAddressSpace( + pointeeTy.getAddressSpace()))); + + // Get argument type name. + std::string typeName = pointeeTy.getUnqualifiedType().getAsString() + "*"; + + // Turn "unsigned type" to "utype" + std::string::size_type pos = typeName.find("unsigned"); + if (pos != std::string::npos) + typeName.erase(pos+1, 8); + + argTypeNames.push_back(llvm::MDString::get(Context, typeName)); + + // Get argument type qualifiers: + if (ty.isRestrictQualified()) + typeQuals = "restrict"; + if (pointeeTy.isConstQualified() || + (pointeeTy.getAddressSpace() == LangAS::opencl_constant)) + typeQuals += typeQuals.empty() ? "const" : " const"; + if (pointeeTy.isVolatileQualified()) + typeQuals += typeQuals.empty() ? "volatile" : " volatile"; + } else { + addressQuals.push_back(Builder.getInt32(0)); + + // Get argument type name. + std::string typeName = ty.getUnqualifiedType().getAsString(); + + // Turn "unsigned type" to "utype" + std::string::size_type pos = typeName.find("unsigned"); + if (pos != std::string::npos) + typeName.erase(pos+1, 8); + + argTypeNames.push_back(llvm::MDString::get(Context, typeName)); + + // Get argument type qualifiers: + if (ty.isConstQualified()) + typeQuals = "const"; + if (ty.isVolatileQualified()) + typeQuals += typeQuals.empty() ? "volatile" : " volatile"; + } + + argTypeQuals.push_back(llvm::MDString::get(Context, typeQuals)); + + // Get image access qualifier: + if (ty->isImageType()) { + if (parm->hasAttr<OpenCLImageAccessAttr>() && + parm->getAttr<OpenCLImageAccessAttr>()->getAccess() == CLIA_write_only) + accessQuals.push_back(llvm::MDString::get(Context, "write_only")); + else + accessQuals.push_back(llvm::MDString::get(Context, "read_only")); + } else + accessQuals.push_back(llvm::MDString::get(Context, "none")); // Get argument name. argNames.push_back(llvm::MDString::get(Context, parm->getName())); - } - // Add MDNode to the list of all metadata. + + kernelMDArgs.push_back(llvm::MDNode::get(Context, addressQuals)); + kernelMDArgs.push_back(llvm::MDNode::get(Context, accessQuals)); + kernelMDArgs.push_back(llvm::MDNode::get(Context, argTypeNames)); + kernelMDArgs.push_back(llvm::MDNode::get(Context, argTypeQuals)); kernelMDArgs.push_back(llvm::MDNode::get(Context, argNames)); } @@ -321,7 +425,8 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD, kernelMDArgs.push_back(Fn); if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata) - GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs); + GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs, + Builder, getContext()); if (FD->hasAttr<VecTypeHintAttr>()) { VecTypeHintAttr *attr = FD->getAttr<VecTypeHintAttr>(); @@ -368,7 +473,8 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD, OpenCLKernelMetadata->addOperand(kernelMDNode); } -void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, +void CodeGenFunction::StartFunction(GlobalDecl GD, + QualType RetTy, llvm::Function *Fn, const CGFunctionInfo &FnInfo, const FunctionArgList &Args, @@ -376,7 +482,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, const Decl *D = GD.getDecl(); DidCallStackSave = false; - CurCodeDecl = CurFuncDecl = D; + CurCodeDecl = D; + CurFuncDecl = (D ? D->getNonClosureContext() : 0); FnRetTy = RetTy; CurFn = Fn; CurFnInfo = &FnInfo; @@ -475,12 +582,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, LambdaThisCaptureField); if (LambdaThisCaptureField) { // If this lambda captures this, load it. - QualType LambdaTagType = - getContext().getTagDeclType(LambdaThisCaptureField->getParent()); - LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue, - LambdaTagType); - LValue ThisLValue = EmitLValueForField(LambdaLV, - LambdaThisCaptureField); + LValue ThisLValue = EmitLValueForLambdaField(LambdaThisCaptureField); CXXThisValue = EmitLoadOfLValue(ThisLValue).getScalarVal(); } } else { @@ -564,6 +666,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, SourceRange BodyRange; if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange(); + // CalleeWithThisReturn keeps track of the last callee inside this function + // that returns 'this'. Before starting the function, we set it to null. + CalleeWithThisReturn = 0; + // Emit the standard function prologue. StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin()); @@ -615,6 +721,9 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, // Emit the standard function epilogue. FinishFunction(BodyRange.getEnd()); + // CalleeWithThisReturn keeps track of the last callee inside this function + // that returns 'this'. After finishing the function, we set it to null. + CalleeWithThisReturn = 0; // If we haven't marked the function nothrow through other means, do // a quick pass now to see if we can. @@ -819,6 +928,16 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, return; } + if (const CXXThrowExpr *Throw = dyn_cast<CXXThrowExpr>(Cond)) { + // Conditional operator handling can give us a throw expression as a + // condition for a case like: + // br(c ? throw x : y, t, f) -> br(c, br(throw x, t, f), br(y, t, f) + // Fold this to: + // br(c, throw x, br(y, t, f)) + EmitCXXThrowExpr(Throw, /*KeepInsertionPoint*/false); + return; + } + // Emit the code with the fully general case. llvm::Value *CondV = EvaluateExprAsBool(Cond); Builder.CreateCondBr(CondV, TrueBlock, FalseBlock); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 0155f033e6..ff74c15c38 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -562,6 +562,11 @@ public: EHScopeStack::stable_iterator getScopeDepth() const { return ScopeDepth; } unsigned getDestIndex() const { return Index; } + // This should be used cautiously. + void setScopeDepth(EHScopeStack::stable_iterator depth) { + ScopeDepth = depth; + } + private: llvm::BasicBlock *Block; EHScopeStack::stable_iterator ScopeDepth; @@ -574,8 +579,8 @@ public: typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy; CGBuilderTy Builder; - /// CurFuncDecl - Holds the Decl for the current function or ObjC method. - /// This excludes BlockDecls. + /// CurFuncDecl - Holds the Decl for the current outermost + /// non-closure context. const Decl *CurFuncDecl; /// CurCodeDecl - This is the inner-most code context, which includes blocks. const Decl *CurCodeDecl; @@ -779,7 +784,9 @@ public: /// PopCleanupBlock - Will pop the cleanup entry on the stack and /// process all branch fixups. - void PopCleanupBlock(bool FallThroughIsBranchThrough = false); + /// \param EHLoc - Optional debug location for EH code. + void PopCleanupBlock(bool FallThroughIsBranchThrough = false, + SourceLocation EHLoc=SourceLocation()); /// DeactivateCleanupBlock - Deactivates the given cleanup block. /// The block cannot be reactivated. Pops it if it's the top of the @@ -853,6 +860,8 @@ public: class LexicalScope: protected RunCleanupsScope { SourceRange Range; + SmallVector<const LabelDecl*, 4> Labels; + LexicalScope *ParentScope; LexicalScope(const LexicalScope &) LLVM_DELETED_FUNCTION; void operator=(const LexicalScope &) LLVM_DELETED_FUNCTION; @@ -860,35 +869,47 @@ public: public: /// \brief Enter a new cleanup scope. explicit LexicalScope(CodeGenFunction &CGF, SourceRange Range) - : RunCleanupsScope(CGF), Range(Range) { + : RunCleanupsScope(CGF), Range(Range), ParentScope(CGF.CurLexicalScope) { + CGF.CurLexicalScope = this; if (CGDebugInfo *DI = CGF.getDebugInfo()) DI->EmitLexicalBlockStart(CGF.Builder, Range.getBegin()); } + void addLabel(const LabelDecl *label) { + assert(PerformCleanup && "adding label to dead scope?"); + Labels.push_back(label); + } + /// \brief Exit this cleanup scope, emitting any accumulated /// cleanups. ~LexicalScope() { - if (PerformCleanup) endLexicalScope(); + if (CGDebugInfo *DI = CGF.getDebugInfo()) + DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd()); + + // If we should perform a cleanup, force them now. Note that + // this ends the cleanup scope before rescoping any labels. + if (PerformCleanup) ForceCleanup(); } /// \brief Force the emission of cleanups now, instead of waiting /// until this object is destroyed. void ForceCleanup() { + CGF.CurLexicalScope = ParentScope; RunCleanupsScope::ForceCleanup(); - endLexicalScope(); - } - private: - void endLexicalScope() { - if (CGDebugInfo *DI = CGF.getDebugInfo()) - DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd()); + if (!Labels.empty()) + rescopeLabels(); } + + void rescopeLabels(); }; /// PopCleanupBlocks - Takes the old cleanup stack size and emits /// the cleanup blocks that have been added. - void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize); + /// \param EHLoc - Optional debug location for EH code. + void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize, + SourceLocation EHLoc=SourceLocation()); void ResolveBranchFixups(llvm::BasicBlock *Target); @@ -1131,6 +1152,10 @@ private: CGDebugInfo *DebugInfo; bool DisableDebugInfo; + /// If the current function returns 'this', use the field to keep track of + /// the callee that returns 'this'. + llvm::Value *CalleeWithThisReturn; + /// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid /// calling llvm.stacksave for multiple VLAs in the same scope. bool DidCallStackSave; @@ -1185,12 +1210,62 @@ private: /// lazily by getUnreachableBlock(). llvm::BasicBlock *UnreachableBlock; + /// Counts of the number return expressions in the function. + unsigned NumReturnExprs; + + /// Count the number of simple (constant) return expressions in the function. + unsigned NumSimpleReturnExprs; + + /// The last regular (non-return) debug location (breakpoint) in the function. + SourceLocation LastStopPoint; + +public: + /// A scope within which we are constructing the fields of an object which + /// might use a CXXDefaultInitExpr. This stashes away a 'this' value to use + /// if we need to evaluate a CXXDefaultInitExpr within the evaluation. + class FieldConstructionScope { + public: + FieldConstructionScope(CodeGenFunction &CGF, llvm::Value *This) + : CGF(CGF), OldCXXDefaultInitExprThis(CGF.CXXDefaultInitExprThis) { + CGF.CXXDefaultInitExprThis = This; + } + ~FieldConstructionScope() { + CGF.CXXDefaultInitExprThis = OldCXXDefaultInitExprThis; + } + + private: + CodeGenFunction &CGF; + llvm::Value *OldCXXDefaultInitExprThis; + }; + + /// The scope of a CXXDefaultInitExpr. Within this scope, the value of 'this' + /// is overridden to be the object under construction. + class CXXDefaultInitExprScope { + public: + CXXDefaultInitExprScope(CodeGenFunction &CGF) + : CGF(CGF), OldCXXThisValue(CGF.CXXThisValue) { + CGF.CXXThisValue = CGF.CXXDefaultInitExprThis; + } + ~CXXDefaultInitExprScope() { + CGF.CXXThisValue = OldCXXThisValue; + } + + public: + CodeGenFunction &CGF; + llvm::Value *OldCXXThisValue; + }; + +private: /// CXXThisDecl - When generating code for a C++ member function, /// this will hold the implicit 'this' declaration. ImplicitParamDecl *CXXABIThisDecl; llvm::Value *CXXABIThisValue; llvm::Value *CXXThisValue; + /// The value of 'this' to use when evaluating CXXDefaultInitExprs within + /// this expression. + llvm::Value *CXXDefaultInitExprThis; + /// CXXStructorImplicitParamDecl - When generating code for a constructor or /// destructor, this will hold the implicit argument (e.g. VTT). ImplicitParamDecl *CXXStructorImplicitParamDecl; @@ -1201,6 +1276,8 @@ private: /// temporary should be destroyed conditionally. ConditionalEvaluation *OutermostConditional; + /// The current lexical scope. + LexicalScope *CurLexicalScope; /// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM /// type as well as the field number that contains the actual data. @@ -1277,6 +1354,7 @@ public: return getInvokeDestImpl(); } + const TargetInfo &getTarget() const { return Target; } llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); } //===--------------------------------------------------------------------===// @@ -1377,7 +1455,6 @@ public: llvm::Function *GenerateBlockFunction(GlobalDecl GD, const CGBlockInfo &Info, - const Decl *OuterFuncDecl, const DeclMapTy &ldm, bool IsLambdaConversionToBlock); @@ -1408,7 +1485,8 @@ public: void GenerateCode(GlobalDecl GD, llvm::Function *Fn, const CGFunctionInfo &FnInfo); - void StartFunction(GlobalDecl GD, QualType RetTy, + void StartFunction(GlobalDecl GD, + QualType RetTy, llvm::Function *Fn, const CGFunctionInfo &FnInfo, const FunctionArgList &Args, @@ -1498,7 +1576,7 @@ public: /// EmitFunctionEpilog - Emit the target specific LLVM code to return the /// given temporary. - void EmitFunctionEpilog(const CGFunctionInfo &FI); + void EmitFunctionEpilog(const CGFunctionInfo &FI, bool EmitRetDbgLoc); /// EmitStartEHSpec - Emit the start of the exception spec. void EmitStartEHSpec(const Decl *D); @@ -1997,18 +2075,34 @@ public: /// initializer. bool IsConstantAggregate; + /// Non-null if we should use lifetime annotations. + llvm::Value *SizeForLifetimeMarkers; + struct Invalid {}; AutoVarEmission(Invalid) : Variable(0) {} AutoVarEmission(const VarDecl &variable) : Variable(&variable), Address(0), NRVOFlag(0), - IsByRef(false), IsConstantAggregate(false) {} + IsByRef(false), IsConstantAggregate(false), + SizeForLifetimeMarkers(0) {} bool wasEmittedAsGlobal() const { return Address == 0; } public: static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); } + bool useLifetimeMarkers() const { return SizeForLifetimeMarkers != 0; } + llvm::Value *getSizeForLifetimeMarkers() const { + assert(useLifetimeMarkers()); + return SizeForLifetimeMarkers; + } + + /// Returns the raw, allocated address, which is not necessarily + /// the address of the object itself. + llvm::Value *getAllocatedAddress() const { + return Address; + } + /// Returns the address of the object within this declaration. /// Note that this does not chase the forwarding pointer for /// __block decls. @@ -2094,6 +2188,7 @@ public: void EmitCaseStmt(const CaseStmt &S); void EmitCaseStmtRange(const CaseStmt &S); void EmitAsmStmt(const AsmStmt &S); + void EmitCapturedStmt(const CapturedStmt &S); void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S); void EmitObjCAtTryStmt(const ObjCAtTryStmt &S); @@ -2172,7 +2267,9 @@ public: /// the LLVM value representation. llvm::Value *EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, unsigned Alignment, QualType Ty, - llvm::MDNode *TBAAInfo = 0); + llvm::MDNode *TBAAInfo = 0, + QualType TBAABaseTy = QualType(), + uint64_t TBAAOffset = 0); /// EmitLoadOfScalar - Load a scalar value from an address, taking /// care to appropriately convert from the memory representation to @@ -2185,7 +2282,9 @@ public: /// the LLVM value representation. void EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr, bool Volatile, unsigned Alignment, QualType Ty, - llvm::MDNode *TBAAInfo = 0, bool isInit=false); + llvm::MDNode *TBAAInfo = 0, bool isInit = false, + QualType TBAABaseTy = QualType(), + uint64_t TBAAOffset = 0); /// EmitStoreOfScalar - Store a scalar value to an address, taking /// care to appropriately convert from the memory representation to @@ -2284,6 +2383,7 @@ public: llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); LValue EmitLValueForField(LValue Base, const FieldDecl* Field); + LValue EmitLValueForLambdaField(const FieldDecl *Field); /// EmitLValueForFieldInitialization - Like EmitLValueForField, except that /// if the Field is a reference, this will return the address of the reference @@ -2403,6 +2503,7 @@ public: /// is unhandled by the current target. llvm::Value *EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E); + llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitNeonCall(llvm::Function *F, SmallVectorImpl<llvm::Value*> &O, @@ -2446,14 +2547,14 @@ public: llvm::Value *EmitARCRetainAutorelease(QualType type, llvm::Value *value); llvm::Value *EmitARCRetainAutoreleaseNonBlock(llvm::Value *value); llvm::Value *EmitARCStoreStrong(LValue lvalue, llvm::Value *value, - bool ignored); + bool resultIgnored); llvm::Value *EmitARCStoreStrongCall(llvm::Value *addr, llvm::Value *value, - bool ignored); + bool resultIgnored); llvm::Value *EmitARCRetain(QualType type, llvm::Value *value); llvm::Value *EmitARCRetainNonBlock(llvm::Value *value); llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory); - void EmitARCDestroyStrong(llvm::Value *addr, bool precise); - void EmitARCRelease(llvm::Value *value, bool precise); + void EmitARCDestroyStrong(llvm::Value *addr, ARCPreciseLifetime_t precise); + void EmitARCRelease(llvm::Value *value, ARCPreciseLifetime_t precise); llvm::Value *EmitARCAutorelease(llvm::Value *value); llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value); llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value); @@ -2474,6 +2575,8 @@ public: llvm::Value *EmitARCRetainScalarExpr(const Expr *expr); llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr); + void EmitARCIntrinsicUse(llvm::ArrayRef<llvm::Value*> values); + static Destroyer destroyARCStrongImprecise; static Destroyer destroyARCStrongPrecise; static Destroyer destroyARCWeak; @@ -2580,8 +2683,8 @@ public: /// GenerateCXXGlobalInitFunc - Generates code for initializing global /// variables. void GenerateCXXGlobalInitFunc(llvm::Function *Fn, - llvm::Constant **Decls, - unsigned NumDecls); + ArrayRef<llvm::Constant *> Decls, + llvm::GlobalVariable *Guard = 0); /// GenerateCXXGlobalDtorsFunc - Generates code for destroying global /// variables. @@ -2605,7 +2708,7 @@ public: } void enterNonTrivialFullExpression(const ExprWithCleanups *E); - void EmitCXXThrowExpr(const CXXThrowExpr *E); + void EmitCXXThrowExpr(const CXXThrowExpr *E, bool KeepInsertionPoint = true); void EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Dest); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 402b309f8e..0b03a3c4b6 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -35,7 +35,6 @@ #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Basic/TargetOptions.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/Triple.h" @@ -55,7 +54,7 @@ using namespace CodeGen; static const char AnnotationSection[] = "llvm.metadata"; static CGCXXABI &createCXXABI(CodeGenModule &CGM) { - switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) { + switch (CGM.getTarget().getCXXABI().getKind()) { case TargetCXXABI::GenericAArch64: case TargetCXXABI::GenericARM: case TargetCXXABI::iOS: @@ -70,22 +69,20 @@ static CGCXXABI &createCXXABI(CodeGenModule &CGM) { CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, - const TargetOptions &TO, llvm::Module &M, - const llvm::DataLayout &TD, + llvm::Module &M, const llvm::DataLayout &TD, DiagnosticsEngine &diags) - : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TargetOpts(TO), - TheModule(M), TheDataLayout(TD), TheTargetCodeGenInfo(0), Diags(diags), - ABI(createCXXABI(*this)), - Types(*this), - TBAA(0), - VTables(*this), ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0), + : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M), + Diags(diags), TheDataLayout(TD), Target(C.getTargetInfo()), + ABI(createCXXABI(*this)), VMContext(M.getContext()), TBAA(0), + TheTargetCodeGenInfo(0), Types(*this), VTables(*this), + ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0), DebugInfo(0), ARCData(0), NoObjCARCExceptionsMetadata(0), RRData(0), CFConstantStringClassRef(0), ConstantStringClassRef(0), NSConstantStringType(0), - VMContext(M.getContext()), NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockObjectAssign(0), BlockObjectDispose(0), BlockDescriptorType(0), GenericBlockLiteralType(0), + LifetimeStartFn(0), LifetimeEndFn(0), SanitizerBlacklist(CGO.SanitizerBlacklistFile), SanOpts(SanitizerBlacklist.isIn(M) ? SanitizerOptions::Disabled : LangOpts.Sanitize) { @@ -179,15 +176,17 @@ void CodeGenModule::Release() { EmitDeferred(); EmitCXXGlobalInitFunc(); EmitCXXGlobalDtorFunc(); + EmitCXXThreadLocalInitFunc(); if (ObjCRuntime) if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction()) AddGlobalCtor(ObjCInitFunction); EmitCtorList(GlobalCtors, "llvm.global_ctors"); EmitCtorList(GlobalDtors, "llvm.global_dtors"); EmitGlobalAnnotations(); + EmitStaticExternCAliases(); EmitLLVMUsed(); - if (CodeGenOpts.ModulesAutolink) { + if (CodeGenOpts.Autolink && Context.getLangOpts().Modules) { EmitModuleLinkOptions(); } @@ -226,13 +225,32 @@ llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) { return TBAA->getTBAAStructInfo(QTy); } -void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst, - llvm::MDNode *TBAAInfo) { - Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo); +llvm::MDNode *CodeGenModule::getTBAAStructTypeInfo(QualType QTy) { + if (!TBAA) + return 0; + return TBAA->getTBAAStructTypeInfo(QTy); } -bool CodeGenModule::isTargetDarwin() const { - return getContext().getTargetInfo().getTriple().isOSDarwin(); +llvm::MDNode *CodeGenModule::getTBAAStructTagInfo(QualType BaseTy, + llvm::MDNode *AccessN, + uint64_t O) { + if (!TBAA) + return 0; + return TBAA->getTBAAStructTagInfo(BaseTy, AccessN, O); +} + +/// Decorate the instruction with a TBAA tag. For scalar TBAA, the tag +/// is the same as the type. For struct-path aware TBAA, the tag +/// is different from the type: base type, access type and offset. +/// When ConvertTypeToTag is true, we create a tag based on the scalar type. +void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst, + llvm::MDNode *TBAAInfo, + bool ConvertTypeToTag) { + if (ConvertTypeToTag && TBAA && CodeGenOpts.StructPathTBAA) + Inst->setMetadata(llvm::LLVMContext::MD_tbaa, + TBAA->getTBAAScalarTagInfo(TBAAInfo)); + else + Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo); } void CodeGenModule::Error(SourceLocation loc, StringRef error) { @@ -308,7 +326,7 @@ static llvm::GlobalVariable::ThreadLocalMode GetLLVMTLSModel( void CodeGenModule::setTLSMode(llvm::GlobalVariable *GV, const VarDecl &D) const { - assert(D.isThreadSpecified() && "setting TLS mode on non-TLS var!"); + assert(D.getTLSKind() && "setting TLS mode on non-TLS var!"); llvm::GlobalVariable::ThreadLocalMode TLM; TLM = GetLLVMTLSModel(CodeGenOpts.getDefaultTLSModel()); @@ -656,7 +674,9 @@ void CodeGenModule::SetCommonAttributes(const Decl *D, if (const SectionAttr *SA = D->getAttr<SectionAttr>()) GV->setSection(SA->getName()); - getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this); + // Alias cannot have attributes. Filter them here. + if (!isa<llvm::GlobalAlias>(GV)) + getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this); } void CodeGenModule::SetInternalFunctionAttributes(const Decl *D, @@ -1458,8 +1478,11 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, GV->setVisibility(GetLLVMVisibility(LV.getVisibility())); } - if (D->isThreadSpecified()) + if (D->getTLSKind()) { + if (D->getTLSKind() == VarDecl::TLS_Dynamic) + CXXThreadLocals.push_back(std::make_pair(D, GV)); setTLSMode(GV, *D); + } } if (AddrSpace != Ty->getAddressSpace()) @@ -1599,7 +1622,8 @@ CodeGenModule::MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D, D->getDeclContext()), D->getLocStart(), D->getLocation(), name, arrayType, sourceInfo, - SC_Static, SC_Static); + SC_Static); + backingArray->setTSCSpec(D->getTSCSpec()); // Now clone the InitListExpr to initialize the array instead. // Incredible hack: we want to use the existing InitListExpr here, so we need @@ -1690,6 +1714,39 @@ unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D, return AddrSpace; } +template<typename SomeDecl> +void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D, + llvm::GlobalValue *GV) { + if (!getLangOpts().CPlusPlus) + return; + + // Must have 'used' attribute, or else inline assembly can't rely on + // the name existing. + if (!D->template hasAttr<UsedAttr>()) + return; + + // Must have internal linkage and an ordinary name. + if (!D->getIdentifier() || D->getLinkage() != InternalLinkage) + return; + + // Must be in an extern "C" context. Entities declared directly within + // a record are not extern "C" even if the record is in such a context. + const SomeDecl *First = D->getFirstDeclaration(); + if (First->getDeclContext()->isRecord() || !First->isInExternCContext()) + return; + + // OK, this is an internal linkage entity inside an extern "C" linkage + // specification. Make a note of that so we can give it the "expected" + // mangled name if nothing else is using that name. + std::pair<StaticExternCMap::iterator, bool> R = + StaticExternCValues.insert(std::make_pair(D->getIdentifier(), GV)); + + // If we have multiple internal linkage entities with the same name + // in extern "C" regions, none of them gets that name. + if (!R.second) + R.first->second = 0; +} + void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { llvm::Constant *Init = 0; QualType ASTTy = D->getType(); @@ -1788,6 +1845,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { cast<llvm::GlobalValue>(Entry)->eraseFromParent(); } + MaybeHandleStaticInExternC(D, GV); + if (D->hasAttr<AnnotateAttr>()) AddGlobalAnnotations(D, GV); @@ -1853,11 +1912,17 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, ((!CodeGenOpts.NoCommon && !D->getAttr<NoCommonAttr>()) || D->getAttr<CommonAttr>()) && !D->hasExternalStorage() && !D->getInit() && - !D->getAttr<SectionAttr>() && !D->isThreadSpecified() && + !D->getAttr<SectionAttr>() && !D->getTLSKind() && !D->getAttr<WeakImportAttr>()) { // Thread local vars aren't considered common linkage. return llvm::GlobalVariable::CommonLinkage; - } + } else if (D->getTLSKind() == VarDecl::TLS_Dynamic && + getTarget().getTriple().isMacOSX()) + // On Darwin, the backing variable for a C++11 thread_local variable always + // has internal linkage; all accesses should just be calls to the + // Itanium-specified entry point, which has the normal linkage of the + // variable. + return llvm::GlobalValue::InternalLinkage; return llvm::GlobalVariable::ExternalLinkage; } @@ -2066,6 +2131,8 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { // FIXME: this is redundant with part of SetFunctionDefinitionAttributes setGlobalVisibility(Fn, D); + MaybeHandleStaticInExternC(D, Fn); + CodeGenFunction(*this).GenerateCode(D, Fn, FI); SetFunctionDefinitionAttributes(D, Fn); @@ -2214,7 +2281,8 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty); llvm::Constant *Zeros[] = { Zero, Zero }; - + llvm::Value *V; + // If we don't already have it, get __CFConstantStringClassReference. if (!CFConstantStringClassRef) { llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); @@ -2222,9 +2290,11 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { llvm::Constant *GV = CreateRuntimeVariable(Ty, "__CFConstantStringClassReference"); // Decay array -> ptr - CFConstantStringClassRef = - llvm::ConstantExpr::getGetElementPtr(GV, Zeros); + V = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); + CFConstantStringClassRef = V; } + else + V = CFConstantStringClassRef; QualType CFTy = getContext().getCFConstantStringType(); @@ -2234,7 +2304,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { llvm::Constant *Fields[4]; // Class pointer. - Fields[0] = CFConstantStringClassRef; + Fields[0] = cast<llvm::ConstantExpr>(V); // Flags. llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); @@ -2269,6 +2339,8 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { new llvm::GlobalVariable(getModule(), C->getType(), /*isConstant=*/true, Linkage, C, ".str"); GV->setUnnamedAddr(true); + // Don't enforce the target's minimum global alignment, since the only use + // of the string is via this class initializer. if (isUTF16) { CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy); GV->setAlignment(Align.getQuantity()); @@ -2293,7 +2365,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { GV = new llvm::GlobalVariable(getModule(), C->getType(), true, llvm::GlobalVariable::PrivateLinkage, C, "_unnamed_cfstring_"); - if (const char *Sect = getContext().getTargetInfo().getCFStringSection()) + if (const char *Sect = getTarget().getCFStringSection()) GV->setSection(Sect); Entry.setValue(GV); @@ -2321,7 +2393,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty); llvm::Constant *Zeros[] = { Zero, Zero }; - + llvm::Value *V; // If we don't already have it, get _NSConstantStringClassReference. if (!ConstantStringClassRef) { std::string StringClass(getLangOpts().ObjCConstantStringClass); @@ -2334,8 +2406,8 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { GV = getObjCRuntime().GetClassGlobal(str); // Make sure the result is of the correct type. llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); - ConstantStringClassRef = - llvm::ConstantExpr::getBitCast(GV, PTy); + V = llvm::ConstantExpr::getBitCast(GV, PTy); + ConstantStringClassRef = V; } else { std::string str = StringClass.empty() ? "_NSConstantStringClassReference" @@ -2343,10 +2415,12 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { llvm::Type *PTy = llvm::ArrayType::get(Ty, 0); GV = CreateRuntimeVariable(PTy, str); // Decay array -> ptr - ConstantStringClassRef = - llvm::ConstantExpr::getGetElementPtr(GV, Zeros); + V = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); + ConstantStringClassRef = V; } } + else + V = ConstantStringClassRef; if (!NSConstantStringType) { // Construct the type for a constant NSString. @@ -2385,7 +2459,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { llvm::Constant *Fields[3]; // Class pointer. - Fields[0] = ConstantStringClassRef; + Fields[0] = cast<llvm::ConstantExpr>(V); // String pointer. llvm::Constant *C = @@ -2400,6 +2474,8 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C, ".str"); GV->setUnnamedAddr(true); + // Don't enforce the target's minimum global alignment, since the only use + // of the string is via this class initializer. CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); GV->setAlignment(Align.getQuantity()); Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); @@ -2416,8 +2492,8 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { // FIXME. Fix section. if (const char *Sect = LangOpts.ObjCRuntime.isNonFragile() - ? getContext().getTargetInfo().getNSStringNonFragileABISection() - : getContext().getTargetInfo().getNSStringSection()) + ? getTarget().getNSStringNonFragileABISection() + : getTarget().getNSStringSection()) GV->setSection(Sect); Entry.setValue(GV); @@ -2504,7 +2580,7 @@ CodeGenModule::GetConstantArrayFromStringLiteral(const StringLiteral *E) { /// constant array for the given string literal. llvm::Constant * CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) { - CharUnits Align = getContext().getTypeAlignInChars(S->getType()); + CharUnits Align = getContext().getAlignOfGlobalVarInChars(S->getType()); if (S->isAscii() || S->isUTF8()) { SmallString<64> Str(S->getString()); @@ -2573,6 +2649,10 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantString(StringRef Str, if (!GlobalName) GlobalName = ".str"; + if (Alignment == 0) + Alignment = getContext().getAlignOfGlobalVarInChars(getContext().CharTy) + .getQuantity(); + // Don't share any string literals if strings aren't constant. if (LangOpts.WritableStrings) return GenerateStringLiteral(Str, false, *this, GlobalName, Alignment); @@ -2753,7 +2833,6 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { // No code generation needed. case Decl::UsingShadow: case Decl::Using: - case Decl::UsingDirective: case Decl::ClassTemplate: case Decl::FunctionTemplate: case Decl::TypeAliasTemplate: @@ -2761,6 +2840,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::Block: case Decl::Empty: break; + case Decl::UsingDirective: // using namespace X; [C++] + if (CGDebugInfo *DI = getModuleDebugInfo()) + DI->EmitUsingDirective(cast<UsingDirectiveDecl>(*D)); + return; case Decl::CXXConstructor: // Skip function templates if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() || @@ -2886,6 +2969,23 @@ static void EmitGlobalDeclMetadata(CodeGenModule &CGM, GlobalMetadata->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops)); } +/// For each function which is declared within an extern "C" region and marked +/// as 'used', but has internal linkage, create an alias from the unmangled +/// name to the mangled name if possible. People expect to be able to refer +/// to such functions with an unmangled name from inline assembly within the +/// same translation unit. +void CodeGenModule::EmitStaticExternCAliases() { + for (StaticExternCMap::iterator I = StaticExternCValues.begin(), + E = StaticExternCValues.end(); + I != E; ++I) { + IdentifierInfo *Name = I->first; + llvm::GlobalValue *Val = I->second; + if (Val && !getModule().getNamedValue(Name->getName())) + AddUsedGlobal(new llvm::GlobalAlias(Val->getType(), Val->getLinkage(), + Name->getName(), Val, &getModule())); + } +} + /// Emits metadata nodes associating all the global values in the /// current module with the Decls they came from. This is useful for /// projects using IR gen as a subroutine. diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 2bddb6f79f..91138c607c 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -67,7 +67,6 @@ namespace clang { class VarDecl; class LangOptions; class CodeGenOptions; - class TargetOptions; class DiagnosticsEngine; class AnnotateAttr; class CXXDestructorDecl; @@ -217,6 +216,9 @@ struct ARCEntrypoints { /// A void(void) inline asm to use to mark that the return value of /// a call will be immediately retain. llvm::InlineAsm *retainAutoreleasedReturnValueMarker; + + /// void clang.arc.use(...); + llvm::Constant *clang_arc_use; }; /// CodeGenModule - This class organizes the cross-function state that is used @@ -230,15 +232,22 @@ class CodeGenModule : public CodeGenTypeCache { ASTContext &Context; const LangOptions &LangOpts; const CodeGenOptions &CodeGenOpts; - const TargetOptions &TargetOpts; llvm::Module &TheModule; - const llvm::DataLayout &TheDataLayout; - mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; DiagnosticsEngine &Diags; + const llvm::DataLayout &TheDataLayout; + const TargetInfo &Target; CGCXXABI &ABI; - CodeGenTypes Types; - CodeGenTBAA *TBAA; + llvm::LLVMContext &VMContext; + CodeGenTBAA *TBAA; + + mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; + + // This should not be moved earlier, since its initialization depends on some + // of the previous reference members being already initialized and also checks + // if TheTargetCodeGenInfo is NULL + CodeGenTypes Types; + /// VTables - Holds information about C++ vtables. CodeGenVTables VTables; friend class CodeGenVTables; @@ -252,8 +261,8 @@ class CodeGenModule : public CodeGenTypeCache { RREntrypoints *RRData; // WeakRefReferences - A set of references that have only been seen via - // a weakref so far. This is used to remove the weak of the reference if we ever - // see a direct reference or a definition. + // a weakref so far. This is used to remove the weak of the reference if we + // ever see a direct reference or a definition. llvm::SmallPtrSet<llvm::GlobalValue*, 10> WeakRefReferences; /// DeferredDecls - This contains all the decls which have definitions but @@ -302,6 +311,20 @@ class CodeGenModule : public CodeGenTypeCache { llvm::DenseMap<QualType, llvm::Constant *> AtomicSetterHelperFnMap; llvm::DenseMap<QualType, llvm::Constant *> AtomicGetterHelperFnMap; + /// Map used to track internal linkage functions declared within + /// extern "C" regions. + typedef llvm::MapVector<IdentifierInfo *, + llvm::GlobalValue *> StaticExternCMap; + StaticExternCMap StaticExternCValues; + + /// \brief thread_local variables defined or used in this TU. + std::vector<std::pair<const VarDecl *, llvm::GlobalVariable *> > + CXXThreadLocals; + + /// \brief thread_local variables with initializers that need to run + /// before any thread_local variable in this TU is odr-used. + std::vector<llvm::Constant*> CXXThreadLocalInits; + /// CXXGlobalInits - Global variables with initializers that need to run /// before main. std::vector<llvm::Constant*> CXXGlobalInits; @@ -337,11 +360,11 @@ class CodeGenModule : public CodeGenTypeCache { /// CFConstantStringClassRef - Cached reference to the class for constant /// strings. This value has type int * but is actually an Obj-C class pointer. - llvm::Constant *CFConstantStringClassRef; + llvm::WeakVH CFConstantStringClassRef; /// ConstantStringClassRef - Cached reference to the class for constant /// strings. This value has type int * but is actually an Obj-C class pointer. - llvm::Constant *ConstantStringClassRef; + llvm::WeakVH ConstantStringClassRef; /// \brief The LLVM type corresponding to NSConstantString. llvm::StructType *NSConstantStringType; @@ -360,7 +383,6 @@ class CodeGenModule : public CodeGenTypeCache { bool isTriviallyRecursive(const FunctionDecl *F); bool shouldEmitFunction(const FunctionDecl *F); - llvm::LLVMContext &VMContext; /// @name Cache for Blocks Runtime Globals /// @{ @@ -378,6 +400,12 @@ class CodeGenModule : public CodeGenTypeCache { int GlobalUniqueCount; } Block; + /// void @llvm.lifetime.start(i64 %size, i8* nocapture <ptr>) + llvm::Constant *LifetimeStartFn; + + /// void @llvm.lifetime.end(i64 %size, i8* nocapture <ptr>) + llvm::Constant *LifetimeEndFn; + GlobalDecl initializedGlobalDecl; llvm::BlackList SanitizerBlacklist; @@ -387,8 +415,8 @@ class CodeGenModule : public CodeGenTypeCache { /// @} public: CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, llvm::Module &M, - const llvm::DataLayout &TD, DiagnosticsEngine &Diags); + llvm::Module &M, const llvm::DataLayout &TD, + DiagnosticsEngine &Diags); ~CodeGenModule(); @@ -418,9 +446,6 @@ public: return *CUDARuntime; } - /// getCXXABI() - Return a reference to the configured C++ ABI. - CGCXXABI &getCXXABI() { return ABI; } - ARCEntrypoints &getARCEntrypoints() const { assert(getLangOpts().ObjCAutoRefCount && ARCData != 0); return *ARCData; @@ -474,32 +499,45 @@ public: } ASTContext &getContext() const { return Context; } - const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } const LangOptions &getLangOpts() const { return LangOpts; } + const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } llvm::Module &getModule() const { return TheModule; } - CodeGenTypes &getTypes() { return Types; } - CodeGenVTables &getVTables() { return VTables; } - VTableContext &getVTableContext() { return VTables.getVTableContext(); } DiagnosticsEngine &getDiags() const { return Diags; } const llvm::DataLayout &getDataLayout() const { return TheDataLayout; } - const TargetInfo &getTarget() const { return Context.getTargetInfo(); } + const TargetInfo &getTarget() const { return Target; } + CGCXXABI &getCXXABI() { return ABI; } llvm::LLVMContext &getLLVMContext() { return VMContext; } - const TargetCodeGenInfo &getTargetCodeGenInfo(); - bool isTargetDarwin() const; - + bool shouldUseTBAA() const { return TBAA != 0; } + const TargetCodeGenInfo &getTargetCodeGenInfo(); + + CodeGenTypes &getTypes() { return Types; } + + CodeGenVTables &getVTables() { return VTables; } + VTableContext &getVTableContext() { return VTables.getVTableContext(); } + llvm::MDNode *getTBAAInfo(QualType QTy); llvm::MDNode *getTBAAInfoForVTablePtr(); llvm::MDNode *getTBAAStructInfo(QualType QTy); + /// Return the MDNode in the type DAG for the given struct type. + llvm::MDNode *getTBAAStructTypeInfo(QualType QTy); + /// Return the path-aware tag for given base type, access node and offset. + llvm::MDNode *getTBAAStructTagInfo(QualType BaseTy, llvm::MDNode *AccessN, + uint64_t O); bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor); bool isPaddedAtomicType(QualType type); bool isPaddedAtomicType(const AtomicType *type); - static void DecorateInstruction(llvm::Instruction *Inst, - llvm::MDNode *TBAAInfo); + /// Decorate the instruction with a TBAA tag. For scalar TBAA, the tag + /// is the same as the type. For struct-path aware TBAA, the tag + /// is different from the type: base type, access type and offset. + /// When ConvertTypeToTag is true, we create a tag based on the scalar type. + void DecorateInstruction(llvm::Instruction *Inst, + llvm::MDNode *TBAAInfo, + bool ConvertTypeToTag = true); /// getSize - Emit the given number of characters as a value of type size_t. llvm::ConstantInt *getSize(CharUnits numChars); @@ -549,8 +587,8 @@ public: return GetAddrOfGlobalVar(cast<VarDecl>(GD.getDecl())); } - /// CreateOrReplaceCXXRuntimeVariable - Will return a global variable of the given - /// type. If a variable with a different type already exists then a new + /// CreateOrReplaceCXXRuntimeVariable - Will return a global variable of the + /// given type. If a variable with a different type already exists then a new /// variable with the right type will be created and all uses of the old /// variable will be replaced with a bitcast to the new variable. llvm::GlobalVariable * @@ -675,7 +713,7 @@ public: /// (if one is created). llvm::Constant *GetAddrOfConstantString(StringRef Str, const char *GlobalName=0, - unsigned Alignment=1); + unsigned Alignment=0); /// GetAddrOfConstantCString - Returns a pointer to a character array /// containing the literal and a terminating '\0' character. The result has @@ -685,7 +723,7 @@ public: /// created). llvm::Constant *GetAddrOfConstantCString(const std::string &str, const char *GlobalName=0, - unsigned Alignment=1); + unsigned Alignment=0); /// GetAddrOfConstantCompoundLiteral - Returns a pointer to a constant global /// variable for the given file-scope compound literal expression. @@ -712,8 +750,7 @@ public: llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD, unsigned BuiltinID); - llvm::Function *getIntrinsic(unsigned IID, ArrayRef<llvm::Type*> Tys = - ArrayRef<llvm::Type*>()); + llvm::Function *getIntrinsic(unsigned IID, ArrayRef<llvm::Type*> Tys = None); /// EmitTopLevelDecl - Emit code for a single top level declaration. void EmitTopLevelDecl(Decl *D); @@ -722,6 +759,12 @@ public: // variable has been instantiated. void HandleCXXStaticMemberVarInstantiation(VarDecl *VD); + /// \brief If the declaration has internal linkage but is inside an + /// extern "C" linkage specification, prepare to emit an alias for it + /// to the expected name. + template<typename SomeDecl> + void MaybeHandleStaticInExternC(const SomeDecl *D, llvm::GlobalValue *GV); + /// AddUsedGlobal - Add a global which should be forced to be /// present in the object file; these are emitted to the llvm.used /// metadata global. @@ -754,6 +797,9 @@ public: ///@} + llvm::Constant *getLLVMLifetimeStartFn(); + llvm::Constant *getLLVMLifetimeEndFn(); + // UpdateCompleteType - Make sure that this type is translated. void UpdateCompletedType(const TagDecl *TD); @@ -987,6 +1033,9 @@ private: /// a C++ destructor Decl. void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type); + /// \brief Emit the function that initializes C++ thread_local variables. + void EmitCXXThreadLocalInitFunc(); + /// EmitCXXGlobalInitFunc - Emit the function that initializes C++ globals. void EmitCXXGlobalInitFunc(); @@ -1031,6 +1080,10 @@ private: /// \brief Emit the link options introduced by imported modules. void EmitModuleLinkOptions(); + /// \brief Emit aliases for internal-linkage declarations inside "C" language + /// linkage specifications, giving them the "expected" name where possible. + void EmitStaticExternCAliases(); + void EmitDeclMetadata(); /// EmitCoverageFile - Emit the llvm.gcov metadata used to tell LLVM where diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp index cfa141ea9a..5ff1560a48 100644 --- a/lib/CodeGen/CodeGenTBAA.cpp +++ b/lib/CodeGen/CodeGenTBAA.cpp @@ -21,6 +21,7 @@ #include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" #include "clang/Frontend/CodeGenOptions.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/IR/Constants.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" @@ -49,13 +50,25 @@ llvm::MDNode *CodeGenTBAA::getRoot() { return Root; } +// For struct-path aware TBAA, the scalar type has the same format as +// the struct type: name, offset, pointer to another node in the type DAG. +// For scalar TBAA, the scalar type is the same as the scalar tag: +// name and a parent pointer. +llvm::MDNode *CodeGenTBAA::createTBAAScalarType(StringRef Name, + llvm::MDNode *Parent) { + if (CodeGenOpts.StructPathTBAA) + return MDHelper.createTBAAScalarTypeNode(Name, Parent); + else + return MDHelper.createTBAANode(Name, Parent); +} + llvm::MDNode *CodeGenTBAA::getChar() { // Define the root of the tree for user-accessible memory. C and C++ // give special powers to char and certain similar types. However, // these special powers only cover user-accessible memory, and doesn't // include things like vtables. if (!Char) - Char = MDHelper.createTBAANode("omnipotent char", getRoot()); + Char = createTBAAScalarType("omnipotent char", getRoot()); return Char; } @@ -123,7 +136,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // "underlying types". default: return MetadataCache[Ty] = - MDHelper.createTBAANode(BTy->getName(Features), getChar()); + createTBAAScalarType(BTy->getName(Features), getChar()); } } @@ -131,8 +144,8 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // TODO: Implement C++'s type "similarity" and consider dis-"similar" // pointers distinct. if (Ty->isPointerType()) - return MetadataCache[Ty] = MDHelper.createTBAANode("any pointer", - getChar()); + return MetadataCache[Ty] = createTBAAScalarType("any pointer", + getChar()); // Enum types are distinct types. In C++ they have "underlying types", // however they aren't related for TBAA. @@ -159,7 +172,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { llvm::raw_svector_ostream Out(OutName); MContext.mangleCXXRTTIName(QualType(ETy, 0), Out); Out.flush(); - return MetadataCache[Ty] = MDHelper.createTBAANode(OutName, getChar()); + return MetadataCache[Ty] = createTBAAScalarType(OutName, getChar()); } // For now, handle any other kind of type conservatively. @@ -167,7 +180,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { } llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() { - return MDHelper.createTBAANode("vtable pointer", getRoot()); + return createTBAAScalarType("vtable pointer", getRoot()); } bool @@ -191,8 +204,18 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset, const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); unsigned idx = 0; + const FieldDecl *LastFD = 0; + bool IsMsStruct = RD->isMsStruct(Context); for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { + if (IsMsStruct) { + // Zero-length bitfields following non-bitfield members are ignored. + if (Context.ZeroBitfieldFollowsNonBitfield(*i, LastFD)) { + --idx; + continue; + } + LastFD = *i; + } uint64_t Offset = BaseOffset + Layout.getFieldOffset(idx) / Context.getCharWidth(); QualType FieldQTy = i->getType(); @@ -207,7 +230,9 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset, uint64_t Offset = BaseOffset; uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity(); llvm::MDNode *TBAAInfo = MayAlias ? getChar() : getTBAAInfo(QTy); - Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAAInfo)); + llvm::MDNode *TBAATag = CodeGenOpts.StructPathTBAA ? + getTBAAScalarTagInfo(TBAAInfo) : TBAAInfo; + Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAATag)); return true; } @@ -225,3 +250,101 @@ CodeGenTBAA::getTBAAStructInfo(QualType QTy) { // For now, handle any other kind of type conservatively. return StructMetadataCache[Ty] = NULL; } + +/// Check if the given type can be handled by path-aware TBAA. +static bool isTBAAPathStruct(QualType QTy) { + if (const RecordType *TTy = QTy->getAs<RecordType>()) { + const RecordDecl *RD = TTy->getDecl()->getDefinition(); + if (RD->hasFlexibleArrayMember()) + return false; + // RD can be struct, union, class, interface or enum. + // For now, we only handle struct and class. + if (RD->isStruct() || RD->isClass()) + return true; + } + return false; +} + +llvm::MDNode * +CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) { + const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); + assert(isTBAAPathStruct(QTy)); + + if (llvm::MDNode *N = StructTypeMetadataCache[Ty]) + return N; + + if (const RecordType *TTy = QTy->getAs<RecordType>()) { + const RecordDecl *RD = TTy->getDecl()->getDefinition(); + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + SmallVector <std::pair<llvm::MDNode*, uint64_t>, 4> Fields; + unsigned idx = 0; + const FieldDecl *LastFD = 0; + bool IsMsStruct = RD->isMsStruct(Context); + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i, ++idx) { + if (IsMsStruct) { + // Zero-length bitfields following non-bitfield members are ignored. + if (Context.ZeroBitfieldFollowsNonBitfield(*i, LastFD)) { + --idx; + continue; + } + LastFD = *i; + } + + QualType FieldQTy = i->getType(); + llvm::MDNode *FieldNode; + if (isTBAAPathStruct(FieldQTy)) + FieldNode = getTBAAStructTypeInfo(FieldQTy); + else + FieldNode = getTBAAInfo(FieldQTy); + if (!FieldNode) + return StructTypeMetadataCache[Ty] = NULL; + Fields.push_back(std::make_pair( + FieldNode, Layout.getFieldOffset(idx) / Context.getCharWidth())); + } + + // TODO: This is using the RTTI name. Is there a better way to get + // a unique string for a type? + SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + MContext.mangleCXXRTTIName(QualType(Ty, 0), Out); + Out.flush(); + // Create the struct type node with a vector of pairs (offset, type). + return StructTypeMetadataCache[Ty] = + MDHelper.createTBAAStructTypeNode(OutName, Fields); + } + + return StructMetadataCache[Ty] = NULL; +} + +llvm::MDNode * +CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode, + uint64_t Offset) { + if (!CodeGenOpts.StructPathTBAA) + return AccessNode; + + const Type *BTy = Context.getCanonicalType(BaseQTy).getTypePtr(); + TBAAPathTag PathTag = TBAAPathTag(BTy, AccessNode, Offset); + if (llvm::MDNode *N = StructTagMetadataCache[PathTag]) + return N; + + llvm::MDNode *BNode = 0; + if (isTBAAPathStruct(BaseQTy)) + BNode = getTBAAStructTypeInfo(BaseQTy); + if (!BNode) + return StructTagMetadataCache[PathTag] = + MDHelper.createTBAAStructTagNode(AccessNode, AccessNode, 0); + + return StructTagMetadataCache[PathTag] = + MDHelper.createTBAAStructTagNode(BNode, AccessNode, Offset); +} + +llvm::MDNode * +CodeGenTBAA::getTBAAScalarTagInfo(llvm::MDNode *AccessNode) { + if (llvm::MDNode *N = ScalarTagMetadataCache[AccessNode]) + return N; + + return ScalarTagMetadataCache[AccessNode] = + MDHelper.createTBAAStructTagNode(AccessNode, AccessNode, 0); +} diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h index 4c6e045fce..f0c9e06f02 100644 --- a/lib/CodeGen/CodeGenTBAA.h +++ b/lib/CodeGen/CodeGenTBAA.h @@ -35,6 +35,14 @@ namespace clang { namespace CodeGen { class CGRecordLayout; + struct TBAAPathTag { + TBAAPathTag(const Type *B, const llvm::MDNode *A, uint64_t O) + : BaseT(B), AccessN(A), Offset(O) {} + const Type *BaseT; + const llvm::MDNode *AccessN; + uint64_t Offset; + }; + /// CodeGenTBAA - This class organizes the cross-module state that is used /// while lowering AST types to LLVM types. class CodeGenTBAA { @@ -46,8 +54,15 @@ class CodeGenTBAA { // MDHelper - Helper for creating metadata. llvm::MDBuilder MDHelper; - /// MetadataCache - This maps clang::Types to llvm::MDNodes describing them. + /// MetadataCache - This maps clang::Types to scalar llvm::MDNodes describing + /// them. llvm::DenseMap<const Type *, llvm::MDNode *> MetadataCache; + /// This maps clang::Types to a struct node in the type DAG. + llvm::DenseMap<const Type *, llvm::MDNode *> StructTypeMetadataCache; + /// This maps TBAAPathTags to a tag node. + llvm::DenseMap<TBAAPathTag, llvm::MDNode *> StructTagMetadataCache; + /// This maps a scalar type to a scalar tag node. + llvm::DenseMap<const llvm::MDNode *, llvm::MDNode *> ScalarTagMetadataCache; /// StructMetadataCache - This maps clang::Types to llvm::MDNodes describing /// them for struct assignments. @@ -71,6 +86,11 @@ class CodeGenTBAA { SmallVectorImpl<llvm::MDBuilder::TBAAStructField> &Fields, bool MayAlias); + /// A wrapper function to create a scalar type. For struct-path aware TBAA, + /// the scalar type has the same format as the struct type: name, offset, + /// pointer to another node in the type DAG. + llvm::MDNode *createTBAAScalarType(StringRef Name, llvm::MDNode *Parent); + public: CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext &VMContext, const CodeGenOptions &CGO, @@ -89,9 +109,52 @@ public: /// getTBAAStructInfo - Get the TBAAStruct MDNode to be used for a memcpy of /// the given type. llvm::MDNode *getTBAAStructInfo(QualType QTy); + + /// Get the MDNode in the type DAG for given struct type QType. + llvm::MDNode *getTBAAStructTypeInfo(QualType QType); + /// Get the tag MDNode for a given base type, the actual scalar access MDNode + /// and offset into the base type. + llvm::MDNode *getTBAAStructTagInfo(QualType BaseQType, + llvm::MDNode *AccessNode, uint64_t Offset); + + /// Get the sclar tag MDNode for a given scalar type. + llvm::MDNode *getTBAAScalarTagInfo(llvm::MDNode *AccessNode); }; } // end namespace CodeGen } // end namespace clang +namespace llvm { + +template<> struct DenseMapInfo<clang::CodeGen::TBAAPathTag> { + static clang::CodeGen::TBAAPathTag getEmptyKey() { + return clang::CodeGen::TBAAPathTag( + DenseMapInfo<const clang::Type *>::getEmptyKey(), + DenseMapInfo<const MDNode *>::getEmptyKey(), + DenseMapInfo<uint64_t>::getEmptyKey()); + } + + static clang::CodeGen::TBAAPathTag getTombstoneKey() { + return clang::CodeGen::TBAAPathTag( + DenseMapInfo<const clang::Type *>::getTombstoneKey(), + DenseMapInfo<const MDNode *>::getTombstoneKey(), + DenseMapInfo<uint64_t>::getTombstoneKey()); + } + + static unsigned getHashValue(const clang::CodeGen::TBAAPathTag &Val) { + return DenseMapInfo<const clang::Type *>::getHashValue(Val.BaseT) ^ + DenseMapInfo<const MDNode *>::getHashValue(Val.AccessN) ^ + DenseMapInfo<uint64_t>::getHashValue(Val.Offset); + } + + static bool isEqual(const clang::CodeGen::TBAAPathTag &LHS, + const clang::CodeGen::TBAAPathTag &RHS) { + return LHS.BaseT == RHS.BaseT && + LHS.AccessN == RHS.AccessN && + LHS.Offset == RHS.Offset; + } +}; + +} // end namespace llvm + #endif diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 8fc78e3de6..4240216b23 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -28,12 +28,12 @@ using namespace clang; using namespace CodeGen; -CodeGenTypes::CodeGenTypes(CodeGenModule &CGM) - : Context(CGM.getContext()), Target(Context.getTargetInfo()), - TheModule(CGM.getModule()), TheDataLayout(CGM.getDataLayout()), - TheABIInfo(CGM.getTargetCodeGenInfo().getABIInfo()), - TheCXXABI(CGM.getCXXABI()), - CodeGenOpts(CGM.getCodeGenOpts()), CGM(CGM) { +CodeGenTypes::CodeGenTypes(CodeGenModule &cgm) + : CGM(cgm), Context(cgm.getContext()), TheModule(cgm.getModule()), + TheDataLayout(cgm.getDataLayout()), + Target(cgm.getTarget()), TheCXXABI(cgm.getCXXABI()), + CodeGenOpts(cgm.getCodeGenOpts()), + TheABIInfo(cgm.getTargetCodeGenInfo().getABIInfo()) { SkippedLayout = false; } @@ -392,6 +392,8 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { } break; } + case Type::Auto: + llvm_unreachable("Unexpected undeduced auto type!"); case Type::Complex: { llvm::Type *EltTy = ConvertType(cast<ComplexType>(Ty)->getElementType()); ResultType = llvm::StructType::get(EltTy, EltTy, NULL); diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 11fd76fb19..452375f374 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -60,14 +60,17 @@ namespace CodeGen { class CodeGenTypes { public: // Some of this stuff should probably be left on the CGM. + CodeGenModule &CGM; ASTContext &Context; - const TargetInfo &Target; llvm::Module &TheModule; const llvm::DataLayout &TheDataLayout; - const ABIInfo &TheABIInfo; + const TargetInfo &Target; CGCXXABI &TheCXXABI; const CodeGenOptions &CodeGenOpts; - CodeGenModule &CGM; + + // This should not be moved earlier, since its initialization depends on some + // of the previous reference members being already initialized + const ABIInfo &TheABIInfo; private: /// The opaque type map for Objective-C interfaces. All direct @@ -107,14 +110,14 @@ private: llvm::DenseMap<const Type *, llvm::Type *> TypeCache; public: - CodeGenTypes(CodeGenModule &CGM); + CodeGenTypes(CodeGenModule &cgm); ~CodeGenTypes(); const llvm::DataLayout &getDataLayout() const { return TheDataLayout; } - const TargetInfo &getTarget() const { return Target; } ASTContext &getContext() const { return Context; } const ABIInfo &getABIInfo() const { return TheABIInfo; } const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } + const TargetInfo &getTarget() const { return Target; } CGCXXABI &getCXXABI() const { return TheCXXABI; } llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); } diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index b314fd6a39..9ab3f8c3ee 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -39,7 +39,6 @@ private: protected: bool UseARMMethodPtrABI; bool UseARMGuardVarABI; - // It's a little silly for us to cache this. llvm::IntegerType *getPtrDiffTy() { if (!PtrDiffTy) { @@ -117,7 +116,7 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); - void EmitConstructorCall(CodeGenFunction &CGF, + llvm::Value *EmitConstructorCall(CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, bool Delegating, @@ -147,8 +146,16 @@ public: void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, llvm::GlobalVariable *DeclPtr, bool PerformInit); - void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor, - llvm::Constant *addr); + void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, + llvm::Constant *dtor, llvm::Constant *addr); + + llvm::Function *getOrCreateThreadLocalWrapper(const VarDecl *VD, + llvm::GlobalVariable *Var); + void EmitThreadLocalInitFuncs( + llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls, + llvm::Function *InitFunc); + LValue EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, + const DeclRefExpr *DRE); }; class ARMCXXABI : public ItaniumCXXABI { @@ -184,11 +191,11 @@ public: llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr, CharUnits cookieSize); -private: /// \brief Returns true if the given instance method is one of the /// kinds that the ARM ABI says returns 'this'. - static bool HasThisReturn(GlobalDecl GD) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + bool HasThisReturn(GlobalDecl GD) const { + const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(GD.getDecl()); + if (!MD) return false; return ((isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Deleting) || (isa<CXXConstructorDecl>(MD))); } @@ -196,7 +203,7 @@ private: } CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) { - switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) { + switch (CGM.getTarget().getCXXABI().getKind()) { // For IR-generation purposes, there's no significant difference // between the ARM and iOS ABIs. case TargetCXXABI::GenericARM: @@ -230,8 +237,8 @@ CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) { llvm::Type * ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { if (MPT->isMemberDataPointer()) - return getPtrDiffTy(); - return llvm::StructType::get(getPtrDiffTy(), getPtrDiffTy(), NULL); + return CGM.PtrDiffTy; + return llvm::StructType::get(CGM.PtrDiffTy, CGM.PtrDiffTy, NULL); } /// In the Itanium and ARM ABIs, method pointers have the form: @@ -270,8 +277,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, CGM.getTypes().GetFunctionType( CGM.getTypes().arrangeCXXMethodType(RD, FPT)); - llvm::IntegerType *ptrdiff = getPtrDiffTy(); - llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(ptrdiff, 1); + llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(CGM.PtrDiffTy, 1); llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("memptr.virtual"); llvm::BasicBlock *FnNonVirtual = CGF.createBasicBlock("memptr.nonvirtual"); @@ -345,7 +351,7 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, llvm::Value *Base, llvm::Value *MemPtr, const MemberPointerType *MPT) { - assert(MemPtr->getType() == getPtrDiffTy()); + assert(MemPtr->getType() == CGM.PtrDiffTy); CGBuilderTy &Builder = CGF.Builder; @@ -493,14 +499,12 @@ ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E, llvm::Constant * ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { - llvm::Type *ptrdiff_t = getPtrDiffTy(); - // Itanium C++ ABI 2.3: // A NULL pointer is represented as -1. if (MPT->isMemberDataPointer()) - return llvm::ConstantInt::get(ptrdiff_t, -1ULL, /*isSigned=*/true); + return llvm::ConstantInt::get(CGM.PtrDiffTy, -1ULL, /*isSigned=*/true); - llvm::Constant *Zero = llvm::ConstantInt::get(ptrdiff_t, 0); + llvm::Constant *Zero = llvm::ConstantInt::get(CGM.PtrDiffTy, 0); llvm::Constant *Values[2] = { Zero, Zero }; return llvm::ConstantStruct::getAnon(Values); } @@ -511,7 +515,7 @@ ItaniumCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, // Itanium C++ ABI 2.3: // A pointer to data member is an offset from the base address of // the class object containing it, represented as a ptrdiff_t - return llvm::ConstantInt::get(getPtrDiffTy(), offset.getQuantity()); + return llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity()); } llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { @@ -524,7 +528,6 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD, MD = MD->getCanonicalDecl(); CodeGenTypes &Types = CGM.getTypes(); - llvm::Type *ptrdiff_t = getPtrDiffTy(); // Get the function pointer (or index if this is a virtual function). llvm::Constant *MemPtr[2]; @@ -543,16 +546,16 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD, // least significant bit of adj then makes exactly the same // discrimination as the least significant bit of ptr does for // Itanium. - MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset); - MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, + MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset); + MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy, 2 * ThisAdjustment.getQuantity() + 1); } else { // Itanium C++ ABI 2.3: // For a virtual function, [the pointer field] is 1 plus the // virtual table offset (in bytes) of the function, // represented as a ptrdiff_t. - MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1); - MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, + MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset + 1); + MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy, ThisAdjustment.getQuantity()); } } else { @@ -565,7 +568,7 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD, } else { // Use an arbitrary non-function type to tell GetAddrOfFunction that the // function type is incomplete. - Ty = ptrdiff_t; + Ty = CGM.PtrDiffTy; } llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty); @@ -696,7 +699,7 @@ ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, /// For member data pointers, this is just a check against -1. if (MPT->isMemberDataPointer()) { - assert(MemPtr->getType() == getPtrDiffTy()); + assert(MemPtr->getType() == CGM.PtrDiffTy); llvm::Value *NegativeOne = llvm::Constant::getAllOnesValue(MemPtr->getType()); return Builder.CreateICmpNE(MemPtr, NegativeOne, "memptr.tobool"); @@ -852,7 +855,7 @@ void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue); } -void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF, +llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, bool Delegating, @@ -867,6 +870,7 @@ void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF, // FIXME: Provide a source location here. CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, VTT, VTTTy, ArgBeg, ArgEnd); + return Callee; } RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, @@ -1075,10 +1079,10 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, bool shouldPerformInit) { CGBuilderTy &Builder = CGF.Builder; - // We only need to use thread-safe statics for local variables; + // We only need to use thread-safe statics for local non-TLS variables; // global initialization is always single-threaded. - bool threadsafe = - (getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl()); + bool threadsafe = getContext().getLangOpts().ThreadsafeStatics && + D.isLocalVarDecl() && !D.getTLSKind(); // If we have a global variable with internal linkage and thread-safe statics // are disabled, we can just let the guard variable be of type i8. @@ -1113,6 +1117,8 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, llvm::ConstantInt::get(guardTy, 0), guardName.str()); guard->setVisibility(var->getVisibility()); + // If the variable is thread-local, so is its guard variable. + guard->setThreadLocalMode(var->getThreadLocalMode()); CGM.setStaticLocalDeclGuardAddress(&D, guard); } @@ -1213,7 +1219,14 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, /// Register a global destructor using __cxa_atexit. static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF, llvm::Constant *dtor, - llvm::Constant *addr) { + llvm::Constant *addr, + bool TLS) { + const char *Name = "__cxa_atexit"; + if (TLS) { + const llvm::Triple &T = CGF.getTarget().getTriple(); + Name = T.isMacOSX() ? "_tlv_atexit" : "__cxa_thread_atexit"; + } + // We're assuming that the destructor function is something we can // reasonably call with the default CC. Go ahead and cast it to the // right prototype. @@ -1226,8 +1239,7 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF, llvm::FunctionType::get(CGF.IntTy, paramTys, false); // Fetch the actual function. - llvm::Constant *atexit = - CGF.CGM.CreateRuntimeFunction(atexitTy, "__cxa_atexit"); + llvm::Constant *atexit = CGF.CGM.CreateRuntimeFunction(atexitTy, Name); if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit)) fn->setDoesNotThrow(); @@ -1245,12 +1257,15 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF, /// Register a global destructor as best as we know how. void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF, + const VarDecl &D, llvm::Constant *dtor, llvm::Constant *addr) { // Use __cxa_atexit if available. - if (CGM.getCodeGenOpts().CXAAtExit) { - return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr); - } + if (CGM.getCodeGenOpts().CXAAtExit) + return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr, D.getTLSKind()); + + if (D.getTLSKind()) + CGM.ErrorUnsupported(&D, "non-trivial TLS destruction"); // In Apple kexts, we want to add a global destructor entry. // FIXME: shouldn't this be guarded by some variable? @@ -1261,3 +1276,138 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF, CGF.registerGlobalDtorWithAtExit(dtor, addr); } + +/// Get the appropriate linkage for the wrapper function. This is essentially +/// the weak form of the variable's linkage; every translation unit which wneeds +/// the wrapper emits a copy, and we want the linker to merge them. +static llvm::GlobalValue::LinkageTypes getThreadLocalWrapperLinkage( + llvm::GlobalValue::LinkageTypes VarLinkage) { + if (llvm::GlobalValue::isLinkerPrivateLinkage(VarLinkage)) + return llvm::GlobalValue::LinkerPrivateWeakLinkage; + // For internal linkage variables, we don't need an external or weak wrapper. + if (llvm::GlobalValue::isLocalLinkage(VarLinkage)) + return VarLinkage; + return llvm::GlobalValue::WeakODRLinkage; +} + +llvm::Function * +ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD, + llvm::GlobalVariable *Var) { + // Mangle the name for the thread_local wrapper function. + SmallString<256> WrapperName; + { + llvm::raw_svector_ostream Out(WrapperName); + getMangleContext().mangleItaniumThreadLocalWrapper(VD, Out); + Out.flush(); + } + + if (llvm::Value *V = Var->getParent()->getNamedValue(WrapperName)) + return cast<llvm::Function>(V); + + llvm::Type *RetTy = Var->getType(); + if (VD->getType()->isReferenceType()) + RetTy = RetTy->getPointerElementType(); + + llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, false); + llvm::Function *Wrapper = llvm::Function::Create( + FnTy, getThreadLocalWrapperLinkage(Var->getLinkage()), WrapperName.str(), + &CGM.getModule()); + // Always resolve references to the wrapper at link time. + Wrapper->setVisibility(llvm::GlobalValue::HiddenVisibility); + return Wrapper; +} + +void ItaniumCXXABI::EmitThreadLocalInitFuncs( + llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls, + llvm::Function *InitFunc) { + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + const VarDecl *VD = Decls[I].first; + llvm::GlobalVariable *Var = Decls[I].second; + + // Mangle the name for the thread_local initialization function. + SmallString<256> InitFnName; + { + llvm::raw_svector_ostream Out(InitFnName); + getMangleContext().mangleItaniumThreadLocalInit(VD, Out); + Out.flush(); + } + + // If we have a definition for the variable, emit the initialization + // function as an alias to the global Init function (if any). Otherwise, + // produce a declaration of the initialization function. + llvm::GlobalValue *Init = 0; + bool InitIsInitFunc = false; + if (VD->hasDefinition()) { + InitIsInitFunc = true; + if (InitFunc) + Init = + new llvm::GlobalAlias(InitFunc->getType(), Var->getLinkage(), + InitFnName.str(), InitFunc, &CGM.getModule()); + } else { + // Emit a weak global function referring to the initialization function. + // This function will not exist if the TU defining the thread_local + // variable in question does not need any dynamic initialization for + // its thread_local variables. + llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, false); + Init = llvm::Function::Create( + FnTy, llvm::GlobalVariable::ExternalWeakLinkage, InitFnName.str(), + &CGM.getModule()); + } + + if (Init) + Init->setVisibility(Var->getVisibility()); + + llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Var); + llvm::LLVMContext &Context = CGM.getModule().getContext(); + llvm::BasicBlock *Entry = llvm::BasicBlock::Create(Context, "", Wrapper); + CGBuilderTy Builder(Entry); + if (InitIsInitFunc) { + if (Init) + Builder.CreateCall(Init); + } else { + // Don't know whether we have an init function. Call it if it exists. + llvm::Value *Have = Builder.CreateIsNotNull(Init); + llvm::BasicBlock *InitBB = llvm::BasicBlock::Create(Context, "", Wrapper); + llvm::BasicBlock *ExitBB = llvm::BasicBlock::Create(Context, "", Wrapper); + Builder.CreateCondBr(Have, InitBB, ExitBB); + + Builder.SetInsertPoint(InitBB); + Builder.CreateCall(Init); + Builder.CreateBr(ExitBB); + + Builder.SetInsertPoint(ExitBB); + } + + // For a reference, the result of the wrapper function is a pointer to + // the referenced object. + llvm::Value *Val = Var; + if (VD->getType()->isReferenceType()) { + llvm::LoadInst *LI = Builder.CreateLoad(Val); + LI->setAlignment(CGM.getContext().getDeclAlign(VD).getQuantity()); + Val = LI; + } + + Builder.CreateRet(Val); + } +} + +LValue ItaniumCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, + const DeclRefExpr *DRE) { + const VarDecl *VD = cast<VarDecl>(DRE->getDecl()); + QualType T = VD->getType(); + llvm::Type *Ty = CGF.getTypes().ConvertTypeForMem(T); + llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD, Ty); + llvm::Function *Wrapper = + getOrCreateThreadLocalWrapper(VD, cast<llvm::GlobalVariable>(Val)); + + Val = CGF.Builder.CreateCall(Wrapper); + + LValue LV; + if (VD->getType()->isReferenceType()) + LV = CGF.MakeNaturalAlignAddrLValue(Val, T); + else + LV = CGF.MakeAddrLValue(Val, DRE->getType(), + CGF.getContext().getDeclAlign(VD)); + // FIXME: need setObjCGCLValueClass? + return LV; +} diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index fb6b86d878..f5242eaaa2 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -28,6 +28,17 @@ class MicrosoftCXXABI : public CGCXXABI { public: MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {} + bool isReturnTypeIndirect(const CXXRecordDecl *RD) const { + // Structures that are not C++03 PODs are always indirect. + return !RD->isPOD(); + } + + RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const { + if (RD->hasNonTrivialCopyConstructor()) + return RAA_DirectInMemory; + return RAA_Default; + } + StringRef GetPureVirtualCallName() { return "_purecall"; } // No known support for deleted functions in MSVC yet, so this choice is // arbitrary. @@ -55,7 +66,7 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); - void EmitConstructorCall(CodeGenFunction &CGF, + llvm::Value *EmitConstructorCall(CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, bool Delegating, @@ -109,6 +120,64 @@ public: llvm::Value *allocPtr, CharUnits cookieSize); static bool needThisReturn(GlobalDecl GD); + +private: + llvm::Constant *getZeroInt() { + return llvm::ConstantInt::get(CGM.IntTy, 0); + } + + llvm::Constant *getAllOnesInt() { + return llvm::Constant::getAllOnesValue(CGM.IntTy); + } + + void + GetNullMemberPointerFields(const MemberPointerType *MPT, + llvm::SmallVectorImpl<llvm::Constant *> &fields); + + llvm::Value *AdjustVirtualBase(CodeGenFunction &CGF, const CXXRecordDecl *RD, + llvm::Value *Base, + llvm::Value *VirtualBaseAdjustmentOffset, + llvm::Value *VBPtrOffset /* optional */); + + /// \brief Emits a full member pointer with the fields common to data and + /// function member pointers. + llvm::Constant *EmitFullMemberPointer(llvm::Constant *FirstField, + bool IsMemberFunction, + const CXXRecordDecl *RD); + +public: + virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT); + + virtual bool isZeroInitializable(const MemberPointerType *MPT); + + virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); + + virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT, + CharUnits offset); + virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); + virtual llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT); + + virtual llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality); + + virtual llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT); + + virtual llvm::Value *EmitMemberDataPointerAddress(CodeGenFunction &CGF, + llvm::Value *Base, + llvm::Value *MemPtr, + const MemberPointerType *MPT); + + virtual llvm::Value * + EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, + llvm::Value *&This, + llvm::Value *MemPtr, + const MemberPointerType *MPT); + }; } @@ -238,7 +307,7 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { } } -void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, +llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, bool Delegating, @@ -259,6 +328,7 @@ void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, ImplicitParam, ImplicitParamTy, ArgBeg, ArgEnd); + return Callee; } RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, @@ -347,10 +417,441 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, // Not sure whether we want thread-safe static local variables as VS // doesn't make them thread-safe. + if (D.getTLSKind()) + CGM.ErrorUnsupported(&D, "dynamic TLS initialization"); + // Emit the initializer and add a global destructor if appropriate. CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit); } +// Member pointer helpers. +static bool hasVBPtrOffsetField(MSInheritanceModel Inheritance) { + return Inheritance == MSIM_Unspecified; +} + +static bool hasOnlyOneField(MSInheritanceModel Inheritance) { + return Inheritance <= MSIM_SinglePolymorphic; +} + +// Only member pointers to functions need a this adjustment, since it can be +// combined with the field offset for data pointers. +static bool hasNonVirtualBaseAdjustmentField(bool IsMemberFunction, + MSInheritanceModel Inheritance) { + return (IsMemberFunction && Inheritance >= MSIM_Multiple); +} + +static bool hasVirtualBaseAdjustmentField(MSInheritanceModel Inheritance) { + return Inheritance >= MSIM_Virtual; +} + +// Use zero for the field offset of a null data member pointer if we can +// guarantee that zero is not a valid field offset, or if the member pointer has +// multiple fields. Polymorphic classes have a vfptr at offset zero, so we can +// use zero for null. If there are multiple fields, we can use zero even if it +// is a valid field offset because null-ness testing will check the other +// fields. +static bool nullFieldOffsetIsZero(MSInheritanceModel Inheritance) { + return Inheritance != MSIM_Multiple && Inheritance != MSIM_Single; +} + +bool MicrosoftCXXABI::isZeroInitializable(const MemberPointerType *MPT) { + // Null-ness for function memptrs only depends on the first field, which is + // the function pointer. The rest don't matter, so we can zero initialize. + if (MPT->isMemberFunctionPointer()) + return true; + + // The virtual base adjustment field is always -1 for null, so if we have one + // we can't zero initialize. The field offset is sometimes also -1 if 0 is a + // valid field offset. + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + return (!hasVirtualBaseAdjustmentField(Inheritance) && + nullFieldOffsetIsZero(Inheritance)); +} + +llvm::Type * +MicrosoftCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + llvm::SmallVector<llvm::Type *, 4> fields; + if (MPT->isMemberFunctionPointer()) + fields.push_back(CGM.VoidPtrTy); // FunctionPointerOrVirtualThunk + else + fields.push_back(CGM.IntTy); // FieldOffset + + if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(), + Inheritance)) + fields.push_back(CGM.IntTy); + if (hasVBPtrOffsetField(Inheritance)) + fields.push_back(CGM.IntTy); + if (hasVirtualBaseAdjustmentField(Inheritance)) + fields.push_back(CGM.IntTy); // VirtualBaseAdjustmentOffset + + if (fields.size() == 1) + return fields[0]; + return llvm::StructType::get(CGM.getLLVMContext(), fields); +} + +void MicrosoftCXXABI:: +GetNullMemberPointerFields(const MemberPointerType *MPT, + llvm::SmallVectorImpl<llvm::Constant *> &fields) { + assert(fields.empty()); + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + if (MPT->isMemberFunctionPointer()) { + // FunctionPointerOrVirtualThunk + fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy)); + } else { + if (nullFieldOffsetIsZero(Inheritance)) + fields.push_back(getZeroInt()); // FieldOffset + else + fields.push_back(getAllOnesInt()); // FieldOffset + } + + if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(), + Inheritance)) + fields.push_back(getZeroInt()); + if (hasVBPtrOffsetField(Inheritance)) + fields.push_back(getZeroInt()); + if (hasVirtualBaseAdjustmentField(Inheritance)) + fields.push_back(getAllOnesInt()); +} + +llvm::Constant * +MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { + llvm::SmallVector<llvm::Constant *, 4> fields; + GetNullMemberPointerFields(MPT, fields); + if (fields.size() == 1) + return fields[0]; + llvm::Constant *Res = llvm::ConstantStruct::getAnon(fields); + assert(Res->getType() == ConvertMemberPointerType(MPT)); + return Res; +} + +llvm::Constant * +MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField, + bool IsMemberFunction, + const CXXRecordDecl *RD) +{ + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + + // Single inheritance class member pointer are represented as scalars instead + // of aggregates. + if (hasOnlyOneField(Inheritance)) + return FirstField; + + llvm::SmallVector<llvm::Constant *, 4> fields; + fields.push_back(FirstField); + + if (hasNonVirtualBaseAdjustmentField(IsMemberFunction, Inheritance)) + fields.push_back(getZeroInt()); + + if (hasVBPtrOffsetField(Inheritance)) { + int64_t VBPtrOffset = + getContext().getASTRecordLayout(RD).getVBPtrOffset().getQuantity(); + if (VBPtrOffset == -1) + VBPtrOffset = 0; + fields.push_back(llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset)); + } + + // The rest of the fields are adjusted by conversions to a more derived class. + if (hasVirtualBaseAdjustmentField(Inheritance)) + fields.push_back(getZeroInt()); + + return llvm::ConstantStruct::getAnon(fields); +} + +llvm::Constant * +MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, + CharUnits offset) { + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + llvm::Constant *FirstField = + llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity()); + return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD); +} + +llvm::Constant * +MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { + assert(MD->isInstance() && "Member function must not be static!"); + MD = MD->getCanonicalDecl(); + const CXXRecordDecl *RD = MD->getParent(); + CodeGenTypes &Types = CGM.getTypes(); + + llvm::Constant *FirstField; + if (MD->isVirtual()) { + // FIXME: We have to instantiate a thunk that loads the vftable and jumps to + // the right offset. + FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy); + } else { + const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); + llvm::Type *Ty; + // Check whether the function has a computable LLVM signature. + if (Types.isFuncTypeConvertible(FPT)) { + // The function has a computable LLVM signature; use the correct type. + Ty = Types.GetFunctionType(Types.arrangeCXXMethodDeclaration(MD)); + } else { + // Use an arbitrary non-function type to tell GetAddrOfFunction that the + // function type is incomplete. + Ty = CGM.PtrDiffTy; + } + FirstField = CGM.GetAddrOfFunction(MD, Ty); + FirstField = llvm::ConstantExpr::getBitCast(FirstField, CGM.VoidPtrTy); + } + + // The rest of the fields are common with data member pointers. + return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/true, RD); +} + +llvm::Constant * +MicrosoftCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) { + // FIXME PR15875: Implement member pointer conversions for Constants. + const CXXRecordDecl *RD = MPT->castAs<MemberPointerType>()->getClass()->getAsCXXRecordDecl(); + return EmitFullMemberPointer(llvm::Constant::getNullValue(CGM.VoidPtrTy), + /*IsMemberFunction=*/true, RD); +} + +/// Member pointers are the same if they're either bitwise identical *or* both +/// null. Null-ness for function members is determined by the first field, +/// while for data member pointers we must compare all fields. +llvm::Value * +MicrosoftCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality) { + CGBuilderTy &Builder = CGF.Builder; + + // Handle != comparisons by switching the sense of all boolean operations. + llvm::ICmpInst::Predicate Eq; + llvm::Instruction::BinaryOps And, Or; + if (Inequality) { + Eq = llvm::ICmpInst::ICMP_NE; + And = llvm::Instruction::Or; + Or = llvm::Instruction::And; + } else { + Eq = llvm::ICmpInst::ICMP_EQ; + And = llvm::Instruction::And; + Or = llvm::Instruction::Or; + } + + // If this is a single field member pointer (single inheritance), this is a + // single icmp. + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + if (hasOnlyOneField(Inheritance)) + return Builder.CreateICmp(Eq, L, R); + + // Compare the first field. + llvm::Value *L0 = Builder.CreateExtractValue(L, 0, "lhs.0"); + llvm::Value *R0 = Builder.CreateExtractValue(R, 0, "rhs.0"); + llvm::Value *Cmp0 = Builder.CreateICmp(Eq, L0, R0, "memptr.cmp.first"); + + // Compare everything other than the first field. + llvm::Value *Res = 0; + llvm::StructType *LType = cast<llvm::StructType>(L->getType()); + for (unsigned I = 1, E = LType->getNumElements(); I != E; ++I) { + llvm::Value *LF = Builder.CreateExtractValue(L, I); + llvm::Value *RF = Builder.CreateExtractValue(R, I); + llvm::Value *Cmp = Builder.CreateICmp(Eq, LF, RF, "memptr.cmp.rest"); + if (Res) + Res = Builder.CreateBinOp(And, Res, Cmp); + else + Res = Cmp; + } + + // Check if the first field is 0 if this is a function pointer. + if (MPT->isMemberFunctionPointer()) { + // (l1 == r1 && ...) || l0 == 0 + llvm::Value *Zero = llvm::Constant::getNullValue(L0->getType()); + llvm::Value *IsZero = Builder.CreateICmp(Eq, L0, Zero, "memptr.cmp.iszero"); + Res = Builder.CreateBinOp(Or, Res, IsZero); + } + + // Combine the comparison of the first field, which must always be true for + // this comparison to succeeed. + return Builder.CreateBinOp(And, Res, Cmp0, "memptr.cmp"); +} + +llvm::Value * +MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + CGBuilderTy &Builder = CGF.Builder; + llvm::SmallVector<llvm::Constant *, 4> fields; + // We only need one field for member functions. + if (MPT->isMemberFunctionPointer()) + fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy)); + else + GetNullMemberPointerFields(MPT, fields); + assert(!fields.empty()); + llvm::Value *FirstField = MemPtr; + if (MemPtr->getType()->isStructTy()) + FirstField = Builder.CreateExtractValue(MemPtr, 0); + llvm::Value *Res = Builder.CreateICmpNE(FirstField, fields[0], "memptr.cmp0"); + + // For function member pointers, we only need to test the function pointer + // field. The other fields if any can be garbage. + if (MPT->isMemberFunctionPointer()) + return Res; + + // Otherwise, emit a series of compares and combine the results. + for (int I = 1, E = fields.size(); I < E; ++I) { + llvm::Value *Field = Builder.CreateExtractValue(MemPtr, I); + llvm::Value *Next = Builder.CreateICmpNE(Field, fields[I], "memptr.cmp"); + Res = Builder.CreateAnd(Res, Next, "memptr.tobool"); + } + return Res; +} + +// Returns an adjusted base cast to i8*, since we do more address arithmetic on +// it. +llvm::Value * +MicrosoftCXXABI::AdjustVirtualBase(CodeGenFunction &CGF, + const CXXRecordDecl *RD, llvm::Value *Base, + llvm::Value *VirtualBaseAdjustmentOffset, + llvm::Value *VBPtrOffset) { + CGBuilderTy &Builder = CGF.Builder; + Base = Builder.CreateBitCast(Base, CGM.Int8PtrTy); + llvm::BasicBlock *OriginalBB = 0; + llvm::BasicBlock *SkipAdjustBB = 0; + llvm::BasicBlock *VBaseAdjustBB = 0; + + // In the unspecified inheritance model, there might not be a vbtable at all, + // in which case we need to skip the virtual base lookup. If there is a + // vbtable, the first entry is a no-op entry that gives back the original + // base, so look for a virtual base adjustment offset of zero. + if (VBPtrOffset) { + OriginalBB = Builder.GetInsertBlock(); + VBaseAdjustBB = CGF.createBasicBlock("memptr.vadjust"); + SkipAdjustBB = CGF.createBasicBlock("memptr.skip_vadjust"); + llvm::Value *IsVirtual = + Builder.CreateICmpNE(VirtualBaseAdjustmentOffset, getZeroInt(), + "memptr.is_vbase"); + Builder.CreateCondBr(IsVirtual, VBaseAdjustBB, SkipAdjustBB); + CGF.EmitBlock(VBaseAdjustBB); + } + + // If we weren't given a dynamic vbptr offset, RD should be complete and we'll + // know the vbptr offset. + if (!VBPtrOffset) { + CharUnits offs = getContext().getASTRecordLayout(RD).getVBPtrOffset(); + VBPtrOffset = llvm::ConstantInt::get(CGM.IntTy, offs.getQuantity()); + } + // Load the vbtable pointer from the vbtable offset in the instance. + llvm::Value *VBPtr = + Builder.CreateInBoundsGEP(Base, VBPtrOffset, "memptr.vbptr"); + llvm::Value *VBTable = + Builder.CreateBitCast(VBPtr, CGM.Int8PtrTy->getPointerTo(0)); + VBTable = Builder.CreateLoad(VBTable, "memptr.vbtable"); + // Load an i32 offset from the vb-table. + llvm::Value *VBaseOffs = + Builder.CreateInBoundsGEP(VBTable, VirtualBaseAdjustmentOffset); + VBaseOffs = Builder.CreateBitCast(VBaseOffs, CGM.Int32Ty->getPointerTo(0)); + VBaseOffs = Builder.CreateLoad(VBaseOffs, "memptr.vbase_offs"); + // Add it to VBPtr. GEP will sign extend the i32 value for us. + llvm::Value *AdjustedBase = Builder.CreateInBoundsGEP(VBPtr, VBaseOffs); + + // Merge control flow with the case where we didn't have to adjust. + if (VBaseAdjustBB) { + Builder.CreateBr(SkipAdjustBB); + CGF.EmitBlock(SkipAdjustBB); + llvm::PHINode *Phi = Builder.CreatePHI(CGM.Int8PtrTy, 2, "memptr.base"); + Phi->addIncoming(Base, OriginalBB); + Phi->addIncoming(AdjustedBase, VBaseAdjustBB); + return Phi; + } + return AdjustedBase; +} + +llvm::Value * +MicrosoftCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, + llvm::Value *Base, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + assert(MPT->isMemberDataPointer()); + unsigned AS = Base->getType()->getPointerAddressSpace(); + llvm::Type *PType = + CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS); + CGBuilderTy &Builder = CGF.Builder; + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + + // Extract the fields we need, regardless of model. We'll apply them if we + // have them. + llvm::Value *FieldOffset = MemPtr; + llvm::Value *VirtualBaseAdjustmentOffset = 0; + llvm::Value *VBPtrOffset = 0; + if (MemPtr->getType()->isStructTy()) { + // We need to extract values. + unsigned I = 0; + FieldOffset = Builder.CreateExtractValue(MemPtr, I++); + if (hasVBPtrOffsetField(Inheritance)) + VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++); + if (hasVirtualBaseAdjustmentField(Inheritance)) + VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++); + } + + if (VirtualBaseAdjustmentOffset) { + Base = AdjustVirtualBase(CGF, RD, Base, VirtualBaseAdjustmentOffset, + VBPtrOffset); + } + llvm::Value *Addr = + Builder.CreateInBoundsGEP(Base, FieldOffset, "memptr.offset"); + + // Cast the address to the appropriate pointer type, adopting the address + // space of the base pointer. + return Builder.CreateBitCast(Addr, PType); +} + +llvm::Value * +MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, + llvm::Value *&This, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + assert(MPT->isMemberFunctionPointer()); + const FunctionProtoType *FPT = + MPT->getPointeeType()->castAs<FunctionProtoType>(); + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + llvm::FunctionType *FTy = + CGM.getTypes().GetFunctionType( + CGM.getTypes().arrangeCXXMethodType(RD, FPT)); + CGBuilderTy &Builder = CGF.Builder; + + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + + // Extract the fields we need, regardless of model. We'll apply them if we + // have them. + llvm::Value *FunctionPointer = MemPtr; + llvm::Value *NonVirtualBaseAdjustment = NULL; + llvm::Value *VirtualBaseAdjustmentOffset = NULL; + llvm::Value *VBPtrOffset = NULL; + if (MemPtr->getType()->isStructTy()) { + // We need to extract values. + unsigned I = 0; + FunctionPointer = Builder.CreateExtractValue(MemPtr, I++); + if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance)) + NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, I++); + if (hasVBPtrOffsetField(Inheritance)) + VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++); + if (hasVirtualBaseAdjustmentField(Inheritance)) + VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++); + } + + if (VirtualBaseAdjustmentOffset) { + This = AdjustVirtualBase(CGF, RD, This, VirtualBaseAdjustmentOffset, + VBPtrOffset); + } + + if (NonVirtualBaseAdjustment) { + // Apply the adjustment and cast back to the original struct type. + llvm::Value *Ptr = Builder.CreateBitCast(This, Builder.getInt8PtrTy()); + Ptr = Builder.CreateInBoundsGEP(Ptr, NonVirtualBaseAdjustment); + This = Builder.CreateBitCast(Ptr, This->getType(), "this.adjusted"); + } + + return Builder.CreateBitCast(FunctionPointer, FTy->getPointerTo()); +} + CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) { return new MicrosoftCXXABI(CGM); } diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp index d6e5f0673f..69e5b32304 100644 --- a/lib/CodeGen/ModuleBuilder.cpp +++ b/lib/CodeGen/ModuleBuilder.cpp @@ -31,15 +31,13 @@ namespace { OwningPtr<const llvm::DataLayout> TD; ASTContext *Ctx; const CodeGenOptions CodeGenOpts; // Intentionally copied in. - const TargetOptions TargetOpts; // Intentionally copied in. protected: OwningPtr<llvm::Module> M; OwningPtr<CodeGen::CodeGenModule> Builder; public: CodeGeneratorImpl(DiagnosticsEngine &diags, const std::string& ModuleName, - const CodeGenOptions &CGO, const TargetOptions &TO, - llvm::LLVMContext& C) - : Diags(diags), CodeGenOpts(CGO), TargetOpts(TO), + const CodeGenOptions &CGO, llvm::LLVMContext& C) + : Diags(diags), CodeGenOpts(CGO), M(new llvm::Module(ModuleName, C)) {} virtual ~CodeGeneratorImpl() {} @@ -58,8 +56,8 @@ namespace { M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple()); M->setDataLayout(Ctx->getTargetInfo().getTargetDescription()); TD.reset(new llvm::DataLayout(Ctx->getTargetInfo().getTargetDescription())); - Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts, TargetOpts, - *M, *TD, Diags)); + Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts, *M, *TD, + Diags)); } virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) { @@ -125,7 +123,7 @@ void CodeGenerator::anchor() { } CodeGenerator *clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags, const std::string& ModuleName, const CodeGenOptions &CGO, - const TargetOptions &TO, + const TargetOptions &/*TO*/, llvm::LLVMContext& C) { - return new CodeGeneratorImpl(Diags, ModuleName, CGO, TO, C); + return new CodeGeneratorImpl(Diags, ModuleName, CGO, C); } diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 612e72bdd7..f9689affa0 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -14,6 +14,7 @@ #include "TargetInfo.h" #include "ABIInfo.h" +#include "CGCXXABI.h" #include "CodeGenFunction.h" #include "clang/AST/RecordLayout.h" #include "clang/Frontend/CodeGenOptions.h" @@ -43,6 +44,37 @@ static bool isAggregateTypeForABI(QualType T) { ABIInfo::~ABIInfo() {} +static bool isRecordReturnIndirect(const RecordType *RT, CodeGen::CodeGenTypes &CGT) { + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD) + return false; + return CGT.CGM.getCXXABI().isReturnTypeIndirect(RD); +} + + +static bool isRecordReturnIndirect(QualType T, CodeGen::CodeGenTypes &CGT) { + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return false; + return isRecordReturnIndirect(RT, CGT); +} + +static CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT, + CodeGen::CodeGenTypes &CGT) { + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD) + return CGCXXABI::RAA_Default; + return CGT.CGM.getCXXABI().getRecordArgABI(RD); +} + +static CGCXXABI::RecordArgABI getRecordArgABI(QualType T, + CodeGen::CodeGenTypes &CGT) { + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return CGCXXABI::RAA_Default; + return getRecordArgABI(RT, CGT); +} + ASTContext &ABIInfo::getContext() const { return CGT.getContext(); } @@ -55,6 +87,9 @@ const llvm::DataLayout &ABIInfo::getDataLayout() const { return CGT.getDataLayout(); } +const TargetInfo &ABIInfo::getTarget() const { + return CGT.getTarget(); +} void ABIArgInfo::dump() const { raw_ostream &OS = llvm::errs(); @@ -167,27 +202,6 @@ static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) { return true; } -/// hasNonTrivialDestructorOrCopyConstructor - Determine if a type has either -/// a non-trivial destructor or a non-trivial copy constructor. -static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) { - const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); - if (!RD) - return false; - - return !RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor(); -} - -/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is -/// a record type with either a non-trivial destructor or a non-trivial copy -/// constructor. -static bool isRecordWithNonTrivialDestructorOrCopyConstructor(QualType T) { - const RecordType *RT = T->getAs<RecordType>(); - if (!RT) - return false; - - return hasNonTrivialDestructorOrCopyConstructor(RT); -} - /// isSingleElementStruct - Determine if a structure is a "single /// element struct", i.e. it has exactly one non-empty field or /// exactly one field which is itself a single element @@ -367,7 +381,7 @@ ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const { if (isAggregateTypeForABI(Ty)) { // Records with non trivial destructors/constructors should not be passed // by value. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) + if (isRecordReturnIndirect(Ty, CGT)) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); return ABIArgInfo::getIndirect(0); @@ -398,6 +412,9 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const { //===----------------------------------------------------------------------===// // le32/PNaCl bitcode ABI Implementation +// +// This is a simplified version of the x86_32 ABI. Arguments and return values +// are always passed on the stack. //===----------------------------------------------------------------------===// class PNaClABIInfo : public ABIInfo { @@ -405,7 +422,7 @@ class PNaClABIInfo : public ABIInfo { PNaClABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} ABIArgInfo classifyReturnType(QualType RetTy) const; - ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs) const; + ABIArgInfo classifyArgumentType(QualType RetTy) const; virtual void computeInfo(CGFunctionInfo &FI) const; virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -425,11 +442,9 @@ class PNaClTargetCodeGenInfo : public TargetCodeGenInfo { void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const { FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); - unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() : 0; - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) - it->info = classifyArgumentType(it->type, FreeRegs); + it->info = classifyArgumentType(it->type); } llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -437,42 +452,29 @@ llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, return 0; } -ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty, - unsigned &FreeRegs) const { +/// \brief Classify argument of given type \p Ty. +ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty) const { if (isAggregateTypeForABI(Ty)) { - // Records with non trivial destructors/constructors should not be passed - // by value. - FreeRegs = 0; - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); - + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); return ABIArgInfo::getIndirect(0); - } - - // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + } else if (const EnumType *EnumTy = Ty->getAs<EnumType>()) { + // Treat an enum type as its underlying type. Ty = EnumTy->getDecl()->getIntegerType(); + } else if (Ty->isFloatingType()) { + // Floating-point types don't go inreg. + return ABIArgInfo::getDirect(); + } - ABIArgInfo BaseInfo = (Ty->isPromotableIntegerType() ? + return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - - // Regparm regs hold 32 bits. - unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; - if (SizeInRegs == 0) return BaseInfo; - if (SizeInRegs > FreeRegs) { - FreeRegs = 0; - return BaseInfo; - } - FreeRegs -= SizeInRegs; - return BaseInfo.isDirect() ? - ABIArgInfo::getDirectInReg(BaseInfo.getCoerceToType()) : - ABIArgInfo::getExtendInReg(BaseInfo.getCoerceToType()); } ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); + // In the PNaCl ABI we always return records/structures on the stack. if (isAggregateTypeForABI(RetTy)) return ABIArgInfo::getIndirect(0); @@ -484,11 +486,9 @@ ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const { ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } -/// UseX86_MMXType - Return true if this is an MMX type that should use the -/// special x86_mmx type. -bool UseX86_MMXType(llvm::Type *IRType) { - // If the type is an MMX type <2 x i32>, <4 x i16>, or <8 x i8>, use the - // special x86_mmx type. +/// IsX86_MMXType - Return true if this is an MMX type. +bool IsX86_MMXType(llvm::Type *IRType) { + // Return true if the type is an MMX type <2 x i32>, <4 x i16>, or <8 x i8>. return IRType->isVectorTy() && IRType->getPrimitiveSizeInBits() == 64 && cast<llvm::VectorType>(IRType)->getElementType()->isIntegerTy() && IRType->getScalarSizeInBits() != 64; @@ -517,8 +517,7 @@ class X86_32ABIInfo : public ABIInfo { bool IsDarwinVectorABI; bool IsSmallStructInRegABI; - bool IsMMXDisabled; - bool IsWin32FloatStructABI; + bool IsWin32StructABI; unsigned DefaultNumRegisterParameters; static bool isRegisterSize(unsigned Size) { @@ -550,26 +549,24 @@ public: virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const; - X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool m, bool w, + X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool w, unsigned r) : ABIInfo(CGT), IsDarwinVectorABI(d), IsSmallStructInRegABI(p), - IsMMXDisabled(m), IsWin32FloatStructABI(w), - DefaultNumRegisterParameters(r) {} + IsWin32StructABI(w), DefaultNumRegisterParameters(r) {} }; class X86_32TargetCodeGenInfo : public TargetCodeGenInfo { public: X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, - bool d, bool p, bool m, bool w, unsigned r) - :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, m, w, r)) {} + bool d, bool p, bool w, unsigned r) + :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, w, r)) {} void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const; int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const { // Darwin uses different dwarf register numbers for EH. - if (CGM.isTargetDarwin()) return 5; - + if (CGM.getTarget().getTriple().isOSDarwin()) return 5; return 4; } @@ -681,9 +678,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, if (isAggregateTypeForABI(RetTy)) { if (const RecordType *RT = RetTy->getAs<RecordType>()) { - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (hasNonTrivialDestructorOrCopyConstructor(RT)) + if (isRecordReturnIndirect(RT, CGT)) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); // Structures with flexible arrays are always indirect. @@ -707,7 +702,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, // We apply a similar transformation for pointer types to improve the // quality of the generated IR. if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) - if ((!IsWin32FloatStructABI && SeltTy->isRealFloatingType()) + if ((!IsWin32StructABI && SeltTy->isRealFloatingType()) || SeltTy->hasPointerRepresentation()) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); @@ -864,13 +859,14 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, bool IsFastCall) const { // FIXME: Set alignment on indirect arguments. if (isAggregateTypeForABI(Ty)) { - // Structures with flexible arrays are always indirect. if (const RecordType *RT = Ty->getAs<RecordType>()) { - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (hasNonTrivialDestructorOrCopyConstructor(RT)) - return getIndirectResult(Ty, false, FreeRegs); + if (IsWin32StructABI) + return getIndirectResult(Ty, true, FreeRegs); + + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, CGT)) + return getIndirectResult(Ty, RAA == CGCXXABI::RAA_DirectInMemory, FreeRegs); + // Structures with flexible arrays are always indirect. if (RT->getDecl()->hasFlexibleArrayMember()) return getIndirectResult(Ty, true, FreeRegs); } @@ -914,15 +910,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, Size)); } - llvm::Type *IRType = CGT.ConvertType(Ty); - if (UseX86_MMXType(IRType)) { - if (IsMMXDisabled) - return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), - 64)); - ABIArgInfo AAI = ABIArgInfo::getDirect(IRType); - AAI.setCoerceToType(llvm::Type::getX86_MMXTy(getVMContext())); - return AAI; - } + if (IsX86_MMXType(CGT.ConvertType(Ty))) + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 64)); return ABIArgInfo::getDirect(); } @@ -1044,7 +1033,7 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable( // 8 is %eip. AssignToArrayRange(Builder, Address, Four8, 0, 8); - if (CGF.CGM.isTargetDarwin()) { + if (CGF.CGM.getTarget().getTriple().isOSDarwin()) { // 12-16 are st(0..4). Not sure why we stop at 4. // These have size 16, which is sizeof(long double) on // platforms with 8-byte alignment for that type. @@ -1169,7 +1158,7 @@ class X86_64ABIInfo : public ABIInfo { /// required strict binary compatibility with older versions of GCC /// may need to exempt themselves. bool honorsRevision0_98() const { - return !getContext().getTargetInfo().getTriple().isOSDarwin(); + return !getTarget().getTriple().isOSDarwin(); } bool HasAVX; @@ -1204,7 +1193,7 @@ public: /// WinX86_64ABIInfo - The Windows X86_64 ABI information. class WinX86_64ABIInfo : public ABIInfo { - ABIArgInfo classify(QualType Ty) const; + ABIArgInfo classify(QualType Ty, bool IsReturnType) const; public: WinX86_64ABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} @@ -1393,8 +1382,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Current = Integer; } else if ((k == BuiltinType::Float || k == BuiltinType::Double) || (k == BuiltinType::LongDouble && - getContext().getTargetInfo().getTriple().getOS() == - llvm::Triple::NaCl)) { + getTarget().getTriple().getOS() == llvm::Triple::NaCl)) { Current = SSE; } else if (k == BuiltinType::LongDouble) { Lo = X87; @@ -1482,8 +1470,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Current = SSE; else if (ET == getContext().DoubleTy || (ET == getContext().LongDoubleTy && - getContext().getTargetInfo().getTriple().getOS() == - llvm::Triple::NaCl)) + getTarget().getTriple().getOS() == llvm::Triple::NaCl)) Lo = Hi = SSE; else if (ET == getContext().LongDoubleTy) Current = ComplexX87; @@ -1552,7 +1539,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial // copy constructor or a non-trivial destructor, it is passed by invisible // reference. - if (hasNonTrivialDestructorOrCopyConstructor(RT)) + if (getRecordArgABI(RT, CGT)) return; const RecordDecl *RD = RT->getDecl(); @@ -1702,8 +1689,8 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); // Compute the byval alignment. We specify the alignment of the byval in all // cases so that the mid-level optimizer knows the alignment of the byval. @@ -2191,7 +2178,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType( // COMPLEX_X87, it is passed in memory. case X87: case ComplexX87: - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) + if (getRecordArgABI(Ty, CGT) == CGCXXABI::RAA_Indirect) ++neededInt; return getIndirectResult(Ty, freeIntRegs); @@ -2522,7 +2509,7 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, return ResAddr; } -ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty) const { +ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, bool IsReturnType) const { if (Ty->isVoidType()) return ABIArgInfo::getIgnore(); @@ -2533,14 +2520,19 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty) const { uint64_t Size = getContext().getTypeSize(Ty); if (const RecordType *RT = Ty->getAs<RecordType>()) { - if (hasNonTrivialDestructorOrCopyConstructor(RT) || - RT->getDecl()->hasFlexibleArrayMember()) + if (IsReturnType) { + if (isRecordReturnIndirect(RT, CGT)) + return ABIArgInfo::getIndirect(0, false); + } else { + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); + } + + if (RT->getDecl()->hasFlexibleArrayMember()) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); // FIXME: mingw-w64-gcc emits 128-bit struct as i128 - if (Size == 128 && - getContext().getTargetInfo().getTriple().getOS() - == llvm::Triple::MinGW32) + if (Size == 128 && getTarget().getTriple().getOS() == llvm::Triple::MinGW32) return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); @@ -2563,11 +2555,11 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty) const { void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const { QualType RetTy = FI.getReturnType(); - FI.getReturnInfo() = classify(RetTy); + FI.getReturnInfo() = classify(RetTy, true); for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) - it->info = classify(it->type); + it->info = classify(it->type, false); } llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -2794,10 +2786,8 @@ PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const { return ABIArgInfo::getDirect(); if (isAggregateTypeForABI(Ty)) { - // Records with non trivial destructors/constructors should not be passed - // by value. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); return ABIArgInfo::getIndirect(0); } @@ -2970,8 +2960,7 @@ public: } bool isEABI() const { - StringRef Env = - getContext().getTargetInfo().getTriple().getEnvironmentName(); + StringRef Env = getTarget().getTriple().getEnvironmentName(); return (Env == "gnueabi" || Env == "eabi" || Env == "android" || Env == "androideabi"); } @@ -3070,7 +3059,7 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { /// Return the default calling convention that LLVM will use. llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC() const { // The default calling convention that LLVM will infer. - if (getContext().getTargetInfo().getTriple().getEnvironmentName()=="gnueabihf") + if (getTarget().getTriple().getEnvironmentName()=="gnueabihf") return llvm::CallingConv::ARM_AAPCS_VFP; else if (isEABI()) return llvm::CallingConv::ARM_AAPCS; @@ -3262,10 +3251,8 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs, if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); if (getABIKind() == ARMABIInfo::AAPCS_VFP) { // Homogeneous Aggregates need to be expanded when we can fit the aggregate @@ -3428,7 +3415,7 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const { // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always indirect. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(RetTy)) + if (isRecordReturnIndirect(RetTy, CGT)) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); // Are we following APCS? @@ -3752,12 +3739,10 @@ ABIArgInfo AArch64ABIInfo::classifyGenericType(QualType Ty, return tryUseRegs(Ty, FreeIntRegs, RegsNeeded, /*IsInt=*/ true); } - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) { - if (FreeIntRegs > 0) + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) { + if (FreeIntRegs > 0 && RAA == CGCXXABI::RAA_Indirect) --FreeIntRegs; - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); } if (isEmptyRecord(getContext(), Ty, true)) { @@ -4032,7 +4017,7 @@ namespace { class NVPTXABIInfo : public ABIInfo { public: - NVPTXABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) { setRuntimeCC(); } + NVPTXABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty) const; @@ -4040,8 +4025,6 @@ public: virtual void computeInfo(CGFunctionInfo &FI) const; virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CFG) const; -private: - void setRuntimeCC(); }; class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo { @@ -4051,6 +4034,8 @@ public: virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const; +private: + static void addKernelMetadata(llvm::Function *F); }; ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const { @@ -4081,25 +4066,6 @@ void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const { FI.setEffectiveCallingConvention(getRuntimeCC()); } -void NVPTXABIInfo::setRuntimeCC() { - // Calling convention as default by an ABI. - // We're still using the PTX_Kernel/PTX_Device calling conventions here, - // but we should switch to NVVM metadata later on. - const LangOptions &LangOpts = getContext().getLangOpts(); - if (LangOpts.OpenCL || LangOpts.CUDA) { - // If we are in OpenCL or CUDA mode, then default to device functions - RuntimeCC = llvm::CallingConv::PTX_Device; - } else { - // If we are in standard C/C++ mode, use the triple to decide on the default - StringRef Env = - getContext().getTargetInfo().getTriple().getEnvironmentName(); - if (Env == "device") - RuntimeCC = llvm::CallingConv::PTX_Device; - else - RuntimeCC = llvm::CallingConv::PTX_Kernel; - } -} - llvm::Value *NVPTXABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CFG) const { llvm_unreachable("NVPTX does not support varargs"); @@ -4115,11 +4081,11 @@ SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, // Perform special handling in OpenCL mode if (M.getLangOpts().OpenCL) { - // Use OpenCL function attributes to set proper calling conventions + // Use OpenCL function attributes to check for kernel functions // By default, all functions are device functions if (FD->hasAttr<OpenCLKernelAttr>()) { - // OpenCL __kernel functions get a kernel calling convention - F->setCallingConv(llvm::CallingConv::PTX_Kernel); + // OpenCL __kernel functions get kernel metadata + addKernelMetadata(F); // And kernel functions are not subject to inlining F->addFnAttr(llvm::Attribute::NoInline); } @@ -4127,14 +4093,318 @@ SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, // Perform special handling in CUDA mode. if (M.getLangOpts().CUDA) { - // CUDA __global__ functions get a kernel calling convention. Since + // CUDA __global__ functions get a kernel metadata entry. Since // __global__ functions cannot be called from the device, we do not // need to set the noinline attribute. if (FD->getAttr<CUDAGlobalAttr>()) - F->setCallingConv(llvm::CallingConv::PTX_Kernel); + addKernelMetadata(F); } } +void NVPTXTargetCodeGenInfo::addKernelMetadata(llvm::Function *F) { + llvm::Module *M = F->getParent(); + llvm::LLVMContext &Ctx = M->getContext(); + + // Get "nvvm.annotations" metadata node + llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations"); + + // Create !{<func-ref>, metadata !"kernel", i32 1} node + llvm::SmallVector<llvm::Value *, 3> MDVals; + MDVals.push_back(F); + MDVals.push_back(llvm::MDString::get(Ctx, "kernel")); + MDVals.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), 1)); + + // Append metadata to nvvm.annotations + MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); +} + +} + +//===----------------------------------------------------------------------===// +// SystemZ ABI Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class SystemZABIInfo : public ABIInfo { +public: + SystemZABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} + + bool isPromotableIntegerType(QualType Ty) const; + bool isCompoundType(QualType Ty) const; + bool isFPArgumentType(QualType Ty) const; + + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType ArgTy) const; + + virtual void computeInfo(CGFunctionInfo &FI) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type); + } + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; + +class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { +public: + SystemZTargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(new SystemZABIInfo(CGT)) {} +}; + +} + +bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); + + // Promotable integer types are required to be promoted by the ABI. + if (Ty->isPromotableIntegerType()) + return true; + + // 32-bit values must also be promoted. + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) + switch (BT->getKind()) { + case BuiltinType::Int: + case BuiltinType::UInt: + return true; + default: + return false; + } + return false; +} + +bool SystemZABIInfo::isCompoundType(QualType Ty) const { + return Ty->isAnyComplexType() || isAggregateTypeForABI(Ty); +} + +bool SystemZABIInfo::isFPArgumentType(QualType Ty) const { + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) + switch (BT->getKind()) { + case BuiltinType::Float: + case BuiltinType::Double: + return true; + default: + return false; + } + + if (const RecordType *RT = Ty->getAsStructureType()) { + const RecordDecl *RD = RT->getDecl(); + bool Found = false; + + // If this is a C++ record, check the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) + for (CXXRecordDecl::base_class_const_iterator I = CXXRD->bases_begin(), + E = CXXRD->bases_end(); I != E; ++I) { + QualType Base = I->getType(); + + // Empty bases don't affect things either way. + if (isEmptyRecord(getContext(), Base, true)) + continue; + + if (Found) + return false; + Found = isFPArgumentType(Base); + if (!Found) + return false; + } + + // Check the fields. + for (RecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I) { + const FieldDecl *FD = *I; + + // Empty bitfields don't affect things either way. + // Unlike isSingleElementStruct(), empty structure and array fields + // do count. So do anonymous bitfields that aren't zero-sized. + if (FD->isBitField() && FD->getBitWidthValue(getContext()) == 0) + return true; + + // Unlike isSingleElementStruct(), arrays do not count. + // Nested isFPArgumentType structures still do though. + if (Found) + return false; + Found = isFPArgumentType(FD->getType()); + if (!Found) + return false; + } + + // Unlike isSingleElementStruct(), trailing padding is allowed. + // An 8-byte aligned struct s { float f; } is passed as a double. + return Found; + } + + return false; +} + +llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + // Assume that va_list type is correct; should be pointer to LLVM type: + // struct { + // i64 __gpr; + // i64 __fpr; + // i8 *__overflow_arg_area; + // i8 *__reg_save_area; + // }; + + // Every argument occupies 8 bytes and is passed by preference in either + // GPRs or FPRs. + Ty = CGF.getContext().getCanonicalType(Ty); + ABIArgInfo AI = classifyArgumentType(Ty); + bool InFPRs = isFPArgumentType(Ty); + + llvm::Type *APTy = llvm::PointerType::getUnqual(CGF.ConvertTypeForMem(Ty)); + bool IsIndirect = AI.isIndirect(); + unsigned UnpaddedBitSize; + if (IsIndirect) { + APTy = llvm::PointerType::getUnqual(APTy); + UnpaddedBitSize = 64; + } else + UnpaddedBitSize = getContext().getTypeSize(Ty); + unsigned PaddedBitSize = 64; + assert((UnpaddedBitSize <= PaddedBitSize) && "Invalid argument size."); + + unsigned PaddedSize = PaddedBitSize / 8; + unsigned Padding = (PaddedBitSize - UnpaddedBitSize) / 8; + + unsigned MaxRegs, RegCountField, RegSaveIndex, RegPadding; + if (InFPRs) { + MaxRegs = 4; // Maximum of 4 FPR arguments + RegCountField = 1; // __fpr + RegSaveIndex = 16; // save offset for f0 + RegPadding = 0; // floats are passed in the high bits of an FPR + } else { + MaxRegs = 5; // Maximum of 5 GPR arguments + RegCountField = 0; // __gpr + RegSaveIndex = 2; // save offset for r2 + RegPadding = Padding; // values are passed in the low bits of a GPR + } + + llvm::Value *RegCountPtr = + CGF.Builder.CreateStructGEP(VAListAddr, RegCountField, "reg_count_ptr"); + llvm::Value *RegCount = CGF.Builder.CreateLoad(RegCountPtr, "reg_count"); + llvm::Type *IndexTy = RegCount->getType(); + llvm::Value *MaxRegsV = llvm::ConstantInt::get(IndexTy, MaxRegs); + llvm::Value *InRegs = CGF.Builder.CreateICmpULT(RegCount, MaxRegsV, + "fits_in_regs"); + + llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); + llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem"); + llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); + CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock); + + // Emit code to load the value if it was passed in registers. + CGF.EmitBlock(InRegBlock); + + // Work out the address of an argument register. + llvm::Value *PaddedSizeV = llvm::ConstantInt::get(IndexTy, PaddedSize); + llvm::Value *ScaledRegCount = + CGF.Builder.CreateMul(RegCount, PaddedSizeV, "scaled_reg_count"); + llvm::Value *RegBase = + llvm::ConstantInt::get(IndexTy, RegSaveIndex * PaddedSize + RegPadding); + llvm::Value *RegOffset = + CGF.Builder.CreateAdd(ScaledRegCount, RegBase, "reg_offset"); + llvm::Value *RegSaveAreaPtr = + CGF.Builder.CreateStructGEP(VAListAddr, 3, "reg_save_area_ptr"); + llvm::Value *RegSaveArea = + CGF.Builder.CreateLoad(RegSaveAreaPtr, "reg_save_area"); + llvm::Value *RawRegAddr = + CGF.Builder.CreateGEP(RegSaveArea, RegOffset, "raw_reg_addr"); + llvm::Value *RegAddr = + CGF.Builder.CreateBitCast(RawRegAddr, APTy, "reg_addr"); + + // Update the register count + llvm::Value *One = llvm::ConstantInt::get(IndexTy, 1); + llvm::Value *NewRegCount = + CGF.Builder.CreateAdd(RegCount, One, "reg_count"); + CGF.Builder.CreateStore(NewRegCount, RegCountPtr); + CGF.EmitBranch(ContBlock); + + // Emit code to load the value if it was passed in memory. + CGF.EmitBlock(InMemBlock); + + // Work out the address of a stack argument. + llvm::Value *OverflowArgAreaPtr = + CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_ptr"); + llvm::Value *OverflowArgArea = + CGF.Builder.CreateLoad(OverflowArgAreaPtr, "overflow_arg_area"); + llvm::Value *PaddingV = llvm::ConstantInt::get(IndexTy, Padding); + llvm::Value *RawMemAddr = + CGF.Builder.CreateGEP(OverflowArgArea, PaddingV, "raw_mem_addr"); + llvm::Value *MemAddr = + CGF.Builder.CreateBitCast(RawMemAddr, APTy, "mem_addr"); + + // Update overflow_arg_area_ptr pointer + llvm::Value *NewOverflowArgArea = + CGF.Builder.CreateGEP(OverflowArgArea, PaddedSizeV, "overflow_arg_area"); + CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr); + CGF.EmitBranch(ContBlock); + + // Return the appropriate result. + CGF.EmitBlock(ContBlock); + llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(APTy, 2, "va_arg.addr"); + ResAddr->addIncoming(RegAddr, InRegBlock); + ResAddr->addIncoming(MemAddr, InMemBlock); + + if (IsIndirect) + return CGF.Builder.CreateLoad(ResAddr, "indirect_arg"); + + return ResAddr; +} + + +ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) + return ABIArgInfo::getIgnore(); + if (isCompoundType(RetTy) || getContext().getTypeSize(RetTy) > 64) + return ABIArgInfo::getIndirect(0); + return (isPromotableIntegerType(RetTy) ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); +} + +ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const { + // Handle the generic C++ ABI. + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); + + // Integers and enums are extended to full register width. + if (isPromotableIntegerType(Ty)) + return ABIArgInfo::getExtend(); + + // Values that are not 1, 2, 4 or 8 bytes in size are passed indirectly. + uint64_t Size = getContext().getTypeSize(Ty); + if (Size != 8 && Size != 16 && Size != 32 && Size != 64) + return ABIArgInfo::getIndirect(0); + + // Handle small structures. + if (const RecordType *RT = Ty->getAs<RecordType>()) { + // Structures with flexible arrays have variable length, so really + // fail the size test above. + const RecordDecl *RD = RT->getDecl(); + if (RD->hasFlexibleArrayMember()) + return ABIArgInfo::getIndirect(0); + + // The structure is passed as an unextended integer, a float, or a double. + llvm::Type *PassTy; + if (isFPArgumentType(Ty)) { + assert(Size == 32 || Size == 64); + if (Size == 32) + PassTy = llvm::Type::getFloatTy(getVMContext()); + else + PassTy = llvm::Type::getDoubleTy(getVMContext()); + } else + PassTy = llvm::IntegerType::get(getVMContext(), Size); + return ABIArgInfo::getDirect(PassTy); + } + + // Non-structure compounds are passed indirectly. + if (isCompoundType(Ty)) + return ABIArgInfo::getIndirect(0); + + return ABIArgInfo::getDirect(0); } //===----------------------------------------------------------------------===// @@ -4325,11 +4595,17 @@ public: void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { - // - // can fill this in when new attribute work in llvm is done. - // attributes mips16 and nomips16 need to be handled here. - // + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (!FD) return; + llvm::Function *Fn = cast<llvm::Function>(GV); + if (FD->hasAttr<Mips16Attr>()) { + Fn->addFnAttr("mips16"); + } + else if (FD->hasAttr<NoMips16Attr>()) { + Fn->addFnAttr("nomips16"); + } } + bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const; @@ -4438,11 +4714,9 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { if (TySize == 0) return ABIArgInfo::getIgnore(); - // Records with non trivial destructors/constructors should not be passed - // by value. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) { + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) { Offset = OrigOffset + MinABIStackAlignInBytes; - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); } // If we have reached here, aggregates are passed directly by coercing to @@ -4512,6 +4786,9 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { return ABIArgInfo::getIgnore(); if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) { + if (isRecordReturnIndirect(RetTy, CGT)) + return ABIArgInfo::getIndirect(0); + if (Size <= 128) { if (RetTy->isAnyComplexType()) return ABIArgInfo::getDirect(); @@ -4520,7 +4797,7 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { if (IsO32 && RetTy->isVectorType() && !RetTy->hasFloatingRepresentation()) return ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size)); - if (!IsO32 && !isRecordWithNonTrivialDestructorOrCopyConstructor(RetTy)) + if (!IsO32) return ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size)); } @@ -4558,7 +4835,7 @@ llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, int64_t TypeAlign = getContext().getTypeAlign(Ty) / 8; llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); llvm::Value *AddrTyped; - unsigned PtrWidth = getContext().getTargetInfo().getPointerWidth(0); + unsigned PtrWidth = getTarget().getPointerWidth(0); llvm::IntegerType *IntTy = (PtrWidth == 32) ? CGF.Int32Ty : CGF.Int64Ty; if (TypeAlign > MinABIStackAlignInBytes) { @@ -4730,10 +5007,8 @@ ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty) const { if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); uint64_t Size = getContext().getTypeSize(Ty); if (Size > 64) @@ -4768,7 +5043,7 @@ ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const { // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always indirect. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(RetTy)) + if (isRecordReturnIndirect(RetTy, CGT)) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); if (isEmptyRecord(getContext(), RetTy, true)) @@ -4819,7 +5094,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { if (TheTargetCodeGenInfo) return *TheTargetCodeGenInfo; - const llvm::Triple &Triple = getContext().getTargetInfo().getTriple(); + const llvm::Triple &Triple = getTarget().getTriple(); switch (Triple.getArch()) { default: return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types)); @@ -4841,10 +5116,11 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { case llvm::Triple::thumb: { ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS; - if (strcmp(getContext().getTargetInfo().getABI(), "apcs-gnu") == 0) + if (strcmp(getTarget().getABI(), "apcs-gnu") == 0) Kind = ARMABIInfo::APCS; else if (CodeGenOpts.FloatABI == "hard" || - (CodeGenOpts.FloatABI != "soft" && Triple.getEnvironment()==llvm::Triple::GNUEABIHF)) + (CodeGenOpts.FloatABI != "soft" && + Triple.getEnvironment() == llvm::Triple::GNUEABIHF)) Kind = ARMABIInfo::AAPCS_VFP; switch (Triple.getOS()) { @@ -4875,15 +5151,16 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { case llvm::Triple::msp430: return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo(Types)); + case llvm::Triple::systemz: + return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo(Types)); + case llvm::Triple::tce: return *(TheTargetCodeGenInfo = new TCETargetCodeGenInfo(Types)); case llvm::Triple::x86: { - bool DisableMMX = strcmp(getContext().getTargetInfo().getABI(), "no-mmx") == 0; - if (Triple.isOSDarwin()) return *(TheTargetCodeGenInfo = - new X86_32TargetCodeGenInfo(Types, true, true, DisableMMX, false, + new X86_32TargetCodeGenInfo(Types, true, true, false, CodeGenOpts.NumRegisterParameters)); switch (Triple.getOS()) { @@ -4895,25 +5172,23 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { case llvm::Triple::OpenBSD: case llvm::Triple::Bitrig: return *(TheTargetCodeGenInfo = - new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX, - false, + new X86_32TargetCodeGenInfo(Types, false, true, false, CodeGenOpts.NumRegisterParameters)); case llvm::Triple::Win32: return *(TheTargetCodeGenInfo = - new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX, true, + new X86_32TargetCodeGenInfo(Types, false, true, true, CodeGenOpts.NumRegisterParameters)); default: return *(TheTargetCodeGenInfo = - new X86_32TargetCodeGenInfo(Types, false, false, DisableMMX, - false, + new X86_32TargetCodeGenInfo(Types, false, false, false, CodeGenOpts.NumRegisterParameters)); } } case llvm::Triple::x86_64: { - bool HasAVX = strcmp(getContext().getTargetInfo().getABI(), "avx") == 0; + bool HasAVX = strcmp(getTarget().getABI(), "avx") == 0; switch (Triple.getOS()) { case llvm::Triple::Win32: @@ -4921,7 +5196,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { case llvm::Triple::Cygwin: return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types)); case llvm::Triple::NaCl: - return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types, HasAVX)); + return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types, + HasAVX)); default: return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types, HasAVX)); diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp index 6c57b622b8..4b8d151d19 100644 --- a/lib/Driver/ArgList.cpp +++ b/lib/Driver/ArgList.cpp @@ -206,6 +206,13 @@ bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const { return Default; } +bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier PosAlias, OptSpecifier Neg, + bool Default) const { + if (Arg *A = getLastArg(Pos, PosAlias, Neg)) + return A->getOption().matches(Pos) || A->getOption().matches(PosAlias); + return Default; +} + StringRef ArgList::getLastArgValue(OptSpecifier Id, StringRef Default) const { if (Arg *A = getLastArg(Id)) @@ -241,6 +248,14 @@ void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id) const { } } +void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id0, + OptSpecifier Id1) const { + if (Arg *A = getLastArg(Id0, Id1)) { + A->claim(); + A->render(*this, Output); + } +} + void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const { for (arg_iterator it = filtered_begin(Id0, Id1, Id2), diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index db948a5bfe..1bff4a3d7a 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -290,11 +290,12 @@ int Compilation::ExecuteCommand(const Command &C, } std::string Error; + bool ExecutionFailed; int Res = llvm::sys::Program::ExecuteAndWait(Prog, Argv, /*env*/0, Redirects, /*secondsToWait*/0, /*memoryLimit*/0, - &Error); + &Error, &ExecutionFailed); if (!Error.empty()) { assert(Res && "Error string set with 0 result code!"); getDriver().Diag(clang::diag::err_drv_command_failure) << Error; @@ -304,7 +305,7 @@ int Compilation::ExecuteCommand(const Command &C, FailingCommand = &C; delete[] Argv; - return Res; + return ExecutionFailed ? 1 : Res; } typedef SmallVectorImpl< std::pair<int, const Command *> > FailingCommandList; diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 652046fce4..1dbbc9a342 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -126,6 +126,7 @@ const { // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) || + (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) || (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) || (PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) || (PhaseArg = DAL.getLastArg(options::OPT__migrate)) || @@ -291,6 +292,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { if (Args->hasArg(options::OPT_nostdlib)) UseStdLib = false; + if (const Arg *A = Args->getLastArg(options::OPT_resource_dir)) + ResourceDir = A->getValue(); + // Perform the default argument translations. DerivedArgList *TranslatedArgs = TranslateInputArgs(*Args); @@ -487,9 +491,8 @@ void Driver::generateCompilationDiagnostics(Compilation &C, << "\n\n********************"; } else { // Failure, remove preprocessed files. - if (!C.getArgs().hasArg(options::OPT_save_temps)) { + if (!C.getArgs().hasArg(options::OPT_save_temps)) C.CleanupFileList(C.getTempFiles(), true); - } Diag(clang::diag::note_drv_command_failed_diag_msg) << "Error generating preprocessed source(s)."; @@ -821,17 +824,6 @@ void Driver::BuildUniversalActions(const ToolChain &TC, if (!Archs.size()) Archs.push_back(Args.MakeArgString(TC.getDefaultUniversalArchName())); - // FIXME: We killed off some others but these aren't yet detected in a - // functional manner. If we added information to jobs about which "auxiliary" - // files they wrote then we could detect the conflict these cause downstream. - if (Archs.size() > 1) { - // No recovery needed, the point of this is just to prevent - // overwriting the same files. - if (const Arg *A = Args.getLastArg(options::OPT_save_temps)) - Diag(clang::diag::err_drv_invalid_opt_with_multiple_archs) - << A->getAsString(Args); - } - ActionList SingleActions; BuildActions(TC, Args, BAInputs, SingleActions); @@ -1167,6 +1159,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, return new MigrateJobAction(Input, types::TY_Remap); } else if (Args.hasArg(options::OPT_emit_ast)) { return new CompileJobAction(Input, types::TY_AST); + } else if (Args.hasArg(options::OPT_module_file_info)) { + return new CompileJobAction(Input, types::TY_ModuleFile); } else if (IsUsingLTO(Args)) { types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; @@ -1215,6 +1209,17 @@ void Driver::BuildJobs(Compilation &C) const { } } + // Collect the list of architectures. + llvm::StringSet<> ArchNames; + if (C.getDefaultToolChain().getTriple().isOSDarwin()) { + for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end(); + it != ie; ++it) { + Arg *A = *it; + if (A->getOption().matches(options::OPT_arch)) + ArchNames.insert(A->getValue()); + } + } + for (ActionList::const_iterator it = C.getActions().begin(), ie = C.getActions().end(); it != ie; ++it) { Action *A = *it; @@ -1237,6 +1242,7 @@ void Driver::BuildJobs(Compilation &C) const { BuildJobsForAction(C, A, &C.getDefaultToolChain(), /*BoundArch*/0, /*AtTopLevel*/ true, + /*MultipleArchs*/ ArchNames.size() > 1, /*LinkingOutput*/ LinkingOutput, II); } @@ -1285,7 +1291,7 @@ void Driver::BuildJobs(Compilation &C) const { } } -static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC, +static const Tool *SelectToolForJob(Compilation &C, const ToolChain *TC, const JobAction *JA, const ActionList *&Inputs) { const Tool *ToolForJob = 0; @@ -1294,23 +1300,23 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC, // bottom up, so what we are actually looking for is an assembler job with a // compiler input. - if (C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - TC->IsIntegratedAssemblerDefault()) && + if (TC->useIntegratedAs() && !C.getArgs().hasArg(options::OPT_save_temps) && isa<AssembleJobAction>(JA) && Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) { - const Tool &Compiler = TC->SelectTool( - C, cast<JobAction>(**Inputs->begin()), (*Inputs)[0]->getInputs()); - if (Compiler.hasIntegratedAssembler()) { + const Tool *Compiler = + TC->SelectTool(cast<JobAction>(**Inputs->begin())); + if (!Compiler) + return NULL; + if (Compiler->hasIntegratedAssembler()) { Inputs = &(*Inputs)[0]->getInputs(); - ToolForJob = &Compiler; + ToolForJob = Compiler; } } // Otherwise use the tool for the current job. if (!ToolForJob) - ToolForJob = &TC->SelectTool(C, *JA, *Inputs); + ToolForJob = TC->SelectTool(*JA); // 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 @@ -1323,7 +1329,7 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC, ToolForJob->hasIntegratedCPP()) Inputs = &(*Inputs)[0]->getInputs(); - return *ToolForJob; + return ToolForJob; } void Driver::BuildJobsForAction(Compilation &C, @@ -1331,6 +1337,7 @@ void Driver::BuildJobsForAction(Compilation &C, const ToolChain *TC, const char *BoundArch, bool AtTopLevel, + bool MultipleArchs, const char *LinkingOutput, InputInfo &Result) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); @@ -1358,14 +1365,16 @@ void Driver::BuildJobsForAction(Compilation &C, TC = &C.getDefaultToolChain(); BuildJobsForAction(C, *BAA->begin(), TC, BAA->getArchName(), - AtTopLevel, LinkingOutput, Result); + AtTopLevel, MultipleArchs, LinkingOutput, Result); return; } const ActionList *Inputs = &A->getInputs(); const JobAction *JA = cast<JobAction>(A); - const Tool &T = SelectToolForJob(C, TC, JA, Inputs); + const Tool *T = SelectToolForJob(C, TC, JA, Inputs); + if (!T) + return; // Only use pipes when there is exactly one input. InputInfoList InputInfos; @@ -1379,8 +1388,8 @@ void Driver::BuildJobsForAction(Compilation &C, SubJobAtTopLevel = true; InputInfo II; - BuildJobsForAction(C, *it, TC, BoundArch, - SubJobAtTopLevel, LinkingOutput, II); + BuildJobsForAction(C, *it, TC, BoundArch, SubJobAtTopLevel, MultipleArchs, + LinkingOutput, II); InputInfos.push_back(II); } @@ -1396,12 +1405,13 @@ void Driver::BuildJobsForAction(Compilation &C, if (JA->getType() == types::TY_Nothing) Result = InputInfo(A->getType(), BaseInput); else - Result = InputInfo(GetNamedOutputPath(C, *JA, BaseInput, AtTopLevel), + Result = InputInfo(GetNamedOutputPath(C, *JA, BaseInput, BoundArch, + AtTopLevel, MultipleArchs), A->getType(), BaseInput); if (CCCPrintBindings && !CCGenDiagnostics) { - llvm::errs() << "# \"" << T.getToolChain().getTripleString() << '"' - << " - \"" << T.getName() << "\", inputs: ["; + llvm::errs() << "# \"" << T->getToolChain().getTripleString() << '"' + << " - \"" << T->getName() << "\", inputs: ["; for (unsigned i = 0, e = InputInfos.size(); i != e; ++i) { llvm::errs() << InputInfos[i].getAsString(); if (i + 1 != e) @@ -1409,15 +1419,17 @@ void Driver::BuildJobsForAction(Compilation &C, } llvm::errs() << "], output: " << Result.getAsString() << "\n"; } else { - T.ConstructJob(C, *JA, Result, InputInfos, - C.getArgsForToolChain(TC, BoundArch), LinkingOutput); + T->ConstructJob(C, *JA, Result, InputInfos, + C.getArgsForToolChain(TC, BoundArch), LinkingOutput); } } const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, const char *BaseInput, - bool AtTopLevel) const { + const char *BoundArch, + bool AtTopLevel, + bool MultipleArchs) const { llvm::PrettyStackTraceString CrashInfo("Computing output path"); // Output to a user requested destination? if (AtTopLevel && !isa<DsymutilJobAction>(JA) && @@ -1427,7 +1439,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, } // Default to writing to stdout? - if (AtTopLevel && isa<PreprocessJobAction>(JA) && !CCGenDiagnostics) + if (AtTopLevel && !CCGenDiagnostics && + (isa<PreprocessJobAction>(JA) || JA.getType() == types::TY_ModuleFile)) return "-"; // Output to a temporary file? @@ -1451,8 +1464,14 @@ const char *Driver::GetNamedOutputPath(Compilation &C, // Determine what the derived output name should be. const char *NamedOutput; - if (JA.getType() == types::TY_Image) { - NamedOutput = DefaultImageName.c_str(); + if (JA.getType() == types::TY_Image) { + if (MultipleArchs && BoundArch) { + SmallString<128> Output(DefaultImageName.c_str()); + Output += "-"; + Output.append(BoundArch); + NamedOutput = C.getArgs().MakeArgString(Output.c_str()); + } else + NamedOutput = DefaultImageName.c_str(); } else { const char *Suffix = types::getTypeTempSuffix(JA.getType()); assert(Suffix && "All types used for output should have a suffix."); @@ -1460,7 +1479,11 @@ const char *Driver::GetNamedOutputPath(Compilation &C, std::string::size_type End = std::string::npos; if (!types::appendSuffixForType(JA.getType())) End = BaseName.rfind('.'); - std::string Suffixed(BaseName.substr(0, End)); + SmallString<128> Suffixed(BaseName.substr(0, End)); + if (MultipleArchs && BoundArch) { + Suffixed += "-"; + Suffixed.append(BoundArch); + } Suffixed += '.'; Suffixed += Suffix; NamedOutput = C.getArgs().MakeArgString(Suffixed.c_str()); @@ -1644,6 +1667,21 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, } } + // Handle pseudo-target flags '-EL' and '-EB'. + if (Arg *A = Args.getLastArg(options::OPT_EL, options::OPT_EB)) { + if (A->getOption().matches(options::OPT_EL)) { + if (Target.getArch() == llvm::Triple::mips) + Target.setArch(llvm::Triple::mipsel); + else if (Target.getArch() == llvm::Triple::mips64) + Target.setArch(llvm::Triple::mips64el); + } else { + if (Target.getArch() == llvm::Triple::mipsel) + Target.setArch(llvm::Triple::mips); + else if (Target.getArch() == llvm::Triple::mips64el) + Target.setArch(llvm::Triple::mips64); + } + } + // Skip further flag support on OSes which don't support '-m32' or '-m64'. if (Target.getArchName() == "tce" || Target.getOS() == llvm::Triple::AuroraUX || @@ -1687,7 +1725,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, Target.getArch() == llvm::Triple::x86_64 || Target.getArch() == llvm::Triple::arm || Target.getArch() == llvm::Triple::thumb) - TC = new toolchains::DarwinClang(*this, Target); + TC = new toolchains::DarwinClang(*this, Target, Args); else TC = new toolchains::Darwin_Generic_GCC(*this, Target, Args); break; @@ -1719,17 +1757,21 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = new toolchains::Solaris(*this, Target, Args); break; case llvm::Triple::Win32: - TC = new toolchains::Windows(*this, Target); + TC = new toolchains::Windows(*this, Target, Args); break; case llvm::Triple::MinGW32: // FIXME: We need a MinGW toolchain. Fallthrough for now. default: // TCE is an OSless target if (Target.getArchName() == "tce") { - TC = new toolchains::TCEToolChain(*this, Target); + TC = new toolchains::TCEToolChain(*this, Target, Args); + break; + } + // If Hexagon is configured as an OSless target + if (Target.getArch() == llvm::Triple::hexagon) { + TC = new toolchains::Hexagon_TC(*this, Target, Args); break; } - TC = new toolchains::Generic_GCC(*this, Target, Args); break; } @@ -1737,8 +1779,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, return *TC; } -bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, - const llvm::Triple &Triple) const { +bool Driver::ShouldUseClangCompiler(const JobAction &JA) const { // Check if user requested no clang, or clang doesn't understand this type (we // only handle single inputs for now). if (JA.size() != 1 || diff --git a/lib/Driver/SanitizerArgs.h b/lib/Driver/SanitizerArgs.h index c3d84f9a4f..326d80db72 100644 --- a/lib/Driver/SanitizerArgs.h +++ b/lib/Driver/SanitizerArgs.h @@ -38,7 +38,8 @@ class SanitizerArgs { NeedsTsanRt = Thread, NeedsMsanRt = Memory, NeedsUbsanRt = Undefined | Integer, - NotAllowedWithTrap = Vptr + NotAllowedWithTrap = Vptr, + HasZeroBaseShadow = Thread | Memory }; unsigned Kind; std::string BlacklistFile; @@ -50,7 +51,7 @@ class SanitizerArgs { SanitizerArgs() : Kind(0), BlacklistFile(""), MsanTrackOrigins(false), AsanZeroBaseShadow(false), UbsanTrapOnError(false) {} /// Parses the sanitizer arguments from an argument list. - SanitizerArgs(const Driver &D, const ArgList &Args); + SanitizerArgs(const ToolChain &TC, const ArgList &Args); bool needsAsanRt() const { return Kind & NeedsAsanRt; } bool needsTsanRt() const { return Kind & NeedsTsanRt; } @@ -63,6 +64,9 @@ class SanitizerArgs { bool sanitizesVptr() const { return Kind & Vptr; } bool notAllowedWithTrap() const { return Kind & NotAllowedWithTrap; } + bool hasZeroBaseShadow() const { + return (Kind & HasZeroBaseShadow) || AsanZeroBaseShadow; + } void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!Kind) @@ -90,14 +94,20 @@ class SanitizerArgs { private: /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. - /// Returns a member of the \c SanitizeKind enumeration, or \c 0 if \p Value - /// is not known. + /// Returns OR of members of the \c SanitizeKind enumeration, or \c 0 + /// if \p Value is not known. static unsigned parse(const char *Value) { - return llvm::StringSwitch<SanitizeKind>(Value) + unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value) #define SANITIZER(NAME, ID) .Case(NAME, ID) #define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID) #include "clang/Basic/Sanitizers.def" .Default(SanitizeKind()); + // Assume -fsanitize=address implies -fsanitize=init-order. + // FIXME: This should be either specified in Sanitizers.def, or go away when + // we get rid of "-fsanitize=init-order" flag at all. + if (ParsedKind & Address) + ParsedKind |= InitOrder; + return ParsedKind; } /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 21015a6c84..71f53933e2 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "Tools.h" #include "clang/Driver/ToolChain.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Driver/Action.h" @@ -18,11 +19,13 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" using namespace clang::driver; using namespace clang; -ToolChain::ToolChain(const Driver &D, const llvm::Triple &T) - : D(D), Triple(T) { +ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, + const ArgList &A) + : D(D), Triple(T), Args(A) { } ToolChain::~ToolChain() { @@ -32,6 +35,12 @@ const Driver &ToolChain::getDriver() const { return D; } +bool ToolChain::useIntegratedAs() const { + return Args.hasFlag(options::OPT_integrated_as, + options::OPT_no_integrated_as, + IsIntegratedAssemblerDefault()); +} + std::string ToolChain::getDefaultUniversalArchName() const { // In universal driver terms, the arch name accepted by -arch isn't exactly // the same as the ones that appear in the triple. Roughly speaking, this is @@ -51,6 +60,73 @@ bool ToolChain::IsUnwindTablesDefault() const { return false; } +Tool *ToolChain::getClang() const { + if (!Clang) + Clang.reset(new tools::Clang(*this)); + return Clang.get(); +} + +Tool *ToolChain::buildAssembler() const { + return new tools::ClangAs(*this); +} + +Tool *ToolChain::buildLinker() const { + llvm_unreachable("Linking is not supported by this toolchain"); +} + +Tool *ToolChain::getAssemble() const { + if (!Assemble) + Assemble.reset(buildAssembler()); + return Assemble.get(); +} + +Tool *ToolChain::getClangAs() const { + if (!Assemble) + Assemble.reset(new tools::ClangAs(*this)); + return Assemble.get(); +} + +Tool *ToolChain::getLink() const { + if (!Link) + Link.reset(buildLinker()); + return Link.get(); +} + +Tool *ToolChain::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::AssembleJobClass: + return getAssemble(); + + case Action::LinkJobClass: + return getLink(); + + case Action::InputClass: + case Action::BindArchClass: + case Action::LipoJobClass: + case Action::DsymutilJobClass: + case Action::VerifyJobClass: + llvm_unreachable("Invalid tool kind."); + + case Action::CompileJobClass: + case Action::PrecompileJobClass: + case Action::PreprocessJobClass: + case Action::AnalyzeJobClass: + case Action::MigrateJobClass: + return getClang(); + } + + llvm_unreachable("Invalid tool kind."); +} + +Tool *ToolChain::SelectTool(const JobAction &JA) const { + if (getDriver().ShouldUseClangCompiler(JA)) + return getClang(); + Action::ActionClass AC = JA.getKind(); + if (AC == Action::AssembleJobClass && useIntegratedAs()) + return getClangAs(); + return getTool(AC); +} + std::string ToolChain::GetFilePath(const char *Name) const { return D.GetFilePath(Name, *this); @@ -258,6 +334,13 @@ ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{ CC1Args.push_back(DriverArgs.MakeArgString(Path)); } +void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs, + ArgStringList &CC1Args, + const Twine &Path) { + if (llvm::sys::fs::exists(Path)) + addExternCSystemInclude(DriverArgs, CC1Args, Path); +} + /// \brief Utility function to add a list of system include directories to CC1. /*static*/ void ToolChain::addSystemIncludes(const ArgList &DriverArgs, ArgStringList &CC1Args, diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 035af21975..fffba0e4e5 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -42,8 +42,8 @@ using namespace clang; /// Darwin - Darwin tool chain for i386 and x86_64. -Darwin::Darwin(const Driver &D, const llvm::Triple& Triple) - : ToolChain(D, Triple), TargetInitialized(false) +Darwin::Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) + : ToolChain(D, Triple, Args), TargetInitialized(false) { // Compute the initial Darwin version from the triple unsigned Major, Minor, Micro; @@ -151,10 +151,6 @@ StringRef Darwin::getDarwinArchName(const ArgList &Args) const { } Darwin::~Darwin() { - // Free tool implementations. - for (llvm::DenseMap<unsigned, Tool*>::iterator - it = Tools.begin(), ie = Tools.end(); it != ie; ++it) - delete it->second; } std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, @@ -176,55 +172,36 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, void Generic_ELF::anchor() {} -Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key = JA.getKind(); - - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) { - // FIXME: This seems like a hacky way to choose clang frontend. - Key = Action::AnalyzeJobClass; - } - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::InputClass: - case Action::BindArchClass: - llvm_unreachable("Invalid tool kind."); - case Action::PreprocessJobClass: - case Action::AnalyzeJobClass: - case Action::MigrateJobClass: - case Action::PrecompileJobClass: - case Action::CompileJobClass: - T = new tools::Clang(*this); break; - case Action::AssembleJobClass: { - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::darwin::Assemble(*this); - break; - } - case Action::LinkJobClass: - T = new tools::darwin::Link(*this); break; - case Action::LipoJobClass: - T = new tools::darwin::Lipo(*this); break; - case Action::DsymutilJobClass: - T = new tools::darwin::Dsymutil(*this); break; - case Action::VerifyJobClass: - T = new tools::darwin::VerifyDebug(*this); break; - } +Tool *Darwin::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::LipoJobClass: + if (!Lipo) + Lipo.reset(new tools::darwin::Lipo(*this)); + return Lipo.get(); + case Action::DsymutilJobClass: + if (!Dsymutil) + Dsymutil.reset(new tools::darwin::Dsymutil(*this)); + return Dsymutil.get(); + case Action::VerifyJobClass: + if (!VerifyDebug) + VerifyDebug.reset(new tools::darwin::VerifyDebug(*this)); + return VerifyDebug.get(); + default: + return ToolChain::getTool(AC); } +} - return *T; +Tool *Darwin::buildLinker() const { + return new tools::darwin::Link(*this); } +Tool *Darwin::buildAssembler() const { + return new tools::darwin::Assemble(*this); +} -DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple) - : Darwin(D, Triple) +DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple, + const ArgList &Args) + : Darwin(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) @@ -317,7 +294,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } } - SanitizerArgs Sanitize(getDriver(), Args); + SanitizerArgs Sanitize(*this, Args); // Add Ubsan runtime library, if required. if (Sanitize.needsUbsanRt()) { @@ -335,17 +312,19 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, // Add ASAN runtime library, if required. Dynamic libraries and bundles // should not be linked with the runtime library. if (Sanitize.needsAsanRt()) { - if (Args.hasArg(options::OPT_dynamiclib) || - Args.hasArg(options::OPT_bundle)) { - // Assume the binary will provide the ASan runtime. - } else if (isTargetIPhoneOS()) { + if (isTargetIPhoneOS() && !isTargetIOSSimulator()) { getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) << "-fsanitize=address"; } else { - AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.asan_osx_dynamic.dylib", true); - - // The ASAN runtime library requires C++. - AddCXXStdlibLibArgs(Args, CmdArgs); + if (Args.hasArg(options::OPT_dynamiclib) || + Args.hasArg(options::OPT_bundle)) { + // Assume the binary will provide the ASan runtime. + } else { + AddLinkRuntimeLib(Args, CmdArgs, + "libclang_rt.asan_osx_dynamic.dylib", true); + // The ASAN runtime library requires C++. + AddCXXStdlibLibArgs(Args, CmdArgs); + } } } @@ -899,6 +878,10 @@ bool Darwin::isPICDefault() const { return true; } +bool Darwin::isPIEDefault() const { + return false; +} + bool Darwin::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64; } @@ -1103,6 +1086,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( }; static const char *const ARMHFTriples[] = { "arm-linux-gnueabihf", + "armv7hl-redhat-linux-gnueabi" }; static const char *const X86_64LibDirs[] = { "/lib64", "/lib" }; @@ -1137,7 +1121,8 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( static const char *const MIPSELLibDirs[] = { "/lib" }; static const char *const MIPSELTriples[] = { "mipsel-linux-gnu", - "mipsel-linux-android" + "mipsel-linux-android", + "mips-linux-gnu" }; static const char *const MIPS64LibDirs[] = { "/lib64", "/lib" }; @@ -1149,6 +1134,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( static const char *const PPCTriples[] = { "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", + "powerpc-linux-gnuspe", "powerpc-suse-linux", "powerpc-montavista-linuxspe" }; @@ -1160,6 +1146,15 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( "ppc64-redhat-linux" }; + static const char *const SystemZLibDirs[] = { "/lib64", "/lib" }; + static const char *const SystemZTriples[] = { + "s390x-linux-gnu", + "s390x-unknown-linux-gnu", + "s390x-ibm-linux-gnu", + "s390x-suse-linux", + "s390x-redhat-linux" + }; + switch (TargetTriple.getArch()) { case llvm::Triple::aarch64: LibDirs.append(AArch64LibDirs, AArch64LibDirs @@ -1260,6 +1255,12 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( MultiarchTripleAliases.append( PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples)); break; + case llvm::Triple::systemz: + LibDirs.append( + SystemZLibDirs, SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs)); + TripleAliases.append( + SystemZTriples, SystemZTriples + llvm::array_lengthof(SystemZTriples)); + break; default: // By default, just rely on the standard lib directories and the original @@ -1276,29 +1277,102 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( MultiarchTripleAliases.push_back(MultiarchTriple.str()); } +static bool isSoftFloatABI(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_msoft_float, + options::OPT_mhard_float, + options::OPT_mfloat_abi_EQ); + if (!A) return false; + + return A->getOption().matches(options::OPT_msoft_float) || + (A->getOption().matches(options::OPT_mfloat_abi_EQ) && + A->getValue() == StringRef("soft")); +} + +static bool isMipsArch(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mips || + Arch == llvm::Triple::mipsel || + Arch == llvm::Triple::mips64 || + Arch == llvm::Triple::mips64el; +} + +static bool isMips16(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mips16, + options::OPT_mno_mips16); + return A && A->getOption().matches(options::OPT_mips16); +} + +static bool isMicroMips(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mmicromips, + options::OPT_mno_micromips); + return A && A->getOption().matches(options::OPT_mmicromips); +} + // FIXME: There is the same routine in the Tools.cpp. static bool hasMipsN32ABIArg(const ArgList &Args) { Arg *A = Args.getLastArg(options::OPT_mabi_EQ); return A && (A->getValue() == StringRef("n32")); } -static StringRef getTargetMultiarchSuffix(llvm::Triple::ArchType TargetArch, - const ArgList &Args) { - if (TargetArch == llvm::Triple::x86_64 || - TargetArch == llvm::Triple::ppc64) - return "/64"; +static void appendMipsTargetSuffix(std::string &Path, + llvm::Triple::ArchType TargetArch, + const ArgList &Args) { + if (isMips16(Args)) + Path += "/mips16"; + else if (isMicroMips(Args)) + Path += "/micromips"; + + if (isSoftFloatABI(Args)) + Path += "/soft-float"; + if (TargetArch == llvm::Triple::mipsel || + TargetArch == llvm::Triple::mips64el) + Path += "/el"; +} + +static StringRef getMipsTargetABISuffix(llvm::Triple::ArchType TargetArch, + const ArgList &Args) { if (TargetArch == llvm::Triple::mips64 || - TargetArch == llvm::Triple::mips64el) { - if (hasMipsN32ABIArg(Args)) - return "/n32"; - else - return "/64"; - } + TargetArch == llvm::Triple::mips64el) + return hasMipsN32ABIArg(Args) ? "/n32" : "/64"; return "/32"; } +static bool findTargetMultiarchSuffix(std::string &Suffix, + StringRef Path, + llvm::Triple::ArchType TargetArch, + const ArgList &Args) { + if (isMipsArch(TargetArch)) { + StringRef ABISuffix = getMipsTargetABISuffix(TargetArch, Args); + + // First build and check a complex path to crtbegin.o + // depends on command line options (-mips16, -msoft-float, ...) + // like mips-linux-gnu/4.7/mips16/soft-float/el/crtbegin.o + appendMipsTargetSuffix(Suffix, TargetArch, Args); + + if (TargetArch == llvm::Triple::mips64 || + TargetArch == llvm::Triple::mips64el) + Suffix += ABISuffix; + + if (llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o")) + return true; + + // Then fall back and probe a simple case like + // mips-linux-gnu/4.7/32/crtbegin.o + Suffix = ABISuffix; + return llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o"); + } + + if (TargetArch == llvm::Triple::x86_64 || + TargetArch == llvm::Triple::ppc64 || + TargetArch == llvm::Triple::systemz) + Suffix = "/64"; + else + Suffix = "/32"; + + return llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o"); +} + void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( llvm::Triple::ArchType TargetArch, const ArgList &Args, const std::string &LibDir, @@ -1348,9 +1422,11 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( // *if* there is a subdirectory of the right name with crtbegin.o in it, // we use that. If not, and if not a multiarch triple, we look for // crtbegin.o without the subdirectory. - StringRef MultiarchSuffix = getTargetMultiarchSuffix(TargetArch, Args); - if (llvm::sys::fs::exists(LI->path() + MultiarchSuffix + "/crtbegin.o")) { - GCCMultiarchSuffix = MultiarchSuffix.str(); + + std::string MultiarchSuffix; + if (findTargetMultiarchSuffix(MultiarchSuffix, + LI->path(), TargetArch, Args)) { + GCCMultiarchSuffix = MultiarchSuffix; } else { if (NeedsMultiarchSuffix || !llvm::sys::fs::exists(LI->path() + "/crtbegin.o")) @@ -1372,60 +1448,40 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) - : ToolChain(D, Triple), GCCInstallation(getDriver(), Triple, Args) { + : ToolChain(D, Triple, Args), GCCInstallation(getDriver(), Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); } Generic_GCC::~Generic_GCC() { - // Free tool implementations. - for (llvm::DenseMap<unsigned, Tool*>::iterator - it = Tools.begin(), ie = Tools.end(); it != ie; ++it) - delete it->second; -} - -Tool &Generic_GCC::SelectTool(const Compilation &C, - const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::InputClass: - case Action::BindArchClass: - llvm_unreachable("Invalid tool kind."); - case Action::PreprocessJobClass: - T = new tools::gcc::Preprocess(*this); break; - case Action::PrecompileJobClass: - T = new tools::gcc::Precompile(*this); break; - case Action::AnalyzeJobClass: - case Action::MigrateJobClass: - T = new tools::Clang(*this); break; - case Action::CompileJobClass: - T = new tools::gcc::Compile(*this); break; - case Action::AssembleJobClass: - T = new tools::gcc::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::gcc::Link(*this); break; - - // This is a bit ungeneric, but the only platform using a driver - // driver is Darwin. - case Action::LipoJobClass: - T = new tools::darwin::Lipo(*this); break; - case Action::DsymutilJobClass: - T = new tools::darwin::Dsymutil(*this); break; - case Action::VerifyJobClass: - T = new tools::darwin::VerifyDebug(*this); break; - } +} + +Tool *Generic_GCC::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::PreprocessJobClass: + if (!Preprocess) + Preprocess.reset(new tools::gcc::Preprocess(*this)); + return Preprocess.get(); + case Action::PrecompileJobClass: + if (!Precompile) + Precompile.reset(new tools::gcc::Precompile(*this)); + return Precompile.get(); + case Action::CompileJobClass: + if (!Compile) + Compile.reset(new tools::gcc::Compile(*this)); + return Compile.get(); + default: + return ToolChain::getTool(AC); } +} - return *T; +Tool *Generic_GCC::buildAssembler() const { + return new tools::gcc::Assemble(*this); +} + +Tool *Generic_GCC::buildLinker() const { + return new tools::gcc::Link(*this); } bool Generic_GCC::IsUnwindTablesDefault() const { @@ -1436,6 +1492,10 @@ bool Generic_GCC::isPICDefault() const { return false; } +bool Generic_GCC::isPIEDefault() const { + return false; +} + bool Generic_GCC::isPICDefaultForced() const { return false; } @@ -1550,47 +1610,14 @@ Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple &Triple, } Hexagon_TC::~Hexagon_TC() { - // Free tool implementations. - for (llvm::DenseMap<unsigned, Tool*>::iterator - it = Tools.begin(), ie = Tools.end(); it != ie; ++it) - delete it->second; -} - -Tool &Hexagon_TC::SelectTool(const Compilation &C, - const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - // if (JA.getKind () == Action::CompileJobClass) - // Key = JA.getKind (); - // else - - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - // if ((JA.getKind () == Action::CompileJobClass) - // && (JA.getType () != types::TY_LTO_BC)) { - // Key = JA.getKind (); - // } - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::InputClass: - case Action::BindArchClass: - assert(0 && "Invalid tool kind."); - case Action::AnalyzeJobClass: - T = new tools::Clang(*this); break; - case Action::AssembleJobClass: - T = new tools::hexagon::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::hexagon::Link(*this); break; - default: - assert(false && "Unsupported action for Hexagon target."); - } - } +} + +Tool *Hexagon_TC::buildAssembler() const { + return new tools::hexagon::Assemble(*this); +} - return *T; +Tool *Hexagon_TC::buildLinker() const { + return new tools::hexagon::Link(*this); } void Hexagon_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -1682,8 +1709,9 @@ StringRef Hexagon_TC::GetTargetCPU(const ArgList &Args) /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. /// Currently does not support anything else but compilation. -TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple) - : ToolChain(D, Triple) { +TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) { // Path mangling to find libexec std::string Path(getDriver().Dir); @@ -1692,9 +1720,6 @@ TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple) } TCEToolChain::~TCEToolChain() { - for (llvm::DenseMap<unsigned, Tool*>::iterator - it = Tools.begin(), ie = Tools.end(); it != ie; ++it) - delete it->second; } bool TCEToolChain::IsMathErrnoDefault() const { @@ -1705,28 +1730,12 @@ bool TCEToolChain::isPICDefault() const { return false; } -bool TCEToolChain::isPICDefaultForced() const { +bool TCEToolChain::isPIEDefault() const { return false; } -Tool &TCEToolChain::SelectTool(const Compilation &C, - const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - Key = Action::AnalyzeJobClass; - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::PreprocessJobClass: - T = new tools::gcc::Preprocess(*this); break; - case Action::AnalyzeJobClass: - T = new tools::Clang(*this); break; - default: - llvm_unreachable("Unsupported action for TCE target."); - } - } - return *T; +bool TCEToolChain::isPICDefaultForced() const { + return false; } /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. @@ -1737,36 +1746,12 @@ OpenBSD::OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Arg getFilePaths().push_back("/usr/lib"); } -Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: { - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::openbsd::Assemble(*this); - break; - } - case Action::LinkJobClass: - T = new tools::openbsd::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *OpenBSD::buildAssembler() const { + return new tools::openbsd::Assemble(*this); +} - return *T; +Tool *OpenBSD::buildLinker() const { + return new tools::openbsd::Link(*this); } /// Bitrig - Bitrig tool chain which can call as(1) and ld(1) directly. @@ -1777,36 +1762,12 @@ Bitrig::Bitrig(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) getFilePaths().push_back("/usr/lib"); } -Tool &Bitrig::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: { - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::bitrig::Assemble(*this); - break; - } - case Action::LinkJobClass: - T = new tools::bitrig::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *Bitrig::buildAssembler() const { + return new tools::bitrig::Assemble(*this); +} - return *T; +Tool *Bitrig::buildLinker() const { + return new tools::bitrig::Link(*this); } void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, @@ -1869,35 +1830,12 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Arg getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); } -Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::freebsd::Assemble(*this); - break; - case Action::LinkJobClass: - T = new tools::freebsd::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *FreeBSD::buildAssembler() const { + return new tools::freebsd::Assemble(*this); +} - return *T; +Tool *FreeBSD::buildLinker() const { + return new tools::freebsd::Link(*this); } bool FreeBSD::UseSjLjExceptions() const { @@ -1931,36 +1869,48 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) } } -Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::netbsd::Assemble(*this); - break; - case Action::LinkJobClass: - T = new tools::netbsd::Link(*this); - break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } +Tool *NetBSD::buildAssembler() const { + return new tools::netbsd::Assemble(*this); +} + +Tool *NetBSD::buildLinker() const { + return new tools::netbsd::Link(*this); +} + +ToolChain::CXXStdlibType +NetBSD::GetCXXStdlibType(const ArgList &Args) const { + if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { + StringRef Value = A->getValue(); + if (Value == "libstdc++") + return ToolChain::CST_Libstdcxx; + if (Value == "libc++") + return ToolChain::CST_Libcxx; + + getDriver().Diag(diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); } - return *T; + return ToolChain::CST_Libstdcxx; +} + +void NetBSD::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/"); + break; + case ToolChain::CST_Libstdcxx: + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/g++"); + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/g++/backward"); + break; + } } /// Minix - Minix tool chain which can call as(1) and ld(1) directly. @@ -1971,27 +1921,12 @@ Minix::Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) getFilePaths().push_back("/usr/lib"); } -Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - T = new tools::minix::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::minix::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *Minix::buildAssembler() const { + return new tools::minix::Assemble(*this); +} - return *T; +Tool *Minix::buildLinker() const { + return new tools::minix::Link(*this); } /// AuroraUX - AuroraUX tool chain which can call as(1) and ld(1) directly. @@ -2012,27 +1947,12 @@ AuroraUX::AuroraUX(const Driver &D, const llvm::Triple& Triple, } -Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - T = new tools::auroraux::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::auroraux::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *AuroraUX::buildAssembler() const { + return new tools::auroraux::Assemble(*this); +} - return *T; +Tool *AuroraUX::buildLinker() const { + return new tools::auroraux::Link(*this); } /// Solaris - Solaris tool chain which can call as(1) and ld(1) directly. @@ -2049,32 +1969,17 @@ Solaris::Solaris(const Driver &D, const llvm::Triple& Triple, getFilePaths().push_back("/usr/lib"); } -Tool &Solaris::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - T = new tools::solaris::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::solaris::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *Solaris::buildAssembler() const { + return new tools::solaris::Assemble(*this); +} - return *T; +Tool *Solaris::buildLinker() const { + return new tools::solaris::Link(*this); } -/// Linux toolchain (very bare-bones at the moment). +/// Distribution (very bare-bones at the moment). -enum LinuxDistro { +enum Distro { ArchLinux, DebianLenny, DebianSqueeze, @@ -2107,33 +2012,33 @@ enum LinuxDistro { UnknownDistro }; -static bool IsRedhat(enum LinuxDistro Distro) { +static bool IsRedhat(enum Distro Distro) { return (Distro >= Fedora13 && Distro <= FedoraRawhide) || (Distro >= RHEL4 && Distro <= RHEL6); } -static bool IsOpenSuse(enum LinuxDistro Distro) { +static bool IsOpenSuse(enum Distro Distro) { return Distro >= OpenSuse11_3 && Distro <= OpenSuse12_2; } -static bool IsDebian(enum LinuxDistro Distro) { +static bool IsDebian(enum Distro Distro) { return Distro >= DebianLenny && Distro <= DebianJessie; } -static bool IsUbuntu(enum LinuxDistro Distro) { +static bool IsUbuntu(enum Distro Distro) { return Distro >= UbuntuHardy && Distro <= UbuntuRaring; } -static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { +static Distro DetectDistro(llvm::Triple::ArchType Arch) { OwningPtr<llvm::MemoryBuffer> File; if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) { StringRef Data = File.get()->getBuffer(); SmallVector<StringRef, 8> Lines; Data.split(Lines, "\n"); - LinuxDistro Version = UnknownDistro; + Distro Version = UnknownDistro; for (unsigned i = 0, s = Lines.size(); i != s; ++i) if (Version == UnknownDistro && Lines[i].startswith("DISTRIB_CODENAME=")) - Version = llvm::StringSwitch<LinuxDistro>(Lines[i].substr(17)) + Version = llvm::StringSwitch<Distro>(Lines[i].substr(17)) .Case("hardy", UbuntuHardy) .Case("intrepid", UbuntuIntrepid) .Case("jaunty", UbuntuJaunty) @@ -2190,7 +2095,7 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { } if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File)) - return llvm::StringSwitch<LinuxDistro>(File.get()->getBuffer()) + return llvm::StringSwitch<Distro>(File.get()->getBuffer()) .StartsWith("openSUSE 11.3", OpenSuse11_3) .StartsWith("openSUSE 11.4", OpenSuse11_4) .StartsWith("openSUSE 12.1", OpenSuse12_1) @@ -2255,6 +2160,8 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple, return "mipsel-linux-gnu"; return TargetTriple.str(); case llvm::Triple::ppc: + if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnuspe")) + return "powerpc-linux-gnuspe"; if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnu")) return "powerpc-linux-gnu"; return TargetTriple.str(); @@ -2269,13 +2176,6 @@ static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) { if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str()); } -static bool isMipsArch(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::mips || - Arch == llvm::Triple::mipsel || - Arch == llvm::Triple::mips64 || - Arch == llvm::Triple::mips64el; -} - static bool isMipsR2Arch(llvm::Triple::ArchType Arch, const ArgList &Args) { if (Arch != llvm::Triple::mips && @@ -2312,7 +2212,7 @@ static StringRef getMultilibDir(const llvm::Triple &Triple, Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { llvm::Triple::ArchType Arch = Triple.getArch(); - const std::string &SysRoot = getDriver().SysRoot; + std::string SysRoot = computeSysRoot(Args); // OpenSuse stores the linker with the compiler, add that to the search // path. @@ -2322,7 +2222,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) Linker = GetProgramPath("ld"); - LinuxDistro Distro = DetectLinuxDistro(Arch); + Distro Distro = DetectDistro(Arch); if (IsOpenSuse(Distro) || IsUbuntu(Distro)) { ExtraOpts.push_back("-z"); @@ -2333,13 +2233,17 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) ExtraOpts.push_back("-X"); const bool IsAndroid = Triple.getEnvironment() == llvm::Triple::Android; + const bool IsMips = isMipsArch(Arch); + + if (IsMips && !SysRoot.empty()) + ExtraOpts.push_back("--sysroot=" + SysRoot); // Do not use 'gnu' hash style for Mips targets because .gnu.hash // and the MIPS ABI require .dynsym to be sorted in different ways. // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS // ABI requires a mapping between the GOT and the symbol table. // Android loader does not support .gnu.hash. - if (!isMipsArch(Arch) && !IsAndroid) { + if (!IsMips && !IsAndroid) { if (IsRedhat(Distro) || IsOpenSuse(Distro) || (IsUbuntu(Distro) && Distro >= UbuntuMaverick)) ExtraOpts.push_back("--hash-style=gnu"); @@ -2404,6 +2308,15 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) if (IsAndroid) { addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths); } + // Sourcery CodeBench MIPS toolchain holds some libraries under + // the parent prefix of the GCC installation. + if (IsMips) { + std::string Suffix; + appendMipsTargetSuffix(Suffix, Arch, Args); + addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + + Multilib + Suffix, + Paths); + } } addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths); addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths); @@ -2430,41 +2343,20 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) } addPathIfExists(SysRoot + "/lib", Paths); addPathIfExists(SysRoot + "/usr/lib", Paths); + + IsPIEDefault = SanitizerArgs(*this, Args).hasZeroBaseShadow(); } bool Linux::HasNativeLLVMSupport() const { return true; } -Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::linuxtools::Assemble(*this); - break; - case Action::LinkJobClass: - T = new tools::linuxtools::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *Linux::buildLinker() const { + return new tools::gnutools::Link(*this); +} - return *T; +Tool *Linux::buildAssembler() const { + return new tools::gnutools::Assemble(*this); } void Linux::addClangTargetOptions(const ArgList &DriverArgs, @@ -2480,15 +2372,31 @@ void Linux::addClangTargetOptions(const ArgList &DriverArgs, CC1Args.push_back("-fuse-init-array"); } +std::string Linux::computeSysRoot(const ArgList &Args) const { + if (!getDriver().SysRoot.empty()) + return getDriver().SysRoot; + + if (!GCCInstallation.isValid() || !isMipsArch(getTriple().getArch())) + return std::string(); + + std::string Path = + (GCCInstallation.getInstallPath() + + "/../../../../" + GCCInstallation.getTriple().str() + "/libc").str(); + appendMipsTargetSuffix(Path, getTriple().getArch(), Args); + + return llvm::sys::fs::exists(Path) ? Path : ""; +} + void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(DriverArgs); if (DriverArgs.hasArg(options::OPT_nostdinc)) return; if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) - addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/local/include"); + addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { llvm::sys::Path P(D.ResourceDir); @@ -2506,7 +2414,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, CIncludeDirs.split(dirs, ":"); for (SmallVectorImpl<StringRef>::iterator I = dirs.begin(), E = dirs.end(); I != E; ++I) { - StringRef Prefix = llvm::sys::path::is_absolute(*I) ? D.SysRoot : ""; + StringRef Prefix = llvm::sys::path::is_absolute(*I) ? SysRoot : ""; addExternCSystemInclude(DriverArgs, CC1Args, Prefix + *I); } return; @@ -2515,6 +2423,20 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Lacking those, try to detect the correct set of system includes for the // target triple. + // Sourcery CodeBench and modern FSF Mips toolchains put extern C + // system includes under three additional directories. + if (GCCInstallation.isValid() && isMipsArch(getTriple().getArch())) { + addExternCSystemIncludeIfExists(DriverArgs, CC1Args, + GCCInstallation.getInstallPath() + + "/include"); + + addExternCSystemIncludeIfExists(DriverArgs, CC1Args, + GCCInstallation.getInstallPath() + + "/../../../../" + + GCCInstallation.getTriple().str() + + "/libc/usr/include"); + } + // Implement generic Debian multiarch support. const StringRef X86_64MultiarchIncludeDirs[] = { "/usr/include/x86_64-linux-gnu", @@ -2580,8 +2502,8 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, for (ArrayRef<StringRef>::iterator I = MultiarchIncludeDirs.begin(), E = MultiarchIncludeDirs.end(); I != E; ++I) { - if (llvm::sys::fs::exists(D.SysRoot + *I)) { - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + *I); + if (llvm::sys::fs::exists(SysRoot + *I)) { + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + *I); break; } } @@ -2592,9 +2514,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Add an include of '/include' directly. This isn't provided by default by // system GCCs, but is often used with cross-compiling GCCs, and harmless to // add even when Clang is acting as-if it were a system compiler. - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include"); + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); } /// \brief Helper to add the three variant paths for a libstdc++ installation. @@ -2678,6 +2600,10 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } } +bool Linux::isPIEDefault() const { + return IsPIEDefault; +} + /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. DragonFly::DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) @@ -2690,28 +2616,16 @@ DragonFly::DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); - getFilePaths().push_back("/usr/lib/gcc41"); + if (llvm::sys::fs::exists("/usr/lib/gcc47")) + getFilePaths().push_back("/usr/lib/gcc47"); + else + getFilePaths().push_back("/usr/lib/gcc44"); } -Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - T = new tools::dragonfly::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::dragonfly::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *DragonFly::buildAssembler() const { + return new tools::dragonfly::Assemble(*this); +} - return *T; +Tool *DragonFly::buildLinker() const { + return new tools::dragonfly::Link(*this); } diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 0419a375ea..3afd8dd228 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -117,20 +117,20 @@ protected: GCCInstallationDetector GCCInstallation; - mutable llvm::DenseMap<unsigned, Tool*> Tools; - public: Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); ~Generic_GCC(); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - virtual bool IsUnwindTablesDefault() const; virtual bool isPICDefault() const; + virtual bool isPIEDefault() const; virtual bool isPICDefaultForced() const; protected: + virtual Tool *getTool(Action::ActionClass AC) const; + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; + /// \name ToolChain Implementation Helper Functions /// @{ @@ -141,6 +141,11 @@ protected: bool isTarget32Bit() const { return getTriple().isArch32Bit(); } /// @} + +private: + mutable OwningPtr<tools::gcc::Preprocess> Preprocess; + mutable OwningPtr<tools::gcc::Precompile> Precompile; + mutable OwningPtr<tools::gcc::Compile> Compile; }; /// Darwin - The base Darwin tool chain. @@ -149,8 +154,15 @@ public: /// The host version. unsigned DarwinVersion[3]; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; + virtual Tool *getTool(Action::ActionClass AC) const; + private: - mutable llvm::DenseMap<unsigned, Tool*> Tools; + mutable OwningPtr<tools::darwin::Lipo> Lipo; + mutable OwningPtr<tools::darwin::Dsymutil> Dsymutil; + mutable OwningPtr<tools::darwin::VerifyDebug> VerifyDebug; /// Whether the information on the target has been initialized. // @@ -181,7 +193,7 @@ private: void AddDeploymentTarget(DerivedArgList &Args) const; public: - Darwin(const Driver &D, const llvm::Triple& Triple); + Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); ~Darwin(); std::string ComputeEffectiveClangTriple(const ArgList &Args, @@ -269,9 +281,6 @@ public: virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args, const char *BoundArch) const; - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - virtual bool IsBlocksDefault() const { // Always allow blocks on Darwin; users interested in versioning are // expected to use /usr/include/Blocks.h. @@ -324,6 +333,7 @@ public: return ToolChain::RLT_CompilerRT; } virtual bool isPICDefault() const; + virtual bool isPIEDefault() const; virtual bool isPICDefaultForced() const; virtual bool SupportsProfiling() const; @@ -342,7 +352,7 @@ public: /// DarwinClang - The Darwin toolchain used by Clang. class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin { public: - DarwinClang(const Driver &D, const llvm::Triple& Triple); + DarwinClang(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); /// @name Darwin ToolChain Implementation /// { @@ -394,18 +404,20 @@ class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC { public: AuroraUX(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC { public: Solaris(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - virtual bool IsIntegratedAssemblerDefault() const { return true; } +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; + }; @@ -416,8 +428,9 @@ public: virtual bool IsMathErrnoDefault() const { return false; } virtual bool IsObjCNonFragileABIDefault() const { return true; } - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF { @@ -428,9 +441,6 @@ public: virtual bool IsObjCNonFragileABIDefault() const { return true; } virtual bool IsObjCLegacyDispatchDefault() const { return false; } - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const; virtual void AddCXXStdlibLibArgs(const ArgList &Args, @@ -438,6 +448,10 @@ public: virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const { return 1; } + +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF { @@ -447,9 +461,10 @@ public: virtual bool IsMathErrnoDefault() const { return false; } virtual bool IsObjCNonFragileABIDefault() const { return true; } - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; virtual bool UseSjLjExceptions() const; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF { @@ -459,16 +474,23 @@ public: virtual bool IsMathErrnoDefault() const { return false; } virtual bool IsObjCNonFragileABIDefault() const { return true; } - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; + virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const; + + virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const; + +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF { public: Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF { @@ -477,8 +499,9 @@ public: virtual bool IsMathErrnoDefault() const { return false; } - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { @@ -487,18 +510,21 @@ public: virtual bool HasNativeLLVMSupport() const; - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const; virtual void addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args) const; virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const; + virtual bool isPIEDefault() const; std::string Linker; std::vector<std::string> ExtraOpts; + bool IsPIEDefault; + +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; private: static bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, @@ -509,22 +535,21 @@ private: static bool addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir, const ArgList &DriverArgs, ArgStringList &CC1Args); + + std::string computeSysRoot(const ArgList &Args) const; }; class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public Linux { protected: - mutable llvm::DenseMap<unsigned, Tool*> Tools; - GCCVersion GCCLibAndIncVersion; + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; public: Hexagon_TC(const Driver &D, const llvm::Triple &Triple, const ArgList &Args); ~Hexagon_TC(); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const; virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, @@ -542,39 +567,33 @@ public: /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain { public: - TCEToolChain(const Driver &D, const llvm::Triple& Triple); + TCEToolChain(const Driver &D, const llvm::Triple& Triple, + const ArgList &Args); ~TCEToolChain(); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; bool IsMathErrnoDefault() const; bool isPICDefault() const; + bool isPIEDefault() const; bool isPICDefaultForced() const; - -private: - mutable llvm::DenseMap<unsigned, Tool*> Tools; - }; class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain { - mutable llvm::DenseMap<unsigned, Tool*> Tools; - public: - Windows(const Driver &D, const llvm::Triple& Triple); - - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; + Windows(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); virtual bool IsIntegratedAssemblerDefault() const; virtual bool IsUnwindTablesDefault() const; virtual bool isPICDefault() const; + virtual bool isPIEDefault() const; virtual bool isPICDefaultForced() const; virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const; virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const; - +protected: + virtual Tool *buildLinker() const; + virtual Tool *buildAssembler() const; }; } // end namespace toolchains diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index ef759ff6d3..aba1fe4d2d 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include <sys/stat.h> #include "Tools.h" #include "InputInfo.h" #include "SanitizerArgs.h" @@ -544,6 +545,9 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { if (Triple.isOSDarwin()) return true; return false; + + case llvm::Triple::systemz: + return false; } } @@ -815,7 +819,9 @@ void Clang::AddARMTargetArgs(const ArgList &Args, CmdArgs.push_back("-mno-global-merge"); } - if (Args.hasArg(options::OPT_mno_implicit_float)) + if (!Args.hasFlag(options::OPT_mimplicit_float, + options::OPT_mno_implicit_float, + true)) CmdArgs.push_back("-no-implicit-float"); } @@ -851,8 +857,15 @@ static void getMipsCPUAndABI(const ArgList &Args, CPUName = A->getValue(); } - if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { ABIName = A->getValue(); + // Convert a GNU style Mips ABI name to the name + // accepted by LLVM Mips backend. + ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName) + .Case("32", "o32") + .Case("64", "n64") + .Default(ABIName); + } // Setup default CPU and ABI names. if (CPUName.empty() && ABIName.empty()) { @@ -899,8 +912,6 @@ static StringRef getGnuCompatibleMipsABIName(StringRef ABI) { // Select the MIPS float ABI as determined by -msoft-float, -mhard-float, // and -mfloat-abi=. static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) { - // Select the float ABI as determined by -msoft-float, -mhard-float, - // and -mfloat-abi=. StringRef FloatABI; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, @@ -911,7 +922,7 @@ static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) { FloatABI = "hard"; else { FloatABI = A->getValue(); - if (FloatABI != "soft" && FloatABI != "single" && FloatABI != "hard") { + if (FloatABI != "soft" && FloatABI != "hard") { D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); FloatABI = "hard"; } @@ -944,7 +955,7 @@ static void AddTargetFeature(const ArgList &Args, } void Clang::AddMIPSTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { + ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); StringRef CPUName; StringRef ABIName; @@ -977,12 +988,6 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, CmdArgs.push_back("-mips16-hard-float"); } } - else if (FloatABI == "single") { - // Restrict the use of hardware floating-point - // instructions to 32-bit operations. - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+single-float"); - } else { // Floating point operations and argument passing are hard. assert(FloatABI == "hard" && "Invalid float abi!"); @@ -991,9 +996,15 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, } AddTargetFeature(Args, CmdArgs, + options::OPT_msingle_float, options::OPT_mdouble_float, + "single-float"); + AddTargetFeature(Args, CmdArgs, options::OPT_mips16, options::OPT_mno_mips16, "mips16"); AddTargetFeature(Args, CmdArgs, + options::OPT_mmicromips, options::OPT_mno_micromips, + "micromips"); + AddTargetFeature(Args, CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp, "dsp"); AddTargetFeature(Args, CmdArgs, @@ -1097,17 +1108,55 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, } // Allow override of the Altivec feature. - if (Args.hasFlag(options::OPT_fno_altivec, options::OPT_faltivec, false)) { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-altivec"); - } + AddTargetFeature(Args, CmdArgs, + options::OPT_faltivec, options::OPT_fno_altivec, + "altivec"); + + AddTargetFeature(Args, CmdArgs, + options::OPT_mfprnd, options::OPT_mno_fprnd, + "fprnd"); + + // Note that gcc calls this mfcrf and LLVM calls this mfocrf. + AddTargetFeature(Args, CmdArgs, + options::OPT_mmfcrf, options::OPT_mno_mfcrf, + "mfocrf"); + + AddTargetFeature(Args, CmdArgs, + options::OPT_mpopcntd, options::OPT_mno_popcntd, + "popcntd"); + // It is really only possible to turn qpx off because turning qpx on is tied + // to using the a2q CPU. if (Args.hasFlag(options::OPT_mno_qpx, options::OPT_mqpx, false)) { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("-qpx"); } } +/// Get the (LLVM) name of the R600 gpu we are targeting. +static std::string getR600TargetGPU(const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + std::string GPUName = A->getValue(); + return llvm::StringSwitch<const char *>(GPUName) + .Cases("rv630", "rv635", "r600") + .Cases("rv610", "rv620", "rs780", "rs880") + .Case("rv740", "rv770") + .Case("palm", "cedar") + .Cases("sumo", "sumo2", "sumo") + .Case("hemlock", "cypress") + .Case("aruba", "cayman") + .Default(GPUName.c_str()); + } + return ""; +} + +void Clang::AddR600TargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + std::string TargetGPUName = getR600TargetGPU(Args); + CmdArgs.push_back("-target-cpu"); + CmdArgs.push_back(Args.MakeArgString(TargetGPUName.c_str())); +} + void Clang::AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); @@ -1217,6 +1266,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args, Args.hasArg(options::OPT_fapple_kext)); if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mno_soft_float, + options::OPT_mimplicit_float, options::OPT_mno_implicit_float)) { const Option &O = A->getOption(); NoImplicitFloat = (O.matches(options::OPT_mno_implicit_float) || @@ -1414,36 +1464,36 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("-fexceptions"); } +static bool ShouldDisableAutolink(const ArgList &Args, + const ToolChain &TC) { + bool Default = true; + if (TC.getTriple().isOSDarwin()) { + // The native darwin assembler doesn't support the linker_option directives, + // so we disable them if we think the .s file will be passed to it. + Default = TC.useIntegratedAs(); + } + return !Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink, + Default); +} + static bool ShouldDisableCFI(const ArgList &Args, const ToolChain &TC) { bool Default = true; if (TC.getTriple().isOSDarwin()) { // The native darwin assembler doesn't support cfi directives, so // we disable them if we think the .s file will be passed to it. - Default = Args.hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - TC.IsIntegratedAssemblerDefault()); + Default = TC.useIntegratedAs(); } return !Args.hasFlag(options::OPT_fdwarf2_cfi_asm, options::OPT_fno_dwarf2_cfi_asm, Default); } -static bool ShouldUseIntegratedAssembler(const ArgList &Args, - const ToolChain &TC) { - bool IsIADefault = TC.IsIntegratedAssemblerDefault(); - bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIADefault); - return UseIntegratedAs; -} - static bool ShouldDisableDwarfDirectory(const ArgList &Args, const ToolChain &TC) { - bool UseIntegratedAs = ShouldUseIntegratedAssembler(Args, TC); bool UseDwarfDirectory = Args.hasFlag(options::OPT_fdwarf_directory_asm, options::OPT_fno_dwarf_directory_asm, - UseIntegratedAs); + TC.useIntegratedAs()); return !UseDwarfDirectory; } @@ -1482,11 +1532,12 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) { RelaxDefault); } -SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) +SanitizerArgs::SanitizerArgs(const ToolChain &TC, const ArgList &Args) : Kind(0), BlacklistFile(""), MsanTrackOrigins(false), AsanZeroBaseShadow(false) { unsigned AllKinds = 0; // All kinds of sanitizers that were turned on // at least once (possibly, disabled further). + const Driver &D = TC.getDriver(); for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { unsigned Add, Remove; if (!parse(D, Args, *I, Add, Remove, true)) @@ -1578,40 +1629,61 @@ SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) /* Default */false); // Parse -f(no-)sanitize-address-zero-base-shadow options. - if (NeedsAsan) + if (NeedsAsan) { + bool IsAndroid = (TC.getTriple().getEnvironment() == llvm::Triple::Android); + bool ZeroBaseShadowDefault = IsAndroid; AsanZeroBaseShadow = - Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow, - options::OPT_fno_sanitize_address_zero_base_shadow, - /* Default */false); + Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow, + options::OPT_fno_sanitize_address_zero_base_shadow, + ZeroBaseShadowDefault); + // Zero-base shadow is a requirement on Android. + if (IsAndroid && !AsanZeroBaseShadow) { + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fno-sanitize-address-zero-base-shadow" + << lastArgumentForKind(D, Args, Address); + } + } } static void addSanitizerRTLinkFlagsLinux( const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, - const StringRef Sanitizer, bool BeforeLibStdCXX) { + const StringRef Sanitizer, bool BeforeLibStdCXX, + bool ExportSymbols = true) { // Sanitizer runtime is located in the Linux library directory and // has name "libclang_rt.<Sanitizer>-<ArchName>.a". SmallString<128> LibSanitizer(TC.getDriver().ResourceDir); llvm::sys::path::append( LibSanitizer, "lib", "linux", (Twine("libclang_rt.") + Sanitizer + "-" + TC.getArchName() + ".a")); + // Sanitizer runtime may need to come before -lstdc++ (or -lc++, libstdc++.a, // etc.) so that the linker picks custom versions of the global 'operator // new' and 'operator delete' symbols. We take the extreme (but simple) // strategy of inserting it at the front of the link command. It also // needs to be forced to end up in the executable, so wrap it in // whole-archive. - if (BeforeLibStdCXX) { - SmallVector<const char *, 3> PrefixArgs; - PrefixArgs.push_back("-whole-archive"); - PrefixArgs.push_back(Args.MakeArgString(LibSanitizer)); - PrefixArgs.push_back("-no-whole-archive"); - CmdArgs.insert(CmdArgs.begin(), PrefixArgs.begin(), PrefixArgs.end()); - } else { - CmdArgs.push_back(Args.MakeArgString(LibSanitizer)); - } + SmallVector<const char *, 3> LibSanitizerArgs; + LibSanitizerArgs.push_back("-whole-archive"); + LibSanitizerArgs.push_back(Args.MakeArgString(LibSanitizer)); + LibSanitizerArgs.push_back("-no-whole-archive"); + + CmdArgs.insert(BeforeLibStdCXX ? CmdArgs.begin() : CmdArgs.end(), + LibSanitizerArgs.begin(), LibSanitizerArgs.end()); + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-lrt"); CmdArgs.push_back("-ldl"); - CmdArgs.push_back("-export-dynamic"); + + // If possible, use a dynamic symbols file to export the symbols from the + // runtime library. If we can't do so, use -export-dynamic instead to export + // all symbols from the binary. + if (ExportSymbols) { + if (llvm::sys::fs::exists(LibSanitizer + ".syms")) + CmdArgs.push_back( + Args.MakeArgString("--dynamic-list=" + LibSanitizer + ".syms")); + else + CmdArgs.push_back("-export-dynamic"); + } } /// If AddressSanitizer is enabled, add appropriate linker flags (Linux). @@ -1619,11 +1691,6 @@ static void addSanitizerRTLinkFlagsLinux( static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { if(TC.getTriple().getEnvironment() == llvm::Triple::Android) { - if (!Args.hasArg(options::OPT_shared)) { - if (!Args.hasArg(options::OPT_pie)) - TC.getDriver().Diag(diag::err_drv_asan_android_requires_pie); - } - SmallString<128> LibAsan(TC.getDriver().ResourceDir); llvm::sys::path::append(LibAsan, "lib", "linux", (Twine("libclang_rt.asan-") + @@ -1631,13 +1698,6 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args, CmdArgs.insert(CmdArgs.begin(), Args.MakeArgString(LibAsan)); } else { if (!Args.hasArg(options::OPT_shared)) { - bool ZeroBaseShadow = Args.hasFlag( - options::OPT_fsanitize_address_zero_base_shadow, - options::OPT_fno_sanitize_address_zero_base_shadow, false); - if (ZeroBaseShadow && !Args.hasArg(options::OPT_pie)) { - TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) << - "-fsanitize-address-zero-base-shadow" << "-pie"; - } addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "asan", true); } } @@ -1648,9 +1708,6 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args, static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { if (!Args.hasArg(options::OPT_shared)) { - if (!Args.hasArg(options::OPT_pie)) - TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) << - "-fsanitize=thread" << "-pie"; addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "tsan", true); } } @@ -1660,9 +1717,6 @@ static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args, static void addMsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { if (!Args.hasArg(options::OPT_shared)) { - if (!Args.hasArg(options::OPT_pie)) - TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) << - "-fsanitize=memory" << "-pie"; addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "msan", true); } } @@ -1670,8 +1724,22 @@ static void addMsanRTLinux(const ToolChain &TC, const ArgList &Args, /// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags /// (Linux). static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { + ArgStringList &CmdArgs, bool IsCXX, + bool HasOtherSanitizerRt) { + if (Args.hasArg(options::OPT_shared)) + return; + + // Need a copy of sanitizer_common. This could come from another sanitizer + // runtime; if we're not including one, include our own copy. + if (!HasOtherSanitizerRt) + addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "san", true, false); + addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan", false); + + // Only include the bits of the runtime which need a C++ ABI library if + // we're linking in C++ mode. + if (IsCXX) + addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan_cxx", false); } static bool shouldUseFramePointer(const ArgList &Args, @@ -1692,17 +1760,48 @@ static bool shouldUseFramePointer(const ArgList &Args, return true; } +static bool shouldUseLeafFramePointer(const ArgList &Args, + const llvm::Triple &Triple) { + if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer, + options::OPT_momit_leaf_frame_pointer)) + return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer); + + // Don't use a leaf frame pointer on linux x86 and x86_64 if optimizing. + if ((Triple.getArch() == llvm::Triple::x86_64 || + Triple.getArch() == llvm::Triple::x86) && + Triple.getOS() == llvm::Triple::Linux) { + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) + if (!A->getOption().matches(options::OPT_O0)) + return false; + } + + return true; +} + /// If the PWD environment variable is set, add a CC1 option to specify the /// debug compilation directory. static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) { - if (const char *pwd = ::getenv("PWD")) { - // GCC also verifies that stat(pwd) and stat(".") have the same inode - // number. Not doing those because stats are slow, but we could. - if (llvm::sys::path::is_absolute(pwd)) { - std::string CompDir = pwd; - CmdArgs.push_back("-fdebug-compilation-dir"); - CmdArgs.push_back(Args.MakeArgString(CompDir)); - } + struct stat StatPWDBuf, StatDotBuf; + + const char *pwd = ::getenv("PWD"); + if (!pwd) + return; + + if (llvm::sys::path::is_absolute(pwd) && + stat(pwd, &StatPWDBuf) == 0 && + stat(".", &StatDotBuf) == 0 && + StatPWDBuf.st_ino == StatDotBuf.st_ino && + StatPWDBuf.st_dev == StatDotBuf.st_dev) { + CmdArgs.push_back("-fdebug-compilation-dir"); + CmdArgs.push_back(Args.MakeArgString(pwd)); + return; + } + + // Fall back to using getcwd. + SmallString<128> cwd; + if (!llvm::sys::fs::current_path(cwd)) { + CmdArgs.push_back("-fdebug-compilation-dir"); + CmdArgs.push_back(Args.MakeArgString(cwd)); } } @@ -1748,6 +1847,13 @@ static void SplitDebugInfo(const ToolChain &TC, Compilation &C, C.addCommand(new Command(JA, T, Exec, StripArgs)); } +static bool isOptimizationLevelFast(const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) + if (A->getOption().matches(options::OPT_Ofast)) + return true; + return false; +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -1781,8 +1887,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else if (isa<PreprocessJobAction>(JA)) { if (Output.getType() == types::TY_Dependencies) CmdArgs.push_back("-Eonly"); - else + else { CmdArgs.push_back("-E"); + if (Args.hasArg(options::OPT_rewrite_objc) && + !Args.hasArg(options::OPT_g_Group)) + CmdArgs.push_back("-P"); + } } else if (isa<AssembleJobAction>(JA)) { CmdArgs.push_back("-emit-obj"); @@ -1843,6 +1953,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-S"); } else if (JA.getType() == types::TY_AST) { CmdArgs.push_back("-emit-pch"); + } else if (JA.getType() == types::TY_ModuleFile) { + CmdArgs.push_back("-module-file-info"); } else if (JA.getType() == types::TY_RewrittenObjC) { CmdArgs.push_back("-rewrite-objc"); rewriteKind = RK_NonFragile; @@ -1894,6 +2006,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-analyzer-checker=deadcode"); + if (types::isCXX(Inputs[0].getType())) + CmdArgs.push_back("-analyzer-checker=cplusplus"); + // Enable the following experimental checkers for testing. CmdArgs.push_back("-analyzer-checker=security.insecureAPI.UncheckedReturn"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw"); @@ -1922,37 +2037,38 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CheckCodeGenerationOptions(D, Args); - // For the PIC and PIE flag options, this logic is different from the legacy - // logic in very old versions of GCC, as that logic was just a bug no one had - // ever fixed. This logic is both more rational and consistent with GCC's new - // logic now that the bugs are fixed. The last argument relating to either - // PIC or PIE wins, and no other argument is used. If the last argument is - // any flavor of the '-fno-...' arguments, both PIC and PIE are disabled. Any - // PIE option implicitly enables PIC at the same level. - bool PIE = false; - bool PIC = getToolChain().isPICDefault(); + bool PIE = getToolChain().isPIEDefault(); + bool PIC = PIE || getToolChain().isPICDefault(); bool IsPICLevelTwo = PIC; - if (Arg *A = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, - options::OPT_fpic, options::OPT_fno_pic, - options::OPT_fPIE, options::OPT_fno_PIE, - options::OPT_fpie, options::OPT_fno_pie)) { - Option O = A->getOption(); - if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || - O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { - PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); - PIC = PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic); - IsPICLevelTwo = O.matches(options::OPT_fPIE) || - O.matches(options::OPT_fPIC); - } else { - PIE = PIC = false; - } - } + + // For the PIC and PIE flag options, this logic is different from the + // legacy logic in very old versions of GCC, as that logic was just + // a bug no one had ever fixed. This logic is both more rational and + // consistent with GCC's new logic now that the bugs are fixed. The last + // argument relating to either PIC or PIE wins, and no other argument is + // used. If the last argument is any flavor of the '-fno-...' arguments, + // both PIC and PIE are disabled. Any PIE option implicitly enables PIC + // at the same level. + Arg *LastPICArg =Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, + options::OPT_fpic, options::OPT_fno_pic, + options::OPT_fPIE, options::OPT_fno_PIE, + options::OPT_fpie, options::OPT_fno_pie); // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness // is forced, then neither PIC nor PIE flags will have no effect. - if (getToolChain().isPICDefaultForced()) { - PIE = false; - PIC = getToolChain().isPICDefault(); - IsPICLevelTwo = PIC; + if (!getToolChain().isPICDefaultForced()) { + if (LastPICArg) { + Option O = LastPICArg->getOption(); + if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || + O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { + PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); + PIC = PIE || O.matches(options::OPT_fPIC) || + O.matches(options::OPT_fpic); + IsPICLevelTwo = O.matches(options::OPT_fPIE) || + O.matches(options::OPT_fPIC); + } else { + PIE = PIC = false; + } + } } // Inroduce a Darwin-specific hack. If the default is PIC but the flags @@ -2026,10 +2142,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, options::OPT_fno_zero_initialized_in_bss)) CmdArgs.push_back("-mno-zero-initialized-in-bss"); - if (!Args.hasFlag(options::OPT_fstrict_aliasing, + + bool OFastEnabled = isOptimizationLevelFast(Args); + // If -Ofast is the optimization level, then -fstrict-aliasing should be + // enabled. This alias option is being used to simplify the hasFlag logic. + OptSpecifier StrictAliasingAliasOption = OFastEnabled ? options::OPT_Ofast : + options::OPT_fstrict_aliasing; + if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption, options::OPT_fno_strict_aliasing, getToolChain().IsStrictAliasingDefault())) CmdArgs.push_back("-relaxed-aliasing"); + if (Args.hasArg(options::OPT_fstruct_path_tbaa)) + CmdArgs.push_back("-struct-path-tbaa"); if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, false)) CmdArgs.push_back("-fstrict-enums"); @@ -2037,12 +2161,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_optimize_sibling_calls)) CmdArgs.push_back("-mdisable-tail-calls"); + // Handle segmented stacks. + if (Args.hasArg(options::OPT_fsplit_stack)) + CmdArgs.push_back("-split-stacks"); + + // If -Ofast is the optimization level, then -ffast-math should be enabled. + // This alias option is being used to simplify the getLastArg logic. + OptSpecifier FastMathAliasOption = OFastEnabled ? options::OPT_Ofast : + options::OPT_ffast_math; + // Handle various floating point optimization flags, mapping them to the // appropriate LLVM code generation flags. The pattern for all of these is to // default off the codegen optimizations, and if any flag enables them and no // flag disables them after the flag enabling them, enable the codegen // optimization. This is complicated by several "umbrella" flags. - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_ffinite_math_only, options::OPT_fno_finite_math_only, @@ -2052,7 +2185,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->getOption().getID() != options::OPT_fno_finite_math_only && A->getOption().getID() != options::OPT_fhonor_infinities) CmdArgs.push_back("-menable-no-infs"); - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_ffinite_math_only, options::OPT_fno_finite_math_only, @@ -2065,7 +2198,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. bool MathErrno = getToolChain().IsMathErrnoDefault(); - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_fmath_errno, options::OPT_fno_math_errno)) @@ -2078,7 +2211,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // entire set of LLVM optimizations, so collect them through all the flag // madness. bool AssociativeMath = false; - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, @@ -2089,7 +2222,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->getOption().getID() != options::OPT_fno_associative_math) AssociativeMath = true; bool ReciprocalMath = false; - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, @@ -2100,7 +2233,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->getOption().getID() != options::OPT_fno_reciprocal_math) ReciprocalMath = true; bool SignedZeros = true; - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, @@ -2111,7 +2244,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->getOption().getID() != options::OPT_fsigned_zeros) SignedZeros = false; bool TrappingMath = true; - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, @@ -2127,7 +2260,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Validate and pass through -fp-contract option. - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_ffp_contract)) { if (A->getOption().getID() == options::OPT_ffp_contract) { @@ -2138,7 +2271,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Val; } - } else if (A->getOption().getID() == options::OPT_ffast_math) { + } else if (A->getOption().matches(options::OPT_ffast_math) || + (OFastEnabled && A->getOption().matches(options::OPT_Ofast))) { // If fast-math is set then set the fp-contract mode to fast. CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); } @@ -2149,9 +2283,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // preprocessor macros. This is distinct from enabling any optimizations as // these options induce language changes which must survive serialization // and deserialization, etc. - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, options::OPT_fno_fast_math)) - if (A->getOption().matches(options::OPT_ffast_math)) - CmdArgs.push_back("-ffast-math"); + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math)) + if (!A->getOption().matches(options::OPT_fno_fast_math)) + CmdArgs.push_back("-ffast-math"); if (Arg *A = Args.getLastArg(options::OPT_ffinite_math_only, options::OPT_fno_fast_math)) if (A->getOption().matches(options::OPT_ffinite_math_only)) CmdArgs.push_back("-ffinite-math-only"); @@ -2236,6 +2371,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, AddPPCTargetArgs(Args, CmdArgs); break; + case llvm::Triple::r600: + AddR600TargetArgs(Args, CmdArgs); + break; + case llvm::Triple::sparc: AddSparcTargetArgs(Args, CmdArgs); break; @@ -2258,10 +2397,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } - // -mno-omit-leaf-frame-pointer is the default on Darwin. - if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer, - options::OPT_mno_omit_leaf_frame_pointer, - !getToolChain().getTriple().isOSDarwin())) + if (!shouldUseLeafFramePointer(Args, getToolChain().getTriple())) CmdArgs.push_back("-momit-leaf-frame-pointer"); // Explicitly error on some things we know we don't support and can't just @@ -2515,6 +2651,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (ShouldDisableDwarfDirectory(Args, getToolChain())) CmdArgs.push_back("-fno-dwarf-directory-asm"); + if (ShouldDisableAutolink(Args, getToolChain())) + CmdArgs.push_back("-fno-autolink"); + // Add in -fdebug-compilation-dir if necessary. addDebugCompDirArg(Args, CmdArgs); @@ -2623,7 +2762,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree); Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type); - SanitizerArgs Sanitize(D, Args); + SanitizerArgs Sanitize(getToolChain(), Args); Sanitize.addArgs(Args, CmdArgs); if (!Args.hasFlag(options::OPT_fsanitize_recover, @@ -2784,12 +2923,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fmodules"); HaveModules = true; } - - if (HaveModules && !ShouldUseIntegratedAssembler(Args, getToolChain())) { - D.Diag(diag::err_drv_modules_integrated_as); - D.Diag(diag::note_drv_modules_integrated_as); - return; - } } // If a module path was provided, pass it along. Otherwise, use a temporary @@ -2803,7 +2936,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, SmallString<128> DefaultModuleCache; llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, DefaultModuleCache); - llvm::sys::path::append(DefaultModuleCache, "clang-module-cache"); + llvm::sys::path::append(DefaultModuleCache, "org.llvm.clang"); + llvm::sys::path::append(DefaultModuleCache, "ModuleCache"); const char Arg[] = "-fmodules-cache-path="; DefaultModuleCache.insert(DefaultModuleCache.begin(), Arg, Arg + strlen(Arg)); @@ -2812,15 +2946,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Pass through all -fmodules-ignore-macro arguments. Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro); - - // -fmodules-autolink (on by default when modules is enabled) automatically - // links against libraries for imported modules. - if (HaveModules && - Args.hasFlag(options::OPT_fmodules_autolink, - options::OPT_fno_modules_autolink, - true)) { - CmdArgs.push_back("-fmodules-autolink"); - } + Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after); // -faccess-control is default. if (Args.hasFlag(options::OPT_fno_access_control, @@ -3118,9 +3245,42 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Color diagnostics are the default, unless the terminal doesn't support // them. - if (Args.hasFlag(options::OPT_fcolor_diagnostics, - options::OPT_fno_color_diagnostics, - llvm::sys::Process::StandardErrHasColors())) + // Support both clang's -f[no-]color-diagnostics and gcc's + // -f[no-]diagnostics-colors[=never|always|auto]. + enum { Colors_On, Colors_Off, Colors_Auto } ShowColors = Colors_Auto; + for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); + it != ie; ++it) { + const Option &O = (*it)->getOption(); + if (!O.matches(options::OPT_fcolor_diagnostics) && + !O.matches(options::OPT_fdiagnostics_color) && + !O.matches(options::OPT_fno_color_diagnostics) && + !O.matches(options::OPT_fno_diagnostics_color) && + !O.matches(options::OPT_fdiagnostics_color_EQ)) + continue; + + (*it)->claim(); + if (O.matches(options::OPT_fcolor_diagnostics) || + O.matches(options::OPT_fdiagnostics_color)) { + ShowColors = Colors_On; + } else if (O.matches(options::OPT_fno_color_diagnostics) || + O.matches(options::OPT_fno_diagnostics_color)) { + ShowColors = Colors_Off; + } else { + assert(O.matches(options::OPT_fdiagnostics_color_EQ)); + StringRef value((*it)->getValue()); + if (value == "always") + ShowColors = Colors_On; + else if (value == "never") + ShowColors = Colors_Off; + else if (value == "auto") + ShowColors = Colors_Auto; + else + getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) + << ("-fdiagnostics-color=" + value).str(); + } + } + if (ShowColors == Colors_On || + (ShowColors == Colors_Auto && llvm::sys::Process::StandardErrHasColors())) CmdArgs.push_back("-fcolor-diagnostics"); if (!Args.hasFlag(options::OPT_fshow_source_location, @@ -3142,8 +3302,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, false)) CmdArgs.push_back("-fasm-blocks"); + // If -Ofast is the optimization level, then -fvectorize should be enabled. + // This alias option is being used to simplify the hasFlag logic. + OptSpecifier VectorizeAliasOption = OFastEnabled ? options::OPT_Ofast : + options::OPT_fvectorize; + // -fvectorize is default. - if (Args.hasFlag(options::OPT_fvectorize, + if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption, options::OPT_fno_vectorize, true)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-vectorize-loops"); @@ -3153,7 +3318,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_fslp_vectorize, options::OPT_fno_slp_vectorize, false)) { CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-vectorize"); + CmdArgs.push_back("-vectorize-slp"); + } + + // -fno-slp-vectorize-aggressive is default. + if (Args.hasFlag(options::OPT_fslp_vectorize_aggressive, + options::OPT_fno_slp_vectorize_aggressive, false)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-vectorize-slp-aggressive"); } if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) @@ -3218,6 +3390,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Forward -fcomment-block-commands to -cc1. Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands); + // Forward -fparse-all-comments to -cc1. + Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments); // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. @@ -3593,6 +3767,14 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = getToolChain().getDriver().getClangProgramPath(); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); + + // Handle the debug info splitting at object creation time if we're + // creating an object. + // TODO: Currently only works on linux with newer objcopy. + if (Args.hasArg(options::OPT_gsplit_dwarf) && + (getToolChain().getTriple().getOS() == llvm::Triple::Linux)) + SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, + SplitDebugName(Args, Inputs)); } void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, @@ -3644,7 +3826,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, // here. if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) CmdArgs.push_back("-m32"); - else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86_64) + else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::ppc64) CmdArgs.push_back("-m64"); if (Output.isFilename()) { @@ -3678,6 +3860,9 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, else if (II.getType() == types::TY_AST) D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); + else if (II.getType() == types::TY_ModuleFile) + D.Diag(diag::err_drv_no_module_support) + << getToolChain().getTripleString(); if (types::canTypeBeUserSpecified(II.getType())) { CmdArgs.push_back("-x"); @@ -3784,7 +3969,6 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString(std::string("-G") + SmallDataThreshold)); - Args.AddAllArgs(CmdArgs, options::OPT_g_Group); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); @@ -3808,6 +3992,9 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA, else if (II.getType() == types::TY_AST) D.Diag(clang::diag::err_drv_no_ast_support) << getToolChain().getTripleString(); + else if (II.getType() == types::TY_ModuleFile) + D.Diag(diag::err_drv_no_module_support) + << getToolChain().getTripleString(); if (II.isFilename()) CmdArgs.push_back(II.getFilename()); @@ -4493,7 +4680,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); - SanitizerArgs Sanitize(getToolChain().getDriver(), Args); + SanitizerArgs Sanitize(getToolChain(), Args); // If we're building a dynamic lib with -fsanitize=address, // unresolved symbols may appear. Mark all // of them as dynamic_lookup. Linking executables is handled in @@ -5217,6 +5404,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, switch(getToolChain().getTriple().getEnvironment()) { case llvm::Triple::GNUEABI: case llvm::Triple::EABI: + CmdArgs.push_back("-meabi=5"); break; default: @@ -5566,11 +5754,11 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } -void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { +void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { ArgStringList CmdArgs; // Add --32/--64 to make sure we get the format we want. @@ -5619,6 +5807,12 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-EL"); + Args.AddLastArg(CmdArgs, options::OPT_mips16, options::OPT_mno_mips16); + Args.AddLastArg(CmdArgs, options::OPT_mmicromips, + options::OPT_mno_micromips); + Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp); + Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2); + Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, options::OPT_fpic, options::OPT_fno_pic, options::OPT_fPIE, options::OPT_fno_PIE, @@ -5630,6 +5824,9 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, LastPICArg->getOption().matches(options::OPT_fpie))) { CmdArgs.push_back("-KPIC"); } + } else if (getToolChain().getArch() == llvm::Triple::systemz) { + // At the moment we always produce z10 code. + CmdArgs.push_back("-march=z10"); } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, @@ -5687,16 +5884,20 @@ static bool hasMipsN32ABIArg(const ArgList &Args) { return A && (A->getValue() == StringRef("n32")); } -void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { +void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { const toolchains::Linux& ToolChain = static_cast<const toolchains::Linux&>(getToolChain()); const Driver &D = ToolChain.getDriver(); const bool isAndroid = ToolChain.getTriple().getEnvironment() == llvm::Triple::Android; + SanitizerArgs Sanitize(getToolChain(), Args); + const bool IsPIE = + !Args.hasArg(options::OPT_shared) && + (Args.hasArg(options::OPT_pie) || Sanitize.hasZeroBaseShadow()); ArgStringList CmdArgs; @@ -5711,7 +5912,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - if (Args.hasArg(options::OPT_pie) && !Args.hasArg(options::OPT_shared)) + if (IsPIE) CmdArgs.push_back("-pie"); if (Args.hasArg(options::OPT_rdynamic)) @@ -5757,6 +5958,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("elf64ltsmip"); } + else if (ToolChain.getArch() == llvm::Triple::systemz) + CmdArgs.push_back("elf64_s390"); else CmdArgs.push_back("elf_x86_64"); @@ -5803,7 +6006,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, } else if (ToolChain.getArch() == llvm::Triple::ppc) CmdArgs.push_back("/lib/ld.so.1"); - else if (ToolChain.getArch() == llvm::Triple::ppc64) + else if (ToolChain.getArch() == llvm::Triple::ppc64 || + ToolChain.getArch() == llvm::Triple::systemz) CmdArgs.push_back("/lib64/ld64.so.1"); else CmdArgs.push_back("/lib64/ld-linux-x86-64.so.2"); @@ -5817,7 +6021,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!isAndroid) { const char *crt1 = NULL; if (!Args.hasArg(options::OPT_shared)){ - if (Args.hasArg(options::OPT_pie)) + if (IsPIE) crt1 = "Scrt1.o"; else crt1 = "crt1.o"; @@ -5833,7 +6037,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; else if (Args.hasArg(options::OPT_shared)) crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; - else if (Args.hasArg(options::OPT_pie)) + else if (IsPIE) crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; else crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o"; @@ -5884,11 +6088,11 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); - SanitizerArgs Sanitize(D, Args); - // Call these before we add the C++ ABI library. if (Sanitize.needsUbsanRt()) - addUbsanRTLinux(getToolChain(), Args, CmdArgs); + addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX, + Sanitize.needsAsanRt() || Sanitize.needsTsanRt() || + Sanitize.needsMsanRt()); if (Sanitize.needsAsanRt()) addAsanRTLinux(getToolChain(), Args, CmdArgs); if (Sanitize.needsTsanRt()) @@ -5941,7 +6145,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *crtend; if (Args.hasArg(options::OPT_shared)) crtend = isAndroid ? "crtend_so.o" : "crtendS.o"; - else if (Args.hasArg(options::OPT_pie)) + else if (IsPIE) crtend = isAndroid ? "crtend_android.o" : "crtendS.o"; else crtend = isAndroid ? "crtend_android.o" : "crtend.o"; @@ -6073,21 +6277,29 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + bool UseGCC47 = false; const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; + if (llvm::sys::fs::exists("/usr/lib/gcc47", UseGCC47)) + UseGCC47 = false; + if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-Bshareable"); else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld-elf.so.2"); } + CmdArgs.push_back("--hash-style=both"); } // When building 32-bit code on DragonFly/pc64, we have to explicitly @@ -6107,18 +6319,26 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); - } else { - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back(Args.MakeArgString( + getToolChain().GetFilePath("gcrt1.o"))); + else { + if (Args.hasArg(options::OPT_pie)) + CmdArgs.push_back(Args.MakeArgString( + getToolChain().GetFilePath("Scrt1.o"))); + else + CmdArgs.push_back(Args.MakeArgString( + getToolChain().GetFilePath("crt1.o"))); + } } + CmdArgs.push_back(Args.MakeArgString( + getToolChain().GetFilePath("crti.o"))); + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + CmdArgs.push_back(Args.MakeArgString( + getToolChain().GetFilePath("crtbeginS.o"))); + else + CmdArgs.push_back(Args.MakeArgString( + getToolChain().GetFilePath("crtbegin.o"))); } Args.AddAllArgs(CmdArgs, options::OPT_L); @@ -6131,20 +6351,19 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, !Args.hasArg(options::OPT_nodefaultlibs)) { // FIXME: GCC passes on -lgcc, -lgcc_pic and a whole lot of // rpaths - CmdArgs.push_back("-L/usr/lib/gcc41"); + if (UseGCC47) + CmdArgs.push_back("-L/usr/lib/gcc47"); + else + CmdArgs.push_back("-L/usr/lib/gcc44"); if (!Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-rpath"); - CmdArgs.push_back("/usr/lib/gcc41"); - - CmdArgs.push_back("-rpath-link"); - CmdArgs.push_back("/usr/lib/gcc41"); - - CmdArgs.push_back("-rpath"); - CmdArgs.push_back("/usr/lib"); - - CmdArgs.push_back("-rpath-link"); - CmdArgs.push_back("/usr/lib"); + if (UseGCC47) { + CmdArgs.push_back("-rpath"); + CmdArgs.push_back("/usr/lib/gcc47"); + } else { + CmdArgs.push_back("-rpath"); + CmdArgs.push_back("/usr/lib/gcc44"); + } } if (D.CCCIsCXX) { @@ -6152,13 +6371,6 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lm"); } - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-lgcc_pic"); - } else { - CmdArgs.push_back("-lgcc"); - } - - if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); @@ -6166,23 +6378,42 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lc"); } - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-lgcc_pic"); + if (UseGCC47) { + if (Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_static_libgcc)) { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("-lgcc_eh"); + } else { + if (Args.hasArg(options::OPT_shared_libgcc)) { + CmdArgs.push_back("-lgcc_pic"); + if (!Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("-lgcc"); + } else { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lgcc_pic"); + CmdArgs.push_back("--no-as-needed"); + } + } } else { - CmdArgs.push_back("-lgcc"); + if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-lgcc_pic"); + } else { + CmdArgs.push_back("-lgcc"); + } } } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath("crtend.o"))); + getToolChain().GetFilePath("crtendS.o"))); else CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath("crtendS.o"))); + getToolChain().GetFilePath("crtend.o"))); CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath("crtn.o"))); + getToolChain().GetFilePath("crtn.o"))); } addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index 846c834034..d6471716e6 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -51,6 +51,7 @@ namespace tools { bool KernelOrKext) const; void AddMIPSTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; void AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; + void AddR600TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; void AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; void AddHexagonTargetArgs (const ArgList &Args, ArgStringList &CmdArgs) const; @@ -427,12 +428,11 @@ namespace netbsd { }; } // end namespace netbsd - /// linux -- Directly call GNU Binutils assembler and linker -namespace linuxtools { + /// Directly call GNU Binutils' assembler and linker. +namespace gnutools { class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { public: - Assemble(const ToolChain &TC) : Tool("linux::Assemble", "assembler", - TC) {} + Assemble(const ToolChain &TC) : Tool("GNU::Assemble", "assembler", TC) {} virtual bool hasIntegratedCPP() const { return false; } @@ -444,7 +444,7 @@ namespace linuxtools { }; class LLVM_LIBRARY_VISIBILITY Link : public Tool { public: - Link(const ToolChain &TC) : Tool("linux::Link", "linker", TC) {} + Link(const ToolChain &TC) : Tool("GNU::Link", "linker", TC) {} virtual bool hasIntegratedCPP() const { return false; } virtual bool isLinkJob() const { return true; } diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 9665095b00..7d22596a17 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -87,7 +87,7 @@ bool types::isAcceptedByClang(ID Id) { case TY_ObjCHeader: case TY_PP_ObjCHeader: case TY_CXXHeader: case TY_PP_CXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: - case TY_AST: + case TY_AST: case TY_ModuleFile: case TY_LLVM_IR: case TY_LLVM_BC: return true; } @@ -164,6 +164,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) { .Case("F90", TY_Fortran) .Case("F95", TY_Fortran) .Case("mii", TY_PP_ObjCXX) + .Case("pcm", TY_ModuleFile) .Default(TY_INVALID); } diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp index e7ab4ced87..622c49296d 100644 --- a/lib/Driver/WindowsToolChain.cpp +++ b/lib/Driver/WindowsToolChain.cpp @@ -14,6 +14,7 @@ #include "clang/Driver/ArgList.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" @@ -31,48 +32,20 @@ using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang; -Windows::Windows(const Driver &D, const llvm::Triple& Triple) - : ToolChain(D, Triple) { +Windows::Windows(const Driver &D, const llvm::Triple& Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) { } -Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::InputClass: - case Action::BindArchClass: - case Action::LipoJobClass: - case Action::DsymutilJobClass: - case Action::VerifyJobClass: - case Action::PreprocessJobClass: - case Action::PrecompileJobClass: - case Action::AnalyzeJobClass: - case Action::MigrateJobClass: - case Action::CompileJobClass: - T = new tools::Clang(*this); break; - case Action::AssembleJobClass: - if (!UseIntegratedAs && getTriple().getEnvironment() == llvm::Triple::MachO) - T = new tools::darwin::Assemble(*this); - else - T = new tools::ClangAs(*this); - break; - case Action::LinkJobClass: - T = new tools::visualstudio::Link(*this); break; - } - } +Tool *Windows::buildLinker() const { + return new tools::visualstudio::Link(*this); +} - return *T; +Tool *Windows::buildAssembler() const { + if (getTriple().getEnvironment() == llvm::Triple::MachO) + return new tools::darwin::Assemble(*this); + getDriver().Diag(clang::diag::err_no_external_windows_assembler); + return NULL; } bool Windows::IsIntegratedAssemblerDefault() const { @@ -87,6 +60,10 @@ bool Windows::isPICDefault() const { return getArch() == llvm::Triple::x86_64; } +bool Windows::isPIEDefault() const { + return false; +} + bool Windows::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64; } diff --git a/lib/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp index dd99ca9280..34b5e62333 100644 --- a/lib/Edit/EditedSource.cpp +++ b/lib/Edit/EditedSource.cpp @@ -188,6 +188,8 @@ void EditedSource::commitRemove(SourceLocation OrigLoc, unsigned diff = EndOffs.getOffset() - TopEnd.getOffset(); TopEnd = EndOffs; TopFA->RemoveLen += diff; + if (B == BeginOffs) + TopFA->Text = StringRef(); ++I; } diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp new file mode 100644 index 0000000000..3e2e0ce7cf --- /dev/null +++ b/lib/Format/BreakableToken.cpp @@ -0,0 +1,179 @@ +//===--- BreakableToken.cpp - Format C++ code -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Contains implementation of BreakableToken class and classes derived +/// from it. +/// +//===----------------------------------------------------------------------===// + +#include "BreakableToken.h" +#include "llvm/ADT/STLExtras.h" +#include <algorithm> + +namespace clang { +namespace format { + +BreakableToken::Split BreakableComment::getSplit(unsigned LineIndex, + unsigned TailOffset, + unsigned ColumnLimit) const { + StringRef Text = getLine(LineIndex).substr(TailOffset); + unsigned ContentStartColumn = getContentStartColumn(LineIndex, TailOffset); + if (ColumnLimit <= ContentStartColumn + 1) + return Split(StringRef::npos, 0); + + unsigned MaxSplit = ColumnLimit - ContentStartColumn + 1; + StringRef::size_type SpaceOffset = Text.rfind(' ', MaxSplit); + if (SpaceOffset == StringRef::npos || + Text.find_last_not_of(' ', SpaceOffset) == StringRef::npos) { + SpaceOffset = Text.find(' ', MaxSplit); + } + if (SpaceOffset != StringRef::npos && SpaceOffset != 0) { + StringRef BeforeCut = Text.substr(0, SpaceOffset).rtrim(); + StringRef AfterCut = Text.substr(SpaceOffset).ltrim(); + return BreakableToken::Split(BeforeCut.size(), + AfterCut.begin() - BeforeCut.end()); + } + return BreakableToken::Split(StringRef::npos, 0); +} + +void BreakableComment::insertBreak(unsigned LineIndex, unsigned TailOffset, + Split Split, bool InPPDirective, + WhitespaceManager &Whitespaces) { + StringRef Text = getLine(LineIndex).substr(TailOffset); + StringRef AdditionalPrefix = Decoration; + if (Text.size() == Split.first + Split.second) { + // For all but the last line handle trailing space in trimLine. + if (LineIndex < Lines.size() - 1) + return; + // For the last line we need to break before "*/", but not to add "* ". + AdditionalPrefix = ""; + } + + unsigned WhitespaceStartColumn = + getContentStartColumn(LineIndex, TailOffset) + Split.first; + unsigned BreakOffset = Text.data() - TokenText.data() + Split.first; + unsigned CharsToRemove = Split.second; + Whitespaces.breakToken(Tok, BreakOffset, CharsToRemove, "", AdditionalPrefix, + InPPDirective, IndentAtLineBreak, + WhitespaceStartColumn); +} + +BreakableBlockComment::BreakableBlockComment(const SourceManager &SourceMgr, + const AnnotatedToken &Token, + unsigned StartColumn) + : BreakableComment(SourceMgr, Token.FormatTok, StartColumn + 2) { + assert(TokenText.startswith("/*") && TokenText.endswith("*/")); + + OriginalStartColumn = + SourceMgr.getSpellingColumnNumber(Tok.getStartOfNonWhitespace()) - 1; + + TokenText.substr(2, TokenText.size() - 4).split(Lines, "\n"); + + bool NeedsStar = true; + CommonPrefixLength = UINT_MAX; + if (Lines.size() == 1) { + if (Token.Parent == 0) { + // Standalone block comments will be aligned and prefixed with *s. + CommonPrefixLength = OriginalStartColumn + 1; + } else { + // Trailing comments can start on arbitrary column, and available + // horizontal space can be too small to align consecutive lines with + // the first one. We could, probably, align them to current + // indentation level, but now we just wrap them without indentation + // and stars. + CommonPrefixLength = 0; + NeedsStar = false; + } + } else { + for (size_t i = 1; i < Lines.size(); ++i) { + size_t FirstNonWhitespace = Lines[i].find_first_not_of(" "); + if (FirstNonWhitespace != StringRef::npos) { + NeedsStar = NeedsStar && (Lines[i][FirstNonWhitespace] == '*'); + CommonPrefixLength = + std::min<unsigned>(CommonPrefixLength, FirstNonWhitespace); + } + } + } + if (CommonPrefixLength == UINT_MAX) + CommonPrefixLength = 0; + + Decoration = NeedsStar ? "* " : ""; + + IndentAtLineBreak = + std::max<int>(StartColumn - OriginalStartColumn + CommonPrefixLength, 0); +} + +void BreakableBlockComment::alignLines(WhitespaceManager &Whitespaces) { + SourceLocation TokenLoc = Tok.getStartOfNonWhitespace(); + int IndentDelta = (StartColumn - 2) - OriginalStartColumn; + if (IndentDelta > 0) { + std::string WhiteSpace(IndentDelta, ' '); + for (size_t i = 1; i < Lines.size(); ++i) { + Whitespaces.addReplacement( + TokenLoc.getLocWithOffset(Lines[i].data() - TokenText.data()), 0, + WhiteSpace); + } + } else if (IndentDelta < 0) { + std::string WhiteSpace(-IndentDelta, ' '); + // Check that the line is indented enough. + for (size_t i = 1; i < Lines.size(); ++i) { + if (!Lines[i].startswith(WhiteSpace)) + return; + } + for (size_t i = 1; i < Lines.size(); ++i) { + Whitespaces.addReplacement( + TokenLoc.getLocWithOffset(Lines[i].data() - TokenText.data()), + -IndentDelta, ""); + } + } + + for (unsigned i = 1; i < Lines.size(); ++i) + Lines[i] = Lines[i].substr(CommonPrefixLength + Decoration.size()); +} + +void BreakableBlockComment::trimLine(unsigned LineIndex, unsigned TailOffset, + unsigned InPPDirective, + WhitespaceManager &Whitespaces) { + if (LineIndex == Lines.size() - 1) + return; + StringRef Text = Lines[LineIndex].substr(TailOffset); + if (!Text.endswith(" ") && !InPPDirective) + return; + + StringRef TrimmedLine = Text.rtrim(); + unsigned WhitespaceStartColumn = + getLineLengthAfterSplit(LineIndex, TailOffset); + unsigned BreakOffset = TrimmedLine.end() - TokenText.data(); + unsigned CharsToRemove = Text.size() - TrimmedLine.size() + 1; + Whitespaces.breakToken(Tok, BreakOffset, CharsToRemove, "", "", InPPDirective, + 0, WhitespaceStartColumn); +} + +BreakableLineComment::BreakableLineComment(const SourceManager &SourceMgr, + const AnnotatedToken &Token, + unsigned StartColumn) + : BreakableComment(SourceMgr, Token.FormatTok, StartColumn) { + assert(TokenText.startswith("//")); + Decoration = getLineCommentPrefix(TokenText); + Lines.push_back(TokenText.substr(Decoration.size())); + IndentAtLineBreak = StartColumn; + this->StartColumn += Decoration.size(); // Start column of the contents. +} + +StringRef BreakableLineComment::getLineCommentPrefix(StringRef Comment) { + const char *KnownPrefixes[] = { "/// ", "///", "// ", "//" }; + for (size_t i = 0; i < llvm::array_lengthof(KnownPrefixes); ++i) + if (Comment.startswith(KnownPrefixes[i])) + return KnownPrefixes[i]; + return ""; +} + +} // namespace format +} // namespace clang diff --git a/lib/Format/BreakableToken.h b/lib/Format/BreakableToken.h new file mode 100644 index 0000000000..c1303183d3 --- /dev/null +++ b/lib/Format/BreakableToken.h @@ -0,0 +1,240 @@ +//===--- BreakableToken.h - Format C++ code -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Declares BreakableToken, BreakableStringLiteral, and +/// BreakableBlockComment classes, that contain token type-specific logic to +/// break long lines in tokens. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FORMAT_BREAKABLETOKEN_H +#define LLVM_CLANG_FORMAT_BREAKABLETOKEN_H + +#include "TokenAnnotator.h" +#include "WhitespaceManager.h" +#include <utility> + +namespace clang { +namespace format { + +class BreakableToken { +public: + BreakableToken(const SourceManager &SourceMgr, const FormatToken &Tok, + unsigned StartColumn) + : Tok(Tok), StartColumn(StartColumn), + TokenText(SourceMgr.getCharacterData(Tok.getStartOfNonWhitespace()), + Tok.TokenLength) {} + virtual ~BreakableToken() {} + virtual unsigned getLineCount() const = 0; + virtual unsigned getLineSize(unsigned Index) const = 0; + virtual unsigned getLineLengthAfterSplit(unsigned LineIndex, + unsigned TailOffset) const = 0; + + // Contains starting character index and length of split. + typedef std::pair<StringRef::size_type, unsigned> Split; + virtual Split getSplit(unsigned LineIndex, unsigned TailOffset, + unsigned ColumnLimit) const = 0; + virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, + bool InPPDirective, + WhitespaceManager &Whitespaces) = 0; + virtual void trimLine(unsigned LineIndex, unsigned TailOffset, + unsigned InPPDirective, + WhitespaceManager &Whitespaces) {} +protected: + const FormatToken &Tok; + unsigned StartColumn; + StringRef TokenText; +}; + +class BreakableStringLiteral : public BreakableToken { +public: + BreakableStringLiteral(const SourceManager &SourceMgr, const FormatToken &Tok, + unsigned StartColumn) + : BreakableToken(SourceMgr, Tok, StartColumn) { + assert(TokenText.startswith("\"") && TokenText.endswith("\"")); + } + + virtual unsigned getLineCount() const { return 1; } + + virtual unsigned getLineSize(unsigned Index) const { + return Tok.TokenLength - 2; // Should be in sync with getLine + } + + virtual unsigned getLineLengthAfterSplit(unsigned LineIndex, + unsigned TailOffset) const { + return getDecorationLength() + getLine().size() - TailOffset; + } + + virtual Split getSplit(unsigned LineIndex, unsigned TailOffset, + unsigned ColumnLimit) const { + StringRef Text = getLine().substr(TailOffset); + if (ColumnLimit <= getDecorationLength()) + return Split(StringRef::npos, 0); + unsigned MaxSplit = ColumnLimit - getDecorationLength(); + assert(MaxSplit < Text.size()); + StringRef::size_type SpaceOffset = Text.rfind(' ', MaxSplit); + if (SpaceOffset != StringRef::npos && SpaceOffset != 0) + return Split(SpaceOffset + 1, 0); + StringRef::size_type SlashOffset = Text.rfind('/', MaxSplit); + if (SlashOffset != StringRef::npos && SlashOffset != 0) + return Split(SlashOffset + 1, 0); + StringRef::size_type SplitPoint = getStartOfCharacter(Text, MaxSplit); + if (SplitPoint != StringRef::npos && SplitPoint > 1) + // Do not split at 0. + return Split(SplitPoint, 0); + return Split(StringRef::npos, 0); + } + + virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, + bool InPPDirective, WhitespaceManager &Whitespaces) { + unsigned WhitespaceStartColumn = StartColumn + Split.first + 2; + Whitespaces.breakToken(Tok, 1 + TailOffset + Split.first, Split.second, + "\"", "\"", InPPDirective, StartColumn, + WhitespaceStartColumn); + } + +private: + StringRef getLine() const { + // Get string without quotes. + // FIXME: Handle string prefixes. + return TokenText.substr(1, TokenText.size() - 2); + } + + unsigned getDecorationLength() const { return StartColumn + 2; } + + static StringRef::size_type getStartOfCharacter(StringRef Text, + StringRef::size_type Offset) { + StringRef::size_type NextEscape = Text.find('\\'); + while (NextEscape != StringRef::npos && NextEscape < Offset) { + StringRef::size_type SequenceLength = + getEscapeSequenceLength(Text.substr(NextEscape)); + if (Offset < NextEscape + SequenceLength) + return NextEscape; + NextEscape = Text.find('\\', NextEscape + SequenceLength); + } + return Offset; + } + + static unsigned getEscapeSequenceLength(StringRef Text) { + assert(Text[0] == '\\'); + if (Text.size() < 2) + return 1; + + switch (Text[1]) { + case 'u': + return 6; + case 'U': + return 10; + case 'x': + return getHexLength(Text); + default: + if (Text[1] >= '0' && Text[1] <= '7') + return getOctalLength(Text); + return 2; + } + } + + static unsigned getHexLength(StringRef Text) { + unsigned I = 2; // Point after '\x'. + while (I < Text.size() && ((Text[I] >= '0' && Text[I] <= '9') || + (Text[I] >= 'a' && Text[I] <= 'f') || + (Text[I] >= 'A' && Text[I] <= 'F'))) { + ++I; + } + return I; + } + + static unsigned getOctalLength(StringRef Text) { + unsigned I = 1; + while (I < Text.size() && I < 4 && (Text[I] >= '0' && Text[I] <= '7')) { + ++I; + } + return I; + } + +}; + +class BreakableComment : public BreakableToken { +public: + virtual unsigned getLineSize(unsigned Index) const { + return getLine(Index).size(); + } + + virtual unsigned getLineCount() const { return Lines.size(); } + + virtual unsigned getLineLengthAfterSplit(unsigned LineIndex, + unsigned TailOffset) const { + return getContentStartColumn(LineIndex, TailOffset) + + getLine(LineIndex).size() - TailOffset; + } + + virtual Split getSplit(unsigned LineIndex, unsigned TailOffset, + unsigned ColumnLimit) const; + virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, + bool InPPDirective, WhitespaceManager &Whitespaces); + +protected: + BreakableComment(const SourceManager &SourceMgr, const FormatToken &Tok, + unsigned StartColumn) + : BreakableToken(SourceMgr, Tok, StartColumn) {} + + // Get comment lines without /* */, common prefix and trailing whitespace. + // Last line is not trimmed, as it is terminated by */, so its trailing + // whitespace is not really trailing. + StringRef getLine(unsigned Index) const { + return Index < Lines.size() - 1 ? Lines[Index].rtrim() : Lines[Index]; + } + + unsigned getContentStartColumn(unsigned LineIndex, + unsigned TailOffset) const { + return (TailOffset == 0 && LineIndex == 0) + ? StartColumn + : IndentAtLineBreak + Decoration.size(); + } + + unsigned IndentAtLineBreak; + StringRef Decoration; + SmallVector<StringRef, 16> Lines; +}; + +class BreakableBlockComment : public BreakableComment { +public: + BreakableBlockComment(const SourceManager &SourceMgr, + const AnnotatedToken &Token, unsigned StartColumn); + + void alignLines(WhitespaceManager &Whitespaces); + + virtual unsigned getLineLengthAfterSplit(unsigned LineIndex, + unsigned TailOffset) const { + return BreakableComment::getLineLengthAfterSplit(LineIndex, TailOffset) + + (LineIndex + 1 < Lines.size() ? 0 : 2); + } + + virtual void trimLine(unsigned LineIndex, unsigned TailOffset, + unsigned InPPDirective, WhitespaceManager &Whitespaces); + +private: + unsigned OriginalStartColumn; + unsigned CommonPrefixLength; +}; + +class BreakableLineComment : public BreakableComment { +public: + BreakableLineComment(const SourceManager &SourceMgr, + const AnnotatedToken &Token, unsigned StartColumn); + +private: + static StringRef getLineCommentPrefix(StringRef Comment); +}; + +} // namespace format +} // namespace clang + +#endif // LLVM_CLANG_FORMAT_BREAKABLETOKEN_H diff --git a/lib/Format/CMakeLists.txt b/lib/Format/CMakeLists.txt index d8630eeeea..560e38b4bf 100644 --- a/lib/Format/CMakeLists.txt +++ b/lib/Format/CMakeLists.txt @@ -1,9 +1,11 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangFormat + BreakableToken.cpp + Format.cpp TokenAnnotator.cpp UnwrappedLineParser.cpp - Format.cpp + WhitespaceManager.cpp ) add_dependencies(clangFormat diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 0e556fe9b2..a0557f7818 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -15,14 +15,17 @@ #define DEBUG_TYPE "format-formatter" +#include "BreakableToken.h" #include "TokenAnnotator.h" #include "UnwrappedLineParser.h" +#include "WhitespaceManager.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/OperatorPrecedence.h" #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Lex/Lexer.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" #include <queue> @@ -33,56 +36,66 @@ namespace format { FormatStyle getLLVMStyle() { FormatStyle LLVMStyle; - LLVMStyle.ColumnLimit = 80; - LLVMStyle.MaxEmptyLinesToKeep = 1; - LLVMStyle.PointerBindsToType = false; - LLVMStyle.DerivePointerBinding = false; LLVMStyle.AccessModifierOffset = -2; - LLVMStyle.Standard = FormatStyle::LS_Cpp03; - LLVMStyle.IndentCaseLabels = false; - LLVMStyle.SpacesBeforeTrailingComments = 1; - LLVMStyle.BinPackParameters = true; + LLVMStyle.AlignEscapedNewlinesLeft = false; LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; - LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false; LLVMStyle.AllowShortIfStatementsOnASingleLine = false; + LLVMStyle.BinPackParameters = true; + LLVMStyle.ColumnLimit = 80; + LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false; + LLVMStyle.DerivePointerBinding = false; + LLVMStyle.IndentCaseLabels = false; + LLVMStyle.MaxEmptyLinesToKeep = 1; LLVMStyle.ObjCSpaceBeforeProtocolList = true; LLVMStyle.PenaltyExcessCharacter = 1000000; - LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 5; + LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 75; + LLVMStyle.PointerBindsToType = false; + LLVMStyle.SpacesBeforeTrailingComments = 1; + LLVMStyle.Standard = FormatStyle::LS_Cpp03; return LLVMStyle; } FormatStyle getGoogleStyle() { FormatStyle GoogleStyle; - GoogleStyle.ColumnLimit = 80; - GoogleStyle.MaxEmptyLinesToKeep = 1; - GoogleStyle.PointerBindsToType = true; - GoogleStyle.DerivePointerBinding = true; GoogleStyle.AccessModifierOffset = -1; - GoogleStyle.Standard = FormatStyle::LS_Auto; - GoogleStyle.IndentCaseLabels = true; - GoogleStyle.SpacesBeforeTrailingComments = 2; - GoogleStyle.BinPackParameters = true; + GoogleStyle.AlignEscapedNewlinesLeft = true; GoogleStyle.AllowAllParametersOfDeclarationOnNextLine = true; + GoogleStyle.AllowShortIfStatementsOnASingleLine = true; + GoogleStyle.BinPackParameters = true; + GoogleStyle.ColumnLimit = 80; GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true; - GoogleStyle.AllowShortIfStatementsOnASingleLine = false; + GoogleStyle.DerivePointerBinding = true; + GoogleStyle.IndentCaseLabels = true; + GoogleStyle.MaxEmptyLinesToKeep = 1; GoogleStyle.ObjCSpaceBeforeProtocolList = false; GoogleStyle.PenaltyExcessCharacter = 1000000; - GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 100; + GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200; + GoogleStyle.PointerBindsToType = true; + GoogleStyle.SpacesBeforeTrailingComments = 2; + GoogleStyle.Standard = FormatStyle::LS_Auto; return GoogleStyle; } FormatStyle getChromiumStyle() { FormatStyle ChromiumStyle = getGoogleStyle(); ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false; + ChromiumStyle.AllowShortIfStatementsOnASingleLine = false; ChromiumStyle.BinPackParameters = false; ChromiumStyle.Standard = FormatStyle::LS_Cpp03; ChromiumStyle.DerivePointerBinding = false; return ChromiumStyle; } -static bool isTrailingComment(const AnnotatedToken &Tok) { - return Tok.is(tok::comment) && - (Tok.Children.empty() || Tok.Children[0].MustBreakBefore); +FormatStyle getMozillaStyle() { + FormatStyle MozillaStyle = getLLVMStyle(); + MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false; + MozillaStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true; + MozillaStyle.DerivePointerBinding = true; + MozillaStyle.IndentCaseLabels = true; + MozillaStyle.ObjCSpaceBeforeProtocolList = false; + MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200; + MozillaStyle.PointerBindsToType = true; + return MozillaStyle; } // Returns the length of everything up to the first possible line break after @@ -97,184 +110,12 @@ static unsigned getLengthToMatchingParen(const AnnotatedToken &Tok) { return End->TotalLength - Tok.TotalLength + 1; } -/// \brief Manages the whitespaces around tokens and their replacements. -/// -/// This includes special handling for certain constructs, e.g. the alignment of -/// trailing line comments. -class WhitespaceManager { -public: - WhitespaceManager(SourceManager &SourceMgr) : SourceMgr(SourceMgr) {} - - /// \brief Replaces the whitespace in front of \p Tok. Only call once for - /// each \c AnnotatedToken. - void replaceWhitespace(const AnnotatedToken &Tok, unsigned NewLines, - unsigned Spaces, unsigned WhitespaceStartColumn, - const FormatStyle &Style) { - // 2+ newlines mean an empty line separating logic scopes. - if (NewLines >= 2) - alignComments(); - - // Align line comments if they are trailing or if they continue other - // trailing comments. - if (isTrailingComment(Tok)) { - // Remove the comment's trailing whitespace. - if (Tok.FormatTok.Tok.getLength() != Tok.FormatTok.TokenLength) - Replaces.insert(tooling::Replacement( - SourceMgr, Tok.FormatTok.Tok.getLocation().getLocWithOffset( - Tok.FormatTok.TokenLength), - Tok.FormatTok.Tok.getLength() - Tok.FormatTok.TokenLength, "")); - - // Align comment with other comments. - if (Tok.Parent != NULL || !Comments.empty()) { - if (Style.ColumnLimit >= - Spaces + WhitespaceStartColumn + Tok.FormatTok.TokenLength) { - Comments.push_back(StoredComment()); - Comments.back().Tok = Tok.FormatTok; - Comments.back().Spaces = Spaces; - Comments.back().NewLines = NewLines; - if (NewLines == 0) - Comments.back().MinColumn = WhitespaceStartColumn + Spaces; - else - Comments.back().MinColumn = Spaces; - Comments.back().MaxColumn = - Style.ColumnLimit - Tok.FormatTok.TokenLength; - return; - } - } - } - - // If this line does not have a trailing comment, align the stored comments. - if (Tok.Children.empty() && !isTrailingComment(Tok)) - alignComments(); - storeReplacement(Tok.FormatTok, getNewLineText(NewLines, Spaces)); - } - - /// \brief Like \c replaceWhitespace, but additionally adds right-aligned - /// backslashes to escape newlines inside a preprocessor directive. - /// - /// This function and \c replaceWhitespace have the same behavior if - /// \c Newlines == 0. - void replacePPWhitespace(const AnnotatedToken &Tok, unsigned NewLines, - unsigned Spaces, unsigned WhitespaceStartColumn, - const FormatStyle &Style) { - storeReplacement( - Tok.FormatTok, - getNewLineText(NewLines, Spaces, WhitespaceStartColumn, Style)); - } - - /// \brief Inserts a line break into the middle of a token. - /// - /// Will break at \p Offset inside \p Tok, putting \p Prefix before the line - /// break and \p Postfix before the rest of the token starts in the next line. - /// - /// \p InPPDirective, \p Spaces, \p WhitespaceStartColumn and \p Style are - /// used to generate the correct line break. - void breakToken(const AnnotatedToken &Tok, unsigned Offset, StringRef Prefix, - StringRef Postfix, bool InPPDirective, unsigned Spaces, - unsigned WhitespaceStartColumn, const FormatStyle &Style) { - std::string NewLineText; - if (!InPPDirective) - NewLineText = getNewLineText(1, Spaces); - else - NewLineText = getNewLineText(1, Spaces, WhitespaceStartColumn, Style); - std::string ReplacementText = (Prefix + NewLineText + Postfix).str(); - SourceLocation InsertAt = Tok.FormatTok.WhiteSpaceStart - .getLocWithOffset(Tok.FormatTok.WhiteSpaceLength + Offset); - Replaces.insert( - tooling::Replacement(SourceMgr, InsertAt, 0, ReplacementText)); - } - - /// \brief Returns all the \c Replacements created during formatting. - const tooling::Replacements &generateReplacements() { - alignComments(); - return Replaces; - } - -private: - std::string getNewLineText(unsigned NewLines, unsigned Spaces) { - return std::string(NewLines, '\n') + std::string(Spaces, ' '); - } - - std::string - getNewLineText(unsigned NewLines, unsigned Spaces, - unsigned WhitespaceStartColumn, const FormatStyle &Style) { - std::string NewLineText; - if (NewLines > 0) { - unsigned Offset = - std::min<int>(Style.ColumnLimit - 1, WhitespaceStartColumn); - for (unsigned i = 0; i < NewLines; ++i) { - NewLineText += std::string(Style.ColumnLimit - Offset - 1, ' '); - NewLineText += "\\\n"; - Offset = 0; - } - } - return NewLineText + std::string(Spaces, ' '); - } - - /// \brief Structure to store a comment for later layout and alignment. - struct StoredComment { - FormatToken Tok; - unsigned MinColumn; - unsigned MaxColumn; - unsigned NewLines; - unsigned Spaces; - }; - SmallVector<StoredComment, 16> Comments; - typedef SmallVector<StoredComment, 16>::iterator comment_iterator; - - /// \brief Try to align all stashed comments. - void alignComments() { - unsigned MinColumn = 0; - unsigned MaxColumn = UINT_MAX; - comment_iterator Start = Comments.begin(); - for (comment_iterator I = Comments.begin(), E = Comments.end(); I != E; - ++I) { - if (I->MinColumn > MaxColumn || I->MaxColumn < MinColumn) { - alignComments(Start, I, MinColumn); - MinColumn = I->MinColumn; - MaxColumn = I->MaxColumn; - Start = I; - } else { - MinColumn = std::max(MinColumn, I->MinColumn); - MaxColumn = std::min(MaxColumn, I->MaxColumn); - } - } - alignComments(Start, Comments.end(), MinColumn); - Comments.clear(); - } - - /// \brief Put all the comments between \p I and \p E into \p Column. - void alignComments(comment_iterator I, comment_iterator E, unsigned Column) { - while (I != E) { - unsigned Spaces = I->Spaces + Column - I->MinColumn; - storeReplacement(I->Tok, std::string(I->NewLines, '\n') + - std::string(Spaces, ' ')); - ++I; - } - } - - /// \brief Stores \p Text as the replacement for the whitespace in front of - /// \p Tok. - void storeReplacement(const FormatToken &Tok, const std::string Text) { - // Don't create a replacement, if it does not change anything. - if (StringRef(SourceMgr.getCharacterData(Tok.WhiteSpaceStart), - Tok.WhiteSpaceLength) == Text) - return; - - Replaces.insert(tooling::Replacement(SourceMgr, Tok.WhiteSpaceStart, - Tok.WhiteSpaceLength, Text)); - } - - SourceManager &SourceMgr; - tooling::Replacements Replaces; -}; - class UnwrappedLineFormatter { public: UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr, const AnnotatedLine &Line, unsigned FirstIndent, const AnnotatedToken &RootToken, - WhitespaceManager &Whitespaces, bool StructuralError) + WhitespaceManager &Whitespaces) : Style(Style), SourceMgr(SourceMgr), Line(Line), FirstIndent(FirstIndent), RootToken(RootToken), Whitespaces(Whitespaces), Count(0) {} @@ -288,19 +129,14 @@ public: LineState State; State.Column = FirstIndent; State.NextToken = &RootToken; - State.Stack.push_back(ParenState(FirstIndent + 4, FirstIndent, - !Style.BinPackParameters, - /*HasMultiParameterLine=*/ false)); - State.VariablePos = 0; + State.Stack.push_back( + ParenState(FirstIndent, FirstIndent, !Style.BinPackParameters, + /*NoLineBreak=*/ false)); State.LineContainsContinuedForLoopSection = false; State.ParenLevel = 0; State.StartOfStringLiteral = 0; State.StartOfLineLevel = State.ParenLevel; - DEBUG({ - DebugTokenState(*State.NextToken); - }); - // The first token has already been indented and thus consumed. moveStateToNextToken(State, /*DryRun=*/ false); @@ -335,12 +171,13 @@ private: struct ParenState { ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking, - bool HasMultiParameterLine) + bool NoLineBreak) : Indent(Indent), LastSpace(LastSpace), FirstLessLess(0), BreakBeforeClosingBrace(false), QuestionColumn(0), AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), - HasMultiParameterLine(HasMultiParameterLine), ColonPos(0), - StartOfFunctionCall(0) {} + NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0), + NestedNameSpecifierContinuation(0), CallContinuation(0), + VariablePos(0) {} /// \brief The position to which a specific parenthesis level needs to be /// indented. @@ -377,8 +214,8 @@ private: /// \c AvoidBinPacking is \c true). bool BreakBeforeParameter; - /// \brief This context already has a line with more than one parameter. - bool HasMultiParameterLine; + /// \brief Line breaking in this context would break a formatting rule. + bool NoLineBreak; /// \brief The position of the colon in an ObjC method declaration/call. unsigned ColonPos; @@ -386,6 +223,19 @@ private: /// \brief The start of the most recent function in a builder-type call. unsigned StartOfFunctionCall; + /// \brief If a nested name specifier was broken over multiple lines, this + /// contains the start column of the second line. Otherwise 0. + unsigned NestedNameSpecifierContinuation; + + /// \brief If a call expression was broken over multiple lines, this + /// contains the start column of the second line. Otherwise 0. + unsigned CallContinuation; + + /// \brief The column of the first variable name in a variable declaration. + /// + /// Used to align further variables if necessary. + unsigned VariablePos; + bool operator<(const ParenState &Other) const { if (Indent != Other.Indent) return Indent < Other.Indent; @@ -401,12 +251,20 @@ private: return AvoidBinPacking; if (BreakBeforeParameter != Other.BreakBeforeParameter) return BreakBeforeParameter; - if (HasMultiParameterLine != Other.HasMultiParameterLine) - return HasMultiParameterLine; + if (NoLineBreak != Other.NoLineBreak) + return NoLineBreak; if (ColonPos != Other.ColonPos) return ColonPos < Other.ColonPos; if (StartOfFunctionCall != Other.StartOfFunctionCall) return StartOfFunctionCall < Other.StartOfFunctionCall; + if (NestedNameSpecifierContinuation != + Other.NestedNameSpecifierContinuation) + return NestedNameSpecifierContinuation < + Other.NestedNameSpecifierContinuation; + if (CallContinuation != Other.CallContinuation) + return CallContinuation < Other.CallContinuation; + if (VariablePos != Other.VariablePos) + return VariablePos < Other.VariablePos; return false; } }; @@ -421,11 +279,6 @@ private: /// \brief The token that needs to be next formatted. const AnnotatedToken *NextToken; - /// \brief The column of the first variable name in a variable declaration. - /// - /// Used to align further variables if necessary. - unsigned VariablePos; - /// \brief \c true if this line contains a continued for-loop section. bool LineContainsContinuedForLoopSection; @@ -449,8 +302,6 @@ private: return NextToken < Other.NextToken; if (Column != Other.Column) return Column < Other.Column; - if (VariablePos != Other.VariablePos) - return VariablePos < Other.VariablePos; if (LineContainsContinuedForLoopSection != Other.LineContainsContinuedForLoopSection) return LineContainsContinuedForLoopSection; @@ -475,9 +326,8 @@ private: unsigned addTokenToState(bool Newline, bool DryRun, LineState &State) { const AnnotatedToken &Current = *State.NextToken; const AnnotatedToken &Previous = *State.NextToken->Parent; - assert(State.Stack.size()); - if (Current.Type == TT_ImplicitStringLiteral) { + if (State.Stack.size() == 0 || Current.Type == TT_ImplicitStringLiteral) { State.Column += State.NextToken->FormatTok.WhiteSpaceLength + State.NextToken->FormatTok.TokenLength; if (State.NextToken->Children.empty()) @@ -487,6 +337,9 @@ private: return 0; } + // If we are continuing an expression, we want to indent an extra 4 spaces. + unsigned ContinuationIndent = + std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) + 4; if (Newline) { unsigned WhitespaceStartColumn = State.Column; if (Current.is(tok::r_brace)) { @@ -498,24 +351,29 @@ private: } else if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess != 0) { State.Column = State.Stack.back().FirstLessLess; - } else if (State.ParenLevel != 0 && - (Previous.is(tok::equal) || Previous.is(tok::coloncolon) || - Current.is(tok::period) || Current.is(tok::arrow) || - Current.is(tok::question))) { - // Indent and extra 4 spaces after if we know the current expression is - // continued. Don't do that on the top level, as we already indent 4 - // there. - State.Column = std::max(State.Stack.back().LastSpace, - State.Stack.back().Indent) + 4; + } else if (Previous.is(tok::coloncolon)) { + if (State.Stack.back().NestedNameSpecifierContinuation == 0) { + State.Column = ContinuationIndent; + State.Stack.back().NestedNameSpecifierContinuation = State.Column; + } else { + State.Column = State.Stack.back().NestedNameSpecifierContinuation; + } + } else if (Current.isOneOf(tok::period, tok::arrow)) { + if (State.Stack.back().CallContinuation == 0) { + State.Column = ContinuationIndent; + State.Stack.back().CallContinuation = State.Column; + } else { + State.Column = State.Stack.back().CallContinuation; + } } else if (Current.Type == TT_ConditionalExpr) { State.Column = State.Stack.back().QuestionColumn; - } else if (Previous.is(tok::comma) && State.VariablePos != 0 && - ((RootToken.is(tok::kw_for) && State.ParenLevel == 1) || - State.ParenLevel == 0)) { - State.Column = State.VariablePos; + } else if (Previous.is(tok::comma) && + State.Stack.back().VariablePos != 0) { + State.Column = State.Stack.back().VariablePos; } else if (Previous.ClosesTemplateDeclaration || - (Current.Type == TT_StartOfName && State.ParenLevel == 0)) { - State.Column = State.Stack.back().Indent - 4; + (Current.Type == TT_StartOfName && State.ParenLevel == 0 && + Line.StartsDefinition)) { + State.Column = State.Stack.back().Indent; } else if (Current.Type == TT_ObjCSelectorName) { if (State.Stack.back().ColonPos > Current.FormatTok.TokenLength) { State.Column = @@ -525,16 +383,20 @@ private: State.Stack.back().ColonPos = State.Column + Current.FormatTok.TokenLength; } - } else if (Previous.Type == TT_ObjCMethodExpr || - Current.Type == TT_StartOfName) { - State.Column = State.Stack.back().Indent + 4; + } else if (Current.Type == TT_StartOfName || Previous.is(tok::equal) || + Previous.Type == TT_ObjCMethodExpr) { + State.Column = ContinuationIndent; } else { State.Column = State.Stack.back().Indent; + // Ensure that we fall back to indenting 4 spaces instead of just + // flushing continuations left. + if (State.Column == FirstIndent) + State.Column += 4; } if (Current.is(tok::question)) State.Stack.back().BreakBeforeParameter = true; - if ((Previous.is(tok::comma) || Previous.is(tok::semi)) && + if (Previous.isOneOf(tok::comma, tok::semi) && !State.Stack.back().AvoidBinPacking) State.Stack.back().BreakBeforeParameter = false; @@ -546,23 +408,23 @@ private: Style.MaxEmptyLinesToKeep + 1)); if (!Line.InPPDirective) Whitespaces.replaceWhitespace(Current, NewLines, State.Column, - WhitespaceStartColumn, Style); + WhitespaceStartColumn); else Whitespaces.replacePPWhitespace(Current, NewLines, State.Column, - WhitespaceStartColumn, Style); + WhitespaceStartColumn); } State.Stack.back().LastSpace = State.Column; State.StartOfLineLevel = State.ParenLevel; - if (Current.is(tok::colon) && Current.Type != TT_ConditionalExpr) - State.Stack.back().Indent += 2; // Any break on this level means that the parent level has been broken // and we need to avoid bin packing there. for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) { State.Stack[i].BreakBeforeParameter = true; } - if (Current.is(tok::period) || Current.is(tok::arrow)) + const AnnotatedToken *TokenBefore = Current.getPreviousNoneComment(); + if (TokenBefore && !TokenBefore->isOneOf(tok::comma, tok::semi) && + !TokenBefore->opensScope()) State.Stack.back().BreakBeforeParameter = true; // If we break after {, we should also break before the corresponding }. @@ -578,15 +440,27 @@ private: State.Stack.back().BreakBeforeParameter = true; } } else { - // FIXME: Put VariablePos into ParenState and remove second part of if(). if (Current.is(tok::equal) && - (RootToken.is(tok::kw_for) || State.ParenLevel == 0)) - State.VariablePos = State.Column - Previous.FormatTok.TokenLength; + (RootToken.is(tok::kw_for) || State.ParenLevel == 0) && + State.Stack.back().VariablePos == 0) { + State.Stack.back().VariablePos = State.Column; + // Move over * and & if they are bound to the variable name. + const AnnotatedToken *Tok = &Previous; + while (Tok && + State.Stack.back().VariablePos >= Tok->FormatTok.TokenLength) { + State.Stack.back().VariablePos -= Tok->FormatTok.TokenLength; + if (Tok->SpacesRequiredBefore != 0) + break; + Tok = Tok->Parent; + } + if (Previous.PartOfMultiVariableDeclStmt) + State.Stack.back().LastSpace = State.Stack.back().VariablePos; + } unsigned Spaces = State.NextToken->SpacesRequiredBefore; if (!DryRun) - Whitespaces.replaceWhitespace(Current, 0, Spaces, State.Column, Style); + Whitespaces.replaceWhitespace(Current, 0, Spaces, State.Column); if (Current.Type == TT_ObjCSelectorName && State.Stack.back().ColonPos == 0) { @@ -599,20 +473,19 @@ private: State.Column + Spaces + Current.FormatTok.TokenLength; } - if (Current.Type != TT_LineComment && - (Previous.is(tok::l_paren) || Previous.is(tok::l_brace) || - State.NextToken->Parent->Type == TT_TemplateOpener)) + if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr && + Current.Type != TT_LineComment) State.Stack.back().Indent = State.Column + Spaces; - if (Previous.is(tok::comma) && !isTrailingComment(Current)) - State.Stack.back().HasMultiParameterLine = true; + if (Previous.is(tok::comma) && !Current.isTrailingComment() && + State.Stack.back().AvoidBinPacking) + State.Stack.back().NoLineBreak = true; State.Column += Spaces; - if (Current.is(tok::l_paren) && Previous.is(tok::kw_if)) + if (Current.is(tok::l_paren) && Previous.isOneOf(tok::kw_if, tok::kw_for)) // Treat the condition inside an if as if it was a second function // parameter, i.e. let nested calls have an indent of 4. State.Stack.back().LastSpace = State.Column + 1; // 1 is length of "(". - else if (Previous.is(tok::comma) && State.ParenLevel != 0) - // Top-level spaces are exempt as that mostly leads to better results. + else if (Previous.is(tok::comma)) State.Stack.back().LastSpace = State.Column; else if ((Previous.Type == TT_BinaryOperator || Previous.Type == TT_ConditionalExpr || @@ -621,10 +494,7 @@ private: State.Stack.back().LastSpace = State.Column; else if (Previous.Type == TT_InheritanceColon) State.Stack.back().Indent = State.Column; - else if (Previous.ParameterCount > 1 && - (Previous.is(tok::l_paren) || Previous.is(tok::l_square) || - Previous.is(tok::l_brace) || - Previous.Type == TT_TemplateOpener)) + else if (Previous.opensScope() && Previous.ParameterCount > 1) // If this function has multiple parameters, indent nested calls from // the start of the first parameter. State.Stack.back().LastSpace = State.Column; @@ -645,29 +515,60 @@ private: State.Stack.back().FirstLessLess = State.Column; if (Current.is(tok::question)) State.Stack.back().QuestionColumn = State.Column; - if ((Current.is(tok::period) || Current.is(tok::arrow)) && + if (Current.isOneOf(tok::period, tok::arrow) && Line.Type == LT_BuilderTypeCall && State.ParenLevel == 0) State.Stack.back().StartOfFunctionCall = Current.LastInChainOfCalls ? 0 : State.Column; if (Current.Type == TT_CtorInitializerColon) { + State.Stack.back().Indent = State.Column + 2; if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) State.Stack.back().AvoidBinPacking = true; State.Stack.back().BreakBeforeParameter = false; } + // If return returns a binary expression, align after it. + if (Current.is(tok::kw_return) && !Current.FakeLParens.empty()) + State.Stack.back().LastSpace = State.Column + 7; + + // In ObjC method declaration we align on the ":" of parameters, but we need + // to ensure that we indent parameters on subsequent lines by at least 4. + if (Current.Type == TT_ObjCMethodSpecifier) + State.Stack.back().Indent += 4; + // Insert scopes created by fake parenthesis. - for (unsigned i = 0, e = Current.FakeLParens; i != e; ++i) { + const AnnotatedToken *Previous = Current.getPreviousNoneComment(); + // Don't add extra indentation for the first fake parenthesis after + // 'return', assignements or opening <({[. The indentation for these cases + // is special cased. + bool SkipFirstExtraIndent = + Current.is(tok::kw_return) || + (Previous && (Previous->opensScope() || + getPrecedence(*Previous) == prec::Assignment)); + for (SmallVector<prec::Level, 4>::const_reverse_iterator + I = Current.FakeLParens.rbegin(), + E = Current.FakeLParens.rend(); + I != E; ++I) { ParenState NewParenState = State.Stack.back(); - NewParenState.Indent = std::max(State.Column, State.Stack.back().Indent); - NewParenState.BreakBeforeParameter = false; + NewParenState.Indent = + std::max(std::max(State.Column, NewParenState.Indent), + State.Stack.back().LastSpace); + + // Always indent conditional expressions. Never indent expression where + // the 'operator' is ',', ';' or an assignment (i.e. *I <= + // prec::Assignment) as those have different indentation rules. Indent + // other expression, unless the indentation needs to be skipped. + if (*I == prec::Conditional || + (!SkipFirstExtraIndent && *I > prec::Assignment)) + NewParenState.Indent += 4; + if (Previous && !Previous->opensScope()) + NewParenState.BreakBeforeParameter = false; State.Stack.push_back(NewParenState); + SkipFirstExtraIndent = false; } // If we encounter an opening (, [, { or <, we add a level to our stacks to // prepare for the following tokens. - if (Current.is(tok::l_paren) || Current.is(tok::l_square) || - Current.is(tok::l_brace) || - State.NextToken->Type == TT_TemplateOpener) { + if (Current.opensScope()) { unsigned NewIndent; bool AvoidBinPacking; if (Current.is(tok::l_brace)) { @@ -676,12 +577,20 @@ private: } else { NewIndent = 4 + std::max(State.Stack.back().LastSpace, State.Stack.back().StartOfFunctionCall); - AvoidBinPacking = - !Style.BinPackParameters || State.Stack.back().AvoidBinPacking; + AvoidBinPacking = !Style.BinPackParameters; } State.Stack.push_back( ParenState(NewIndent, State.Stack.back().LastSpace, AvoidBinPacking, - State.Stack.back().HasMultiParameterLine)); + State.Stack.back().NoLineBreak)); + + if (Current.NoMoreTokensOnLevel && Current.FakeLParens.empty()) { + // This parenthesis was the last token possibly making use of Indent and + // LastSpace of the next higher ParenLevel. Thus, erase them to acieve + // better memoization results. + State.Stack[State.Stack.size() - 2].Indent = 0; + State.Stack[State.Stack.size() - 2].LastSpace = 0; + } + ++State.ParenLevel; } @@ -695,7 +604,7 @@ private: // If we encounter a closing ), ], } or >, we can remove a level from our // stacks. - if (Current.is(tok::r_paren) || Current.is(tok::r_square) || + if (Current.isOneOf(tok::r_paren, tok::r_square) || (Current.is(tok::r_brace) && State.NextToken != &RootToken) || State.NextToken->Type == TT_TemplateCloser) { State.Stack.pop_back(); @@ -704,7 +613,9 @@ private: // Remove scopes created by fake parenthesis. for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) { + unsigned VariablePos = State.Stack.back().VariablePos; State.Stack.pop_back(); + State.Stack.back().VariablePos = VariablePos; } if (Current.is(tok::string_literal)) { @@ -727,114 +638,73 @@ private: /// it if possible. unsigned breakProtrudingToken(const AnnotatedToken &Current, LineState &State, bool DryRun) { - if (Current.isNot(tok::string_literal)) - return 0; - // Only break up default narrow strings. - if (StringRef(Current.FormatTok.Tok.getLiteralData()).find('"') != 0) + llvm::OwningPtr<BreakableToken> Token; + unsigned StartColumn = State.Column - Current.FormatTok.TokenLength; + if (Current.is(tok::string_literal)) { + // Only break up default narrow strings. + const char *LiteralData = SourceMgr.getCharacterData( + Current.FormatTok.getStartOfNonWhitespace()); + if (!LiteralData || *LiteralData != '"') + return 0; + + Token.reset(new BreakableStringLiteral(SourceMgr, Current.FormatTok, + StartColumn)); + } else if (Current.Type == TT_BlockComment) { + BreakableBlockComment *BBC = + new BreakableBlockComment(SourceMgr, Current, StartColumn); + if (!DryRun) + BBC->alignLines(Whitespaces); + Token.reset(BBC); + } else if (Current.Type == TT_LineComment && + (Current.Parent == NULL || + Current.Parent->Type != TT_ImplicitStringLiteral)) { + Token.reset(new BreakableLineComment(SourceMgr, Current, StartColumn)); + } else { return 0; + } + bool BreakInserted = false; unsigned Penalty = 0; - unsigned TailOffset = 0; - unsigned TailLength = Current.FormatTok.TokenLength; - unsigned StartColumn = State.Column - Current.FormatTok.TokenLength; - unsigned OffsetFromStart = 0; - while (StartColumn + TailLength > getColumnLimit()) { - StringRef Text = StringRef(Current.FormatTok.Tok.getLiteralData() + - TailOffset, TailLength); - if (StartColumn + OffsetFromStart + 1 > getColumnLimit()) - break; - StringRef::size_type SplitPoint = getSplitPoint( - Text, getColumnLimit() - StartColumn - OffsetFromStart - 1); - if (SplitPoint == StringRef::npos) - break; - assert(SplitPoint != 0); - // +2, because 'Text' starts after the opening quotes, and does not - // include the closing quote we need to insert. - unsigned WhitespaceStartColumn = - StartColumn + OffsetFromStart + SplitPoint + 2; - State.Stack.back().LastSpace = StartColumn; + for (unsigned LineIndex = 0; LineIndex < Token->getLineCount(); + ++LineIndex) { + unsigned TailOffset = 0; + unsigned RemainingLength = + Token->getLineLengthAfterSplit(LineIndex, TailOffset); + while (RemainingLength > getColumnLimit()) { + BreakableToken::Split Split = + Token->getSplit(LineIndex, TailOffset, getColumnLimit()); + if (Split.first == StringRef::npos) + break; + assert(Split.first != 0); + unsigned NewRemainingLength = Token->getLineLengthAfterSplit( + LineIndex, TailOffset + Split.first + Split.second); + if (NewRemainingLength >= RemainingLength) + break; + if (!DryRun) { + Token->insertBreak(LineIndex, TailOffset, Split, Line.InPPDirective, + Whitespaces); + } + TailOffset += Split.first + Split.second; + RemainingLength = NewRemainingLength; + Penalty += Style.PenaltyExcessCharacter; + BreakInserted = true; + } + State.Column = RemainingLength; if (!DryRun) { - Whitespaces.breakToken(Current, TailOffset + SplitPoint + 1, "\"", "\"", - Line.InPPDirective, StartColumn, - WhitespaceStartColumn, Style); + Token->trimLine(LineIndex, TailOffset, Line.InPPDirective, Whitespaces); } - TailOffset += SplitPoint + 1; - TailLength -= SplitPoint + 1; - OffsetFromStart = 1; - Penalty += Style.PenaltyExcessCharacter; + } + + if (BreakInserted) { for (unsigned i = 0, e = State.Stack.size(); i != e; ++i) State.Stack[i].BreakBeforeParameter = true; + State.Stack.back().LastSpace = StartColumn; } - State.Column = StartColumn + TailLength; return Penalty; } - StringRef::size_type - getSplitPoint(StringRef Text, StringRef::size_type Offset) { - StringRef::size_type SpaceOffset = Text.rfind(' ', Offset); - if (SpaceOffset != StringRef::npos && SpaceOffset != 0) - return SpaceOffset; - StringRef::size_type SlashOffset = Text.rfind('/', Offset); - if (SlashOffset != StringRef::npos && SlashOffset != 0) - return SlashOffset; - StringRef::size_type Split = getStartOfCharacter(Text, Offset); - if (Split != StringRef::npos && Split > 1) - // Do not split at 0. - return Split - 1; - return StringRef::npos; - } - - StringRef::size_type - getStartOfCharacter(StringRef Text, StringRef::size_type Offset) { - StringRef::size_type NextEscape = Text.find('\\'); - while (NextEscape != StringRef::npos && NextEscape < Offset) { - StringRef::size_type SequenceLength = - getEscapeSequenceLength(Text.substr(NextEscape)); - if (Offset < NextEscape + SequenceLength) - return NextEscape; - NextEscape = Text.find('\\', NextEscape + SequenceLength); - } - return Offset; - } - - unsigned getEscapeSequenceLength(StringRef Text) { - assert(Text[0] == '\\'); - if (Text.size() < 2) - return 1; - - switch (Text[1]) { - case 'u': - return 6; - case 'U': - return 10; - case 'x': - return getHexLength(Text); - default: - if (Text[1] >= '0' && Text[1] <= '7') - return getOctalLength(Text); - return 2; - } - } - - unsigned getHexLength(StringRef Text) { - unsigned I = 2; // Point after '\x'. - while (I < Text.size() && ((Text[I] >= '0' && Text[I] <= '9') || - (Text[I] >= 'a' && Text[I] <= 'f') || - (Text[I] >= 'A' && Text[I] <= 'F'))) { - ++I; - } - return I; - } - - unsigned getOctalLength(StringRef Text) { - unsigned I = 1; - while (I < Text.size() && I < 4 && (Text[I] >= '0' && Text[I] <= '7')) { - ++I; - } - return I; - } - unsigned getColumnLimit() { + // In preprocessor directives reserve two chars for trailing " \" return Style.ColumnLimit - (Line.InPPDirective ? 2 : 0); } @@ -959,20 +829,7 @@ private: !(State.NextToken->is(tok::r_brace) && State.Stack.back().BreakBeforeClosingBrace)) return false; - // This prevents breaks like: - // ... - // SomeParameter, OtherParameter).DoSomething( - // ... - // As they hide "DoSomething" and generally bad for readability. - if (State.NextToken->Parent->is(tok::l_paren) && - State.ParenLevel <= State.StartOfLineLevel) - return false; - // Trying to insert a parameter on a new line if there are already more than - // one parameter on the current line is bin packing. - if (State.Stack.back().HasMultiParameterLine && - State.Stack.back().AvoidBinPacking) - return false; - return true; + return !State.Stack.back().NoLineBreak; } /// \brief Returns \c true, if a line break after \p State is mandatory. @@ -985,12 +842,11 @@ private: if (State.NextToken->Parent->is(tok::semi) && State.LineContainsContinuedForLoopSection) return true; - if ((State.NextToken->Parent->is(tok::comma) || - State.NextToken->Parent->is(tok::semi) || + if ((State.NextToken->Parent->isOneOf(tok::comma, tok::semi) || State.NextToken->is(tok::question) || State.NextToken->Type == TT_ConditionalExpr) && State.Stack.back().BreakBeforeParameter && - !isTrailingComment(*State.NextToken) && + !State.NextToken->isTrailingComment() && State.NextToken->isNot(tok::r_paren) && State.NextToken->isNot(tok::r_brace)) return true; @@ -1004,9 +860,27 @@ private: (State.NextToken->Parent->ClosesTemplateDeclaration && State.ParenLevel == 0))) return true; + if (State.NextToken->Type == TT_InlineASMColon) + return true; + // This prevents breaks like: + // ... + // SomeParameter, OtherParameter).DoSomething( + // ... + // As they hide "DoSomething" and generally bad for readability. + if (State.NextToken->isOneOf(tok::period, tok::arrow) && + getRemainingLength(State) + State.Column > getColumnLimit() && + State.ParenLevel < State.StartOfLineLevel) + return true; return false; } + // Returns the total number of columns required for the remaining tokens. + unsigned getRemainingLength(const LineState &State) { + if (State.NextToken && State.NextToken->Parent) + return Line.Last->TotalLength - State.NextToken->Parent->TotalLength; + return 0; + } + FormatStyle Style; SourceManager &SourceMgr; const AnnotatedLine &Line; @@ -1066,6 +940,11 @@ public: // Now FormatTok is the next non-whitespace token. FormatTok.TokenLength = Text.size(); + if (FormatTok.Tok.is(tok::comment)) { + FormatTok.TrailingWhiteSpaceLength = Text.size() - Text.rtrim().size(); + FormatTok.TokenLength -= FormatTok.TrailingWhiteSpaceLength; + } + // In case the token starts with escaped newlines, we want to // take them into account as whitespace - this pattern is quite frequent // in macro definitions. @@ -1092,11 +971,6 @@ public: GreaterStashed = true; } - // If we reformat comments, we remove trailing whitespace. Update the length - // accordingly. - if (FormatTok.Tok.is(tok::comment)) - FormatTok.TokenLength = Text.rtrim().size(); - return FormatTok; } @@ -1122,51 +996,14 @@ public: SourceManager &SourceMgr, const std::vector<CharSourceRange> &Ranges) : Diag(Diag), Style(Style), Lex(Lex), SourceMgr(SourceMgr), - Whitespaces(SourceMgr), Ranges(Ranges) {} + Whitespaces(SourceMgr, Style), Ranges(Ranges) {} virtual ~Formatter() {} - void deriveLocalStyle() { - unsigned CountBoundToVariable = 0; - unsigned CountBoundToType = 0; - bool HasCpp03IncompatibleFormat = false; - for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { - if (AnnotatedLines[i].First.Children.empty()) - continue; - AnnotatedToken *Tok = &AnnotatedLines[i].First.Children[0]; - while (!Tok->Children.empty()) { - if (Tok->Type == TT_PointerOrReference) { - bool SpacesBefore = Tok->FormatTok.WhiteSpaceLength > 0; - bool SpacesAfter = Tok->Children[0].FormatTok.WhiteSpaceLength > 0; - if (SpacesBefore && !SpacesAfter) - ++CountBoundToVariable; - else if (!SpacesBefore && SpacesAfter) - ++CountBoundToType; - } - - if (Tok->Type == TT_TemplateCloser && - Tok->Parent->Type == TT_TemplateCloser && - Tok->FormatTok.WhiteSpaceLength == 0) - HasCpp03IncompatibleFormat = true; - Tok = &Tok->Children[0]; - } - } - if (Style.DerivePointerBinding) { - if (CountBoundToType > CountBoundToVariable) - Style.PointerBindsToType = true; - else if (CountBoundToType < CountBoundToVariable) - Style.PointerBindsToType = false; - } - if (Style.Standard == FormatStyle::LS_Auto) { - Style.Standard = HasCpp03IncompatibleFormat ? FormatStyle::LS_Cpp11 - : FormatStyle::LS_Cpp03; - } - } - tooling::Replacements format() { LexerBasedFormatTokenSource Tokens(Lex, SourceMgr); UnwrappedLineParser Parser(Diag, Style, Tokens, *this); - StructuralError = Parser.parse(); + bool StructuralError = Parser.parse(); unsigned PreviousEndOfLineColumn = 0; TokenAnnotator Annotator(Style, SourceMgr, Lex, Tokens.getIdentTable().get("in")); @@ -1177,24 +1014,38 @@ public: for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { Annotator.calculateFormattingInformation(AnnotatedLines[i]); } + + // Adapt level to the next line if this is a comment. + // FIXME: Can/should this be done in the UnwrappedLineParser? + const AnnotatedLine *NextNoneCommentLine = NULL; + for (unsigned i = AnnotatedLines.size() - 1; i > 0; --i) { + if (NextNoneCommentLine && AnnotatedLines[i].First.is(tok::comment) && + AnnotatedLines[i].First.Children.empty()) + AnnotatedLines[i].Level = NextNoneCommentLine->Level; + else + NextNoneCommentLine = + AnnotatedLines[i].First.isNot(tok::r_brace) ? &AnnotatedLines[i] + : NULL; + } + std::vector<int> IndentForLevel; bool PreviousLineWasTouched = false; + const AnnotatedToken *PreviousLineLastToken = 0; for (std::vector<AnnotatedLine>::iterator I = AnnotatedLines.begin(), E = AnnotatedLines.end(); I != E; ++I) { const AnnotatedLine &TheLine = *I; + const FormatToken &FirstTok = TheLine.First.FormatTok; int Offset = getIndentOffset(TheLine.First); while (IndentForLevel.size() <= TheLine.Level) IndentForLevel.push_back(-1); IndentForLevel.resize(TheLine.Level + 1); - bool WasMoved = - PreviousLineWasTouched && TheLine.First.FormatTok.NewlinesBefore == 0; + bool WasMoved = PreviousLineWasTouched && FirstTok.NewlinesBefore == 0; if (TheLine.First.is(tok::eof)) { if (PreviousLineWasTouched) { - unsigned NewLines = - std::min(TheLine.First.FormatTok.NewlinesBefore, 1u); + unsigned NewLines = std::min(FirstTok.NewlinesBefore, 1u); Whitespaces.replaceWhitespace(TheLine.First, NewLines, /*Indent*/ 0, - /*WhitespaceStartColumn*/ 0, Style); + /*WhitespaceStartColumn*/ 0); } } else if (TheLine.Type != LT_Invalid && (WasMoved || touchesLine(TheLine))) { @@ -1202,52 +1053,95 @@ public: unsigned Indent = LevelIndent; if (static_cast<int>(Indent) + Offset >= 0) Indent += Offset; - if (!TheLine.First.FormatTok.WhiteSpaceStart.isValid() || - StructuralError) { - Indent = LevelIndent = SourceMgr.getSpellingColumnNumber( - TheLine.First.FormatTok.Tok.getLocation()) - 1; + if (FirstTok.WhiteSpaceStart.isValid() && + // Insert a break even if there is a structural error in case where + // we break apart a line consisting of multiple unwrapped lines. + (FirstTok.NewlinesBefore == 0 || !StructuralError)) { + formatFirstToken(TheLine.First, PreviousLineLastToken, Indent, + TheLine.InPPDirective, PreviousEndOfLineColumn); } else { - formatFirstToken(TheLine.First, Indent, TheLine.InPPDirective, - PreviousEndOfLineColumn); + Indent = LevelIndent = + SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1; } tryFitMultipleLinesInOne(Indent, I, E); UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine, Indent, - TheLine.First, Whitespaces, - StructuralError); + TheLine.First, Whitespaces); PreviousEndOfLineColumn = Formatter.format(I + 1 != E ? &*(I + 1) : NULL); IndentForLevel[TheLine.Level] = LevelIndent; PreviousLineWasTouched = true; } else { - if (TheLine.First.FormatTok.NewlinesBefore > 0 || - TheLine.First.FormatTok.IsFirst) { - unsigned Indent = SourceMgr.getSpellingColumnNumber( - TheLine.First.FormatTok.Tok.getLocation()) - 1; + if (FirstTok.NewlinesBefore > 0 || FirstTok.IsFirst) { + unsigned Indent = + SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1; unsigned LevelIndent = Indent; if (static_cast<int>(LevelIndent) - Offset >= 0) LevelIndent -= Offset; - IndentForLevel[TheLine.Level] = LevelIndent; + if (TheLine.First.isNot(tok::comment)) + IndentForLevel[TheLine.Level] = LevelIndent; // Remove trailing whitespace of the previous line if it was touched. if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine)) - formatFirstToken(TheLine.First, Indent, TheLine.InPPDirective, - PreviousEndOfLineColumn); + formatFirstToken(TheLine.First, PreviousLineLastToken, Indent, + TheLine.InPPDirective, PreviousEndOfLineColumn); } // If we did not reformat this unwrapped line, the column at the end of // the last token is unchanged - thus, we can calculate the end of the // last token. + SourceLocation LastLoc = TheLine.Last->FormatTok.Tok.getLocation(); PreviousEndOfLineColumn = - SourceMgr.getSpellingColumnNumber( - TheLine.Last->FormatTok.Tok.getLocation()) + - Lex.MeasureTokenLength(TheLine.Last->FormatTok.Tok.getLocation(), - SourceMgr, Lex.getLangOpts()) - 1; + SourceMgr.getSpellingColumnNumber(LastLoc) + + Lex.MeasureTokenLength(LastLoc, SourceMgr, Lex.getLangOpts()) - 1; PreviousLineWasTouched = false; + if (TheLine.Last->is(tok::comment)) + Whitespaces.addUntouchableComment(SourceMgr.getSpellingColumnNumber( + TheLine.Last->FormatTok.Tok.getLocation()) - 1); + else + Whitespaces.alignComments(); } + PreviousLineLastToken = I->Last; } return Whitespaces.generateReplacements(); } private: + void deriveLocalStyle() { + unsigned CountBoundToVariable = 0; + unsigned CountBoundToType = 0; + bool HasCpp03IncompatibleFormat = false; + for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { + if (AnnotatedLines[i].First.Children.empty()) + continue; + AnnotatedToken *Tok = &AnnotatedLines[i].First.Children[0]; + while (!Tok->Children.empty()) { + if (Tok->Type == TT_PointerOrReference) { + bool SpacesBefore = Tok->FormatTok.WhiteSpaceLength > 0; + bool SpacesAfter = Tok->Children[0].FormatTok.WhiteSpaceLength > 0; + if (SpacesBefore && !SpacesAfter) + ++CountBoundToVariable; + else if (!SpacesBefore && SpacesAfter) + ++CountBoundToType; + } + + if (Tok->Type == TT_TemplateCloser && + Tok->Parent->Type == TT_TemplateCloser && + Tok->FormatTok.WhiteSpaceLength == 0) + HasCpp03IncompatibleFormat = true; + Tok = &Tok->Children[0]; + } + } + if (Style.DerivePointerBinding) { + if (CountBoundToType > CountBoundToVariable) + Style.PointerBindsToType = true; + else if (CountBoundToType < CountBoundToVariable) + Style.PointerBindsToType = false; + } + if (Style.Standard == FormatStyle::LS_Auto) { + Style.Standard = HasCpp03IncompatibleFormat ? FormatStyle::LS_Cpp11 + : FormatStyle::LS_Cpp03; + } + } + /// \brief Get the indent of \p Level from \p IndentForLevel. /// /// \p IndentForLevel must contain the indent for the level \c l @@ -1266,18 +1160,7 @@ private: /// For example, 'public:' labels in classes are offset by 1 or 2 /// characters to the left from their level. int getIndentOffset(const AnnotatedToken &RootToken) { - bool IsAccessModifier = false; - if (RootToken.is(tok::kw_public) || RootToken.is(tok::kw_protected) || - RootToken.is(tok::kw_private)) - IsAccessModifier = true; - else if (RootToken.is(tok::at) && !RootToken.Children.empty() && - (RootToken.Children[0].isObjCAtKeyword(tok::objc_public) || - RootToken.Children[0].isObjCAtKeyword(tok::objc_protected) || - RootToken.Children[0].isObjCAtKeyword(tok::objc_package) || - RootToken.Children[0].isObjCAtKeyword(tok::objc_private))) - IsAccessModifier = true; - - if (IsAccessModifier) + if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier()) return Style.AccessModifierOffset; return 0; } @@ -1361,15 +1244,11 @@ private: // we're not in a control flow statement and the last token is an opening // brace. AnnotatedLine &Line = *I; - bool AllowedTokens = - Line.First.isNot(tok::kw_if) && Line.First.isNot(tok::kw_while) && - Line.First.isNot(tok::kw_do) && Line.First.isNot(tok::r_brace) && - Line.First.isNot(tok::kw_else) && Line.First.isNot(tok::kw_try) && - Line.First.isNot(tok::kw_catch) && Line.First.isNot(tok::kw_for) && - // This gets rid of all ObjC @ keywords and methods. - Line.First.isNot(tok::at) && Line.First.isNot(tok::minus) && - Line.First.isNot(tok::plus); - if (!AllowedTokens) + if (Line.First.isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::r_brace, + tok::kw_else, tok::kw_try, tok::kw_catch, + tok::kw_for, + // This gets rid of all ObjC @ keywords and methods. + tok::at, tok::minus, tok::plus)) return; AnnotatedToken *Tok = &(I + 1)->First; @@ -1391,7 +1270,7 @@ private: if ((I + 1)->Last->Type == TT_LineComment || Tok->MustBreakBefore) return; do { - if (Tok->is(tok::l_brace) || Tok->is(tok::r_brace)) + if (Tok->isOneOf(tok::l_brace, tok::r_brace)) return; Tok = Tok->Children.empty() ? NULL : &Tok->Children.back(); } while (Tok != NULL); @@ -1424,7 +1303,7 @@ private: } } - bool touchesRanges(const CharSourceRange& Range) { + bool touchesRanges(const CharSourceRange &Range) { for (unsigned i = 0, e = Ranges.size(); i != e; ++i) { if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Ranges[i].getBegin()) && @@ -1459,7 +1338,8 @@ private: /// \brief Add a new line and the required indent before the first Token /// of the \c UnwrappedLine if there was no structural parsing error. /// Returns the indent level of the \c UnwrappedLine. - void formatFirstToken(const AnnotatedToken &RootToken, unsigned Indent, + void formatFirstToken(const AnnotatedToken &RootToken, + const AnnotatedToken *PreviousToken, unsigned Indent, bool InPPDirective, unsigned PreviousEndOfLineColumn) { const FormatToken &Tok = RootToken.FormatTok; @@ -1469,10 +1349,15 @@ private: Newlines = 1; if (!InPPDirective || Tok.HasUnescapedNewline) { - Whitespaces.replaceWhitespace(RootToken, Newlines, Indent, 0, Style); + // Insert extra new line before access specifiers. + if (PreviousToken && PreviousToken->isOneOf(tok::semi, tok::r_brace) && + RootToken.isAccessSpecifier() && Tok.NewlinesBefore == 1) + ++Newlines; + + Whitespaces.replaceWhitespace(RootToken, Newlines, Indent, 0); } else { Whitespaces.replacePPWhitespace(RootToken, Newlines, Indent, - PreviousEndOfLineColumn, Style); + PreviousEndOfLineColumn); } } @@ -1483,12 +1368,12 @@ private: WhitespaceManager Whitespaces; std::vector<CharSourceRange> Ranges; std::vector<AnnotatedLine> AnnotatedLines; - bool StructuralError; }; -tooling::Replacements -reformat(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr, - std::vector<CharSourceRange> Ranges, DiagnosticConsumer *DiagClient) { +tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex, + SourceManager &SourceMgr, + std::vector<CharSourceRange> Ranges, + DiagnosticConsumer *DiagClient) { IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); OwningPtr<DiagnosticConsumer> DiagPrinter; if (DiagClient == 0) { @@ -1508,6 +1393,7 @@ LangOptions getFormattingLangOpts() { LangOptions LangOpts; LangOpts.CPlusPlus = 1; LangOpts.CPlusPlus11 = 1; + LangOpts.LineComment = 1; LangOpts.Bool = 1; LangOpts.ObjC1 = 1; LangOpts.ObjC2 = 1; diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 307607aadd..17abb01d18 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -16,12 +16,13 @@ #include "TokenAnnotator.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" +#include "llvm/Support/Debug.h" namespace clang { namespace format { -static bool isUnaryOperator(const AnnotatedToken &Tok) { - switch (Tok.FormatTok.Tok.getKind()) { +bool AnnotatedToken::isUnaryOperator() const { + switch (FormatTok.Tok.getKind()) { case tok::plus: case tok::plusplus: case tok::minus: @@ -36,39 +37,38 @@ static bool isUnaryOperator(const AnnotatedToken &Tok) { } } -static bool isBinaryOperator(const AnnotatedToken &Tok) { +bool AnnotatedToken::isBinaryOperator() const { // Comma is a binary operator, but does not behave as such wrt. formatting. - return getPrecedence(Tok) > prec::Comma; + return getPrecedence(*this) > prec::Comma; } -// Returns the previous token ignoring comments. -static AnnotatedToken *getPreviousToken(AnnotatedToken &Tok) { - AnnotatedToken *PrevToken = Tok.Parent; - while (PrevToken != NULL && PrevToken->is(tok::comment)) - PrevToken = PrevToken->Parent; - return PrevToken; +bool AnnotatedToken::isTrailingComment() const { + return is(tok::comment) && + (Children.empty() || Children[0].FormatTok.NewlinesBefore > 0); } -static const AnnotatedToken *getPreviousToken(const AnnotatedToken &Tok) { - return getPreviousToken(const_cast<AnnotatedToken &>(Tok)); + +AnnotatedToken *AnnotatedToken::getPreviousNoneComment() const { + AnnotatedToken *Tok = Parent; + while (Tok != NULL && Tok->is(tok::comment)) + Tok = Tok->Parent; + return Tok; } -static bool isTrailingComment(AnnotatedToken *Tok) { - return Tok != NULL && Tok->is(tok::comment) && - (Tok->Children.empty() || - Tok->Children[0].FormatTok.NewlinesBefore > 0); +const AnnotatedToken *AnnotatedToken::getNextNoneComment() const { + const AnnotatedToken *Tok = Children.empty() ? NULL : &Children[0]; + while (Tok != NULL && Tok->is(tok::comment)) + Tok = Tok->Children.empty() ? NULL : &Tok->Children[0]; + return Tok; } -// Returns the next token ignoring comments. -static const AnnotatedToken *getNextToken(const AnnotatedToken &Tok) { - if (Tok.Children.empty()) - return NULL; - const AnnotatedToken *NextToken = &Tok.Children[0]; - while (NextToken->is(tok::comment)) { - if (NextToken->Children.empty()) - return NULL; - NextToken = &NextToken->Children[0]; - } - return NextToken; +bool AnnotatedToken::closesScope() const { + return isOneOf(tok::r_paren, tok::r_brace, tok::r_square) || + Type == TT_TemplateCloser; +} + +bool AnnotatedToken::opensScope() const { + return isOneOf(tok::l_paren, tok::l_brace, tok::l_square) || + Type == TT_TemplateOpener; } /// \brief A parser that gathers additional information about tokens. @@ -81,15 +81,15 @@ public: AnnotatingParser(SourceManager &SourceMgr, Lexer &Lex, AnnotatedLine &Line, IdentifierInfo &Ident_in) : SourceMgr(SourceMgr), Lex(Lex), Line(Line), CurrentToken(&Line.First), - KeywordVirtualFound(false), Ident_in(Ident_in) { - Contexts.push_back(Context(1, /*IsExpression=*/ false)); + KeywordVirtualFound(false), NameFound(false), Ident_in(Ident_in) { + Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/ false)); } private: bool parseAngle() { if (CurrentToken == NULL) return false; - ScopedContextCreator ContextCreator(*this, 10); + ScopedContextCreator ContextCreator(*this, tok::less, 10); AnnotatedToken *Left = CurrentToken->Parent; Contexts.back().IsExpression = false; while (CurrentToken != NULL) { @@ -100,11 +100,9 @@ private: next(); return true; } - if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_square) || - CurrentToken->is(tok::r_brace)) - return false; - if (CurrentToken->is(tok::pipepipe) || CurrentToken->is(tok::ampamp) || - CurrentToken->is(tok::question) || CurrentToken->is(tok::colon)) + if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace, + tok::pipepipe, tok::ampamp, tok::question, + tok::colon)) return false; updateParameterCount(Left, CurrentToken); if (!consumeToken()) @@ -116,7 +114,7 @@ private: bool parseParens(bool LookForDecls = false) { if (CurrentToken == NULL) return false; - ScopedContextCreator ContextCreator(*this, 1); + ScopedContextCreator ContextCreator(*this, tok::l_paren, 1); // FIXME: This is a bit of a hack. Do better. Contexts.back().ColonIsForRangeExpr = @@ -149,7 +147,7 @@ private: AnnotatedToken &Prev = *CurrentToken->Parent; AnnotatedToken &Next = CurrentToken->Children[0]; if (Prev.Parent->is(tok::identifier) && - (Prev.is(tok::star) || Prev.is(tok::amp) || Prev.is(tok::ampamp)) && + Prev.isOneOf(tok::star, tok::amp, tok::ampamp) && CurrentToken->is(tok::identifier) && Next.isNot(tok::equal)) { Prev.Type = TT_BinaryOperator; LookForDecls = false; @@ -157,6 +155,8 @@ private: } if (CurrentToken->is(tok::r_paren)) { + if (CurrentToken->Parent->closesScope()) + CurrentToken->Parent->MatchingParen->NoMoreTokensOnLevel = true; Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; @@ -171,7 +171,7 @@ private: next(); return true; } - if (CurrentToken->is(tok::r_square) || CurrentToken->is(tok::r_brace)) + if (CurrentToken->isOneOf(tok::r_square, tok::r_brace)) return false; updateParameterCount(Left, CurrentToken); if (!consumeToken()) @@ -183,21 +183,22 @@ private: bool parseSquare() { if (!CurrentToken) return false; - ScopedContextCreator ContextCreator(*this, 10); // A '[' could be an index subscript (after an indentifier or after // ')' or ']'), it could be the start of an Objective-C method // expression, or it could the the start of an Objective-C array literal. AnnotatedToken *Left = CurrentToken->Parent; - AnnotatedToken *Parent = getPreviousToken(*Left); - Contexts.back().IsExpression = true; + AnnotatedToken *Parent = Left->getPreviousNoneComment(); bool StartsObjCMethodExpr = - !Parent || Parent->is(tok::colon) || Parent->is(tok::l_square) || - Parent->is(tok::l_paren) || Parent->is(tok::kw_return) || - Parent->is(tok::kw_throw) || isUnaryOperator(*Parent) || - Parent->Type == TT_ObjCForIn || Parent->Type == TT_CastRParen || - getBinOpPrecedence(Parent->FormatTok.Tok.getKind(), true, true) > - prec::Unknown; + Contexts.back().CanBeExpression && + (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren, + tok::kw_return, tok::kw_throw) || + Parent->isUnaryOperator() || Parent->Type == TT_ObjCForIn || + Parent->Type == TT_CastRParen || + getBinOpPrecedence(Parent->FormatTok.Tok.getKind(), true, true) > + prec::Unknown); + ScopedContextCreator ContextCreator(*this, tok::l_square, 10); + Contexts.back().IsExpression = true; bool StartsObjCArrayLiteral = Parent && Parent->is(tok::at); if (StartsObjCMethodExpr) { @@ -234,7 +235,7 @@ private: next(); return true; } - if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_brace)) + if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace)) return false; updateParameterCount(Left, CurrentToken); if (!consumeToken()) @@ -244,24 +245,25 @@ private: } bool parseBrace() { - // Lines are fine to end with '{'. - if (CurrentToken == NULL) - return true; - ScopedContextCreator ContextCreator(*this, 1); - AnnotatedToken *Left = CurrentToken->Parent; - while (CurrentToken != NULL) { - if (CurrentToken->is(tok::r_brace)) { - Left->MatchingParen = CurrentToken; - CurrentToken->MatchingParen = Left; - next(); - return true; + if (CurrentToken != NULL) { + ScopedContextCreator ContextCreator(*this, tok::l_brace, 1); + AnnotatedToken *Left = CurrentToken->Parent; + while (CurrentToken != NULL) { + if (CurrentToken->is(tok::r_brace)) { + Left->MatchingParen = CurrentToken; + CurrentToken->MatchingParen = Left; + next(); + return true; + } + if (CurrentToken->isOneOf(tok::r_paren, tok::r_square)) + return false; + updateParameterCount(Left, CurrentToken); + if (!consumeToken()) + return false; } - if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_square)) - return false; - updateParameterCount(Left, CurrentToken); - if (!consumeToken()) - return false; } + // No closing "}" found, this probably starts a definition. + Line.StartsDefinition = true; return true; } @@ -304,21 +306,21 @@ private: switch (Tok->FormatTok.Tok.getKind()) { case tok::plus: case tok::minus: - // At the start of the line, +/- specific ObjectiveC method - // declarations. - if (Tok->Parent == NULL) + if (Tok->Parent == NULL && Line.MustBeDeclaration) Tok->Type = TT_ObjCMethodSpecifier; break; case tok::colon: + if (Tok->Parent == NULL) + return false; // Colons from ?: are handled in parseConditional(). - if (Tok->Parent->is(tok::r_paren)) { + if (Tok->Parent->is(tok::r_paren) && Contexts.size() == 1) { Tok->Type = TT_CtorInitializerColon; } else if (Contexts.back().ColonIsObjCMethodExpr || Line.First.Type == TT_ObjCMethodSpecifier) { Tok->Type = TT_ObjCMethodExpr; Tok->Parent->Type = TT_ObjCSelectorName; if (Tok->Parent->FormatTok.TokenLength > - Contexts.back().LongestObjCSelectorName) + Contexts.back().LongestObjCSelectorName) Contexts.back().LongestObjCSelectorName = Tok->Parent->FormatTok.TokenLength; if (Contexts.back().FirstObjCSelectorName == NULL) @@ -327,6 +329,8 @@ private: Tok->Type = TT_RangeBasedForLoopColon; } else if (Contexts.size() == 1) { Tok->Type = TT_InheritanceColon; + } else if (Contexts.back().ContextKind == tok::l_paren) { + Tok->Type = TT_InlineASMColon; } break; case tok::kw_if: @@ -346,7 +350,7 @@ private: case tok::l_paren: if (!parseParens()) return false; - if (Line.MustBeDeclaration) + if (Line.MustBeDeclaration && NameFound && !Contexts.back().IsExpression) Line.MightBeFunctionDecl = true; break; case tok::l_square: @@ -379,7 +383,7 @@ private: break; case tok::kw_operator: while (CurrentToken && CurrentToken->isNot(tok::l_paren)) { - if (CurrentToken->is(tok::star) || CurrentToken->is(tok::amp)) + if (CurrentToken->isOneOf(tok::star, tok::amp)) CurrentToken->Type = TT_PointerOrReference; consumeToken(); } @@ -397,6 +401,10 @@ private: Tok->FormatTok.Tok.getIdentifierInfo() == &Ident_in) Tok->Type = TT_ObjCForIn; break; + case tok::comma: + if (Contexts.back().FirstStartOfName) + Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true; + break; default: break; } @@ -452,6 +460,10 @@ private: case tok::pp_warning: parseWarningOrError(); break; + case tok::pp_if: + case tok::pp_elif: + parseLine(); + break; default: break; } @@ -471,7 +483,7 @@ public: while (CurrentToken != NULL) { if (CurrentToken->is(tok::kw_virtual)) KeywordVirtualFound = true; - if (CurrentToken->is(tok::period) || CurrentToken->is(tok::arrow)) { + if (CurrentToken->isOneOf(tok::period, tok::arrow)) { ++PeriodsAndArrows; LastPeriodOrArrow = CurrentToken; } @@ -522,17 +534,23 @@ private: /// \brief A struct to hold information valid in a specific context, e.g. /// a pair of parenthesis. struct Context { - Context(unsigned BindingStrength, bool IsExpression) - : BindingStrength(BindingStrength), LongestObjCSelectorName(0), - ColonIsForRangeExpr(false), ColonIsObjCMethodExpr(false), - FirstObjCSelectorName(NULL), IsExpression(IsExpression) {} - + Context(tok::TokenKind ContextKind, unsigned BindingStrength, + bool IsExpression) + : ContextKind(ContextKind), BindingStrength(BindingStrength), + LongestObjCSelectorName(0), ColonIsForRangeExpr(false), + ColonIsObjCMethodExpr(false), FirstObjCSelectorName(NULL), + FirstStartOfName(NULL), IsExpression(IsExpression), + CanBeExpression(true) {} + + tok::TokenKind ContextKind; unsigned BindingStrength; unsigned LongestObjCSelectorName; bool ColonIsForRangeExpr; bool ColonIsObjCMethodExpr; AnnotatedToken *FirstObjCSelectorName; + AnnotatedToken *FirstStartOfName; bool IsExpression; + bool CanBeExpression; }; /// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime @@ -540,16 +558,20 @@ private: struct ScopedContextCreator { AnnotatingParser &P; - ScopedContextCreator(AnnotatingParser &P, unsigned Increase) : P(P) { - P.Contexts.push_back(Context(P.Contexts.back().BindingStrength + Increase, - P.Contexts.back().IsExpression)); + ScopedContextCreator(AnnotatingParser &P, tok::TokenKind ContextKind, + unsigned Increase) + : P(P) { + P.Contexts.push_back( + Context(ContextKind, P.Contexts.back().BindingStrength + Increase, + P.Contexts.back().IsExpression)); } ~ScopedContextCreator() { P.Contexts.pop_back(); } }; void determineTokenType(AnnotatedToken &Current) { - if (getPrecedence(Current) == prec::Assignment) { + if (getPrecedence(Current) == prec::Assignment && + (!Current.Parent || Current.Parent->isNot(tok::kw_operator))) { Contexts.back().IsExpression = true; for (AnnotatedToken *Previous = Current.Parent; Previous && Previous->isNot(tok::comma); @@ -557,23 +579,27 @@ private: if (Previous->is(tok::r_square)) Previous = Previous->MatchingParen; if (Previous->Type == TT_BinaryOperator && - (Previous->is(tok::star) || Previous->is(tok::amp))) { + Previous->isOneOf(tok::star, tok::amp)) { Previous->Type = TT_PointerOrReference; } } - } else if (Current.is(tok::kw_return) || Current.is(tok::kw_throw) || + } else if (Current.isOneOf(tok::kw_return, tok::kw_throw) || (Current.is(tok::l_paren) && !Line.MustBeDeclaration && (!Current.Parent || Current.Parent->isNot(tok::kw_for)))) { Contexts.back().IsExpression = true; - } else if (Current.is(tok::r_paren) || Current.is(tok::greater) || - Current.is(tok::comma)) { + } else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) { for (AnnotatedToken *Previous = Current.Parent; - Previous && (Previous->is(tok::star) || Previous->is(tok::amp)); + Previous && Previous->isOneOf(tok::star, tok::amp); Previous = Previous->Parent) Previous->Type = TT_PointerOrReference; } else if (Current.Parent && Current.Parent->Type == TT_CtorInitializerColon) { Contexts.back().IsExpression = true; + } else if (Current.is(tok::kw_new)) { + Contexts.back().CanBeExpression = false; + } else if (Current.is(tok::semi)) { + // This should be the condition or increment in a for-loop. + Contexts.back().IsExpression = true; } if (Current.Type == TT_Unknown) { @@ -581,21 +607,22 @@ private: ((Current.Parent->is(tok::identifier) && Current.Parent->FormatTok.Tok.getIdentifierInfo() ->getPPKeywordID() == tok::pp_not_keyword) || + isSimpleTypeSpecifier(*Current.Parent) || Current.Parent->Type == TT_PointerOrReference || Current.Parent->Type == TT_TemplateCloser)) { + Contexts.back().FirstStartOfName = &Current; Current.Type = TT_StartOfName; - } else if (Current.is(tok::star) || Current.is(tok::amp) || - Current.is(tok::ampamp)) { + NameFound = true; + } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { Current.Type = determineStarAmpUsage(Current, Contexts.back().IsExpression); - } else if (Current.is(tok::minus) || Current.is(tok::plus) || - Current.is(tok::caret)) { + } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) { Current.Type = determinePlusMinusCaretUsage(Current); - } else if (Current.is(tok::minusminus) || Current.is(tok::plusplus)) { + } else if (Current.isOneOf(tok::minusminus, tok::plusplus)) { Current.Type = determineIncrementUsage(Current); } else if (Current.is(tok::exclaim)) { Current.Type = TT_UnaryOperator; - } else if (isBinaryOperator(Current)) { + } else if (Current.isBinaryOperator()) { Current.Type = TT_BinaryOperator; } else if (Current.is(tok::comment)) { std::string Data(Lexer::getSpelling(Current.FormatTok.Tok, SourceMgr, @@ -609,10 +636,13 @@ private: Current.Parent->Type == TT_PointerOrReference || Current.Parent->Type == TT_TemplateCloser; bool ParensCouldEndDecl = - !Current.Children.empty() && (Current.Children[0].is(tok::equal) || - Current.Children[0].is(tok::semi) || - Current.Children[0].is(tok::l_brace)); - if (ParensNotExpr && !ParensCouldEndDecl && + !Current.Children.empty() && + Current.Children[0].isOneOf(tok::equal, tok::semi, tok::l_brace); + bool IsSizeOfOrAlignOf = + Current.MatchingParen && Current.MatchingParen->Parent && + Current.MatchingParen->Parent->isOneOf(tok::kw_sizeof, + tok::kw_alignof); + if (ParensNotExpr && !ParensCouldEndDecl && !IsSizeOfOrAlignOf && Contexts.back().IsExpression) // FIXME: We need to get smarter and understand more cases of casts. Current.Type = TT_CastRParen; @@ -636,31 +666,30 @@ private: /// \brief Return the type of the given token assuming it is * or &. TokenType determineStarAmpUsage(const AnnotatedToken &Tok, bool IsExpression) { - const AnnotatedToken *PrevToken = getPreviousToken(Tok); + const AnnotatedToken *PrevToken = Tok.getPreviousNoneComment(); if (PrevToken == NULL) return TT_UnaryOperator; - const AnnotatedToken *NextToken = getNextToken(Tok); + const AnnotatedToken *NextToken = Tok.getNextNoneComment(); if (NextToken == NULL) return TT_Unknown; if (PrevToken->is(tok::l_paren) && !IsExpression) return TT_PointerOrReference; - if (PrevToken->is(tok::l_paren) || PrevToken->is(tok::l_square) || - PrevToken->is(tok::l_brace) || PrevToken->is(tok::comma) || - PrevToken->is(tok::kw_return) || PrevToken->is(tok::colon) || - PrevToken->is(tok::equal) || PrevToken->Type == TT_BinaryOperator || + if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace, + tok::comma, tok::semi, tok::kw_return, tok::colon, + tok::equal) || + PrevToken->Type == TT_BinaryOperator || PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen) return TT_UnaryOperator; if (NextToken->is(tok::l_square)) return TT_PointerOrReference; - if (PrevToken->FormatTok.Tok.isLiteral() || PrevToken->is(tok::r_paren) || - PrevToken->is(tok::r_square) || NextToken->FormatTok.Tok.isLiteral() || - isUnaryOperator(*NextToken) || NextToken->is(tok::l_paren) || - NextToken->is(tok::l_square)) + if (PrevToken->FormatTok.Tok.isLiteral() || + PrevToken->isOneOf(tok::r_paren, tok::r_square) || + NextToken->FormatTok.Tok.isLiteral() || NextToken->isUnaryOperator()) return TT_BinaryOperator; // It is very unlikely that we are going to find a pointer or reference type @@ -672,16 +701,14 @@ private: } TokenType determinePlusMinusCaretUsage(const AnnotatedToken &Tok) { - const AnnotatedToken *PrevToken = getPreviousToken(Tok); + const AnnotatedToken *PrevToken = Tok.getPreviousNoneComment(); if (PrevToken == NULL) return TT_UnaryOperator; // Use heuristics to recognize unary operators. - if (PrevToken->is(tok::equal) || PrevToken->is(tok::l_paren) || - PrevToken->is(tok::comma) || PrevToken->is(tok::l_square) || - PrevToken->is(tok::question) || PrevToken->is(tok::colon) || - PrevToken->is(tok::kw_return) || PrevToken->is(tok::kw_case) || - PrevToken->is(tok::at) || PrevToken->is(tok::l_brace)) + if (PrevToken->isOneOf(tok::equal, tok::l_paren, tok::comma, tok::l_square, + tok::question, tok::colon, tok::kw_return, + tok::kw_case, tok::at, tok::l_brace)) return TT_UnaryOperator; // There can't be two consecutive binary operators. @@ -694,16 +721,48 @@ private: /// \brief Determine whether ++/-- are pre- or post-increments/-decrements. TokenType determineIncrementUsage(const AnnotatedToken &Tok) { - const AnnotatedToken *PrevToken = getPreviousToken(Tok); + const AnnotatedToken *PrevToken = Tok.getPreviousNoneComment(); if (PrevToken == NULL) return TT_UnaryOperator; - if (PrevToken->is(tok::r_paren) || PrevToken->is(tok::r_square) || - PrevToken->is(tok::identifier)) + if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier)) return TT_TrailingUnaryOperator; return TT_UnaryOperator; } + // FIXME: This is copy&pasted from Sema. Put it in a common place and remove + // duplication. + /// \brief Determine whether the token kind starts a simple-type-specifier. + bool isSimpleTypeSpecifier(const AnnotatedToken &Tok) const { + switch (Tok.FormatTok.Tok.getKind()) { + case tok::kw_short: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_half: + case tok::kw_float: + case tok::kw_double: + case tok::kw_wchar_t: + case tok::kw_bool: + case tok::kw___underlying_type: + return true; + case tok::annot_typename: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_typeof: + case tok::kw_decltype: + return Lex.getLangOpts().CPlusPlus; + default: + break; + } + return false; + } + SmallVector<Context, 8> Contexts; SourceManager &SourceMgr; @@ -711,6 +770,7 @@ private: AnnotatedLine &Line; AnnotatedToken *CurrentToken; bool KeywordVirtualFound; + bool NameFound; IdentifierInfo &Ident_in; }; @@ -725,12 +785,8 @@ public: if (Precedence > prec::PointerToMember || Current == NULL) return; - // Skip over "return" until we can properly parse it. - if (Current->is(tok::kw_return)) - next(); - // Eagerly consume trailing comments. - while (isTrailingComment(Current)) { + while (Current && Current->isTrailingComment()) { next(); } @@ -739,13 +795,13 @@ public: while (Current) { // Consume operators with higher precedence. - parse(prec::Level(Precedence + 1)); + parse(Precedence + 1); int CurrentPrecedence = 0; if (Current) { if (Current->Type == TT_ConditionalExpr) CurrentPrecedence = 1 + (int) prec::Conditional; - else if (Current->is(tok::semi)) + else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon) CurrentPrecedence = 1; else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma)) CurrentPrecedence = 1 + (int) getPrecedence(*Current); @@ -753,10 +809,10 @@ public: // At the end of the line or when an operator with higher precedence is // found, insert fake parenthesis and return. - if (Current == NULL || closesScope(*Current) || + if (Current == NULL || Current->closesScope() || (CurrentPrecedence != 0 && CurrentPrecedence < Precedence)) { if (OperatorFound) { - ++Start->FakeLParens; + Start->FakeLParens.push_back(prec::Level(Precedence - 1)); if (Current) ++Current->Parent->FakeRParens; } @@ -764,18 +820,11 @@ public: } // Consume scopes: (), [], <> and {} - if (opensScope(*Current)) { - AnnotatedToken *Left = Current; - while (Current && !closesScope(*Current)) { + if (Current->opensScope()) { + while (Current && !Current->closesScope()) { next(); parse(); } - // Remove fake parens that just duplicate the real parens. - if (Current && Left->Children[0].FakeLParens > 0 && - Current->Parent->FakeRParens > 0) { - --Left->Children[0].FakeLParens; - --Current->Parent->FakeRParens; - } next(); } else { // Operator found. @@ -793,16 +842,6 @@ private: Current = Current->Children.empty() ? NULL : &Current->Children[0]; } - bool closesScope(const AnnotatedToken &Tok) { - return Current->is(tok::r_paren) || Current->Type == TT_TemplateCloser || - Current->is(tok::r_brace) || Current->is(tok::r_square); - } - - bool opensScope(const AnnotatedToken &Tok) { - return Current->is(tok::l_paren) || Current->Type == TT_TemplateOpener || - Current->is(tok::l_brace) || Current->is(tok::l_square); - } - AnnotatedToken *Current; }; @@ -844,7 +883,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { Current->MustBreakBefore = true; } else if (Current->Type == TT_LineComment) { Current->MustBreakBefore = Current->FormatTok.NewlinesBefore > 0; - } else if (isTrailingComment(Current->Parent) || + } else if (Current->Parent->isTrailingComment() || (Current->is(tok::string_literal) && Current->Parent->is(tok::string_literal))) { Current->MustBreakBefore = true; @@ -871,6 +910,10 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { Current = Current->Children.empty() ? NULL : &Current->Children[0]; } + + DEBUG({ + printDebugInfo(Line); + }); } unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, @@ -879,28 +922,30 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, const AnnotatedToken &Right = Tok; if (Right.Type == TT_StartOfName) { - if (Line.First.is(tok::kw_for)) + if (Line.First.is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt) return 3; else if (Line.MightBeFunctionDecl && Right.BindingStrength == 1) // FIXME: Clean up hack of using BindingStrength to find top-level names. return Style.PenaltyReturnTypeOnItsOwnLine; else - return 100; + return 200; } if (Left.is(tok::equal) && Right.is(tok::l_brace)) return 150; if (Left.is(tok::coloncolon)) return 500; + if (Left.isOneOf(tok::kw_class, tok::kw_struct)) + return 5000; if (Left.Type == TT_RangeBasedForLoopColon || Left.Type == TT_InheritanceColon) return 2; - if (Right.is(tok::arrow) || Right.is(tok::period)) { + if (Right.isOneOf(tok::arrow, tok::period)) { if (Line.Type == LT_BuilderTypeCall) - return 5; - if ((Left.is(tok::r_paren) || Left.is(tok::r_square)) && - Left.MatchingParen && Left.MatchingParen->ParameterCount > 0) + return prec::PointerToMember; + if (Left.isOneOf(tok::r_paren, tok::r_square) && Left.MatchingParen && + Left.MatchingParen->ParameterCount > 0) return 20; // Should be smaller than breaking at a nested comma. return 150; } @@ -921,16 +966,18 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr) return 20; - if (Left.is(tok::l_paren) || Left.is(tok::l_square) || - Left.is(tok::l_brace) || Left.Type == TT_TemplateOpener) - return 20; + if (Left.is(tok::l_paren) && Line.MightBeFunctionDecl) + return 100; + if (Left.opensScope()) + return Left.ParameterCount > 1 ? prec::Comma : 20; if (Right.is(tok::lessless)) { if (Left.is(tok::string_literal)) { - char LastChar = - StringRef(Left.FormatTok.Tok.getLiteralData(), - Left.FormatTok.TokenLength).drop_back(1).rtrim().back(); - if (LastChar == ':' || LastChar == '=') + StringRef Content = StringRef(Left.FormatTok.Tok.getLiteralData(), + Left.FormatTok.TokenLength); + Content = Content.drop_back(1).drop_front(1).trim(); + if (Content.size() > 1 && + (Content.back() == ':' || Content.back() == '=')) return 100; } return prec::Shift; @@ -950,9 +997,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, const AnnotatedToken &Right) { if (Right.is(tok::hashhash)) return Left.is(tok::hash); - if (Left.is(tok::hashhash) || Left.is(tok::hash)) + if (Left.isOneOf(tok::hashhash, tok::hash)) return Right.is(tok::hash); - if (Right.is(tok::r_paren) || Right.is(tok::semi) || Right.is(tok::comma)) + if (Right.isOneOf(tok::r_paren, tok::semi, tok::comma)) return false; if (Right.is(tok::less) && (Left.is(tok::kw_template) || @@ -960,20 +1007,18 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return true; if (Left.is(tok::arrow) || Right.is(tok::arrow)) return false; - if (Left.is(tok::exclaim) || Left.is(tok::tilde)) + if (Left.isOneOf(tok::exclaim, tok::tilde)) return false; if (Left.is(tok::at) && - (Right.is(tok::identifier) || Right.is(tok::string_literal) || - Right.is(tok::char_constant) || Right.is(tok::numeric_constant) || - Right.is(tok::l_paren) || Right.is(tok::l_brace) || - Right.is(tok::kw_true) || Right.is(tok::kw_false))) + Right.isOneOf(tok::identifier, tok::string_literal, tok::char_constant, + tok::numeric_constant, tok::l_paren, tok::l_brace, + tok::kw_true, tok::kw_false)) return false; if (Left.is(tok::coloncolon)) return false; if (Right.is(tok::coloncolon)) - return Left.isNot(tok::identifier) && Left.isNot(tok::greater) && - Left.isNot(tok::l_paren); - if (Left.is(tok::less) || Right.is(tok::greater) || Right.is(tok::less)) + return !Left.isOneOf(tok::identifier, tok::greater, tok::l_paren); + if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) return false; if (Right.Type == TT_PointerOrReference) return Left.FormatTok.Tok.isLiteral() || @@ -981,7 +1026,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, !Style.PointerBindsToType); if (Left.Type == TT_PointerOrReference) return Right.FormatTok.Tok.isLiteral() || - ((Right.Type != TT_PointerOrReference) && Style.PointerBindsToType); + ((Right.Type != TT_PointerOrReference) && + Right.isNot(tok::l_paren) && Style.PointerBindsToType && + Left.Parent && Left.Parent->isNot(tok::l_paren)); if (Right.is(tok::star) && Left.is(tok::l_paren)) return false; if (Left.is(tok::l_square)) @@ -999,17 +1046,18 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Left.is(tok::l_paren)) return false; if (Right.is(tok::l_paren)) { - return Line.Type == LT_ObjCDecl || Left.is(tok::kw_if) || - Left.is(tok::kw_for) || Left.is(tok::kw_while) || - Left.is(tok::kw_switch) || Left.is(tok::kw_return) || - Left.is(tok::kw_catch) || Left.is(tok::kw_new) || - Left.is(tok::kw_delete); + return Line.Type == LT_ObjCDecl || + Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, + tok::kw_return, tok::kw_catch, tok::kw_new, + tok::kw_delete, tok::semi); } if (Left.is(tok::at) && Right.FormatTok.Tok.getObjCKeywordID() != tok::objc_not_keyword) return false; if (Left.is(tok::l_brace) && Right.is(tok::r_brace)) return false; + if (Right.is(tok::ellipsis)) + return false; return true; } @@ -1040,19 +1088,19 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Tok.Type == TT_OverloadedOperatorLParen) return false; if (Tok.is(tok::colon)) - return Line.First.isNot(tok::kw_case) && - Line.First.isNot(tok::kw_default) && !Tok.Children.empty() && - Tok.Type != TT_ObjCMethodExpr; + return !Line.First.isOneOf(tok::kw_case, tok::kw_default) && + Tok.getNextNoneComment() != NULL && Tok.Type != TT_ObjCMethodExpr; if (Tok.is(tok::l_paren) && !Tok.Children.empty() && Tok.Children[0].Type == TT_PointerOrReference && !Tok.Children[0].Children.empty() && - Tok.Children[0].Children[0].isNot(tok::r_paren)) + Tok.Children[0].Children[0].isNot(tok::r_paren) && + Tok.Parent->isNot(tok::l_paren) && + (Tok.Parent->Type != TT_PointerOrReference || Style.PointerBindsToType)) return true; if (Tok.Parent->Type == TT_UnaryOperator || Tok.Parent->Type == TT_CastRParen) return false; if (Tok.Type == TT_UnaryOperator) - return Tok.Parent->isNot(tok::l_paren) && - Tok.Parent->isNot(tok::l_square) && Tok.Parent->isNot(tok::at) && + return !Tok.Parent->isOneOf(tok::l_paren, tok::l_square, tok::at) && (Tok.Parent->isNot(tok::colon) || Tok.Parent->Type != TT_ObjCMethodExpr); if (Tok.Parent->is(tok::greater) && Tok.is(tok::greater)) { @@ -1060,7 +1108,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Tok.Parent->Type == TT_TemplateCloser && Style.Standard != FormatStyle::LS_Cpp11; } - if (Tok.is(tok::arrowstar) || Tok.Parent->is(tok::arrowstar)) + if (Tok.isOneOf(tok::arrowstar, tok::periodstar) || + Tok.Parent->isOneOf(tok::arrowstar, tok::periodstar)) return false; if (Tok.Type == TT_BinaryOperator || Tok.Parent->Type == TT_BinaryOperator) return true; @@ -1089,16 +1138,15 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, if (Right.Type == TT_ConditionalExpr || Right.is(tok::question)) return true; if (Right.Type == TT_RangeBasedForLoopColon || - Right.Type == TT_InheritanceColon) + Right.Type == TT_OverloadedOperatorLParen) return false; - if (Left.Type == TT_RangeBasedForLoopColon || - Left.Type == TT_InheritanceColon) + if (Left.Type == TT_RangeBasedForLoopColon) return true; if (Right.Type == TT_RangeBasedForLoopColon) return false; if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser || Left.Type == TT_UnaryOperator || Left.Type == TT_ConditionalExpr || - Left.is(tok::question) || Left.is(tok::kw_operator)) + Left.isOneOf(tok::question, tok::kw_operator)) return false; if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl) return false; @@ -1115,28 +1163,43 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, // unless it is follow by ';', '{' or '='. if (Left.is(tok::kw_const) && Left.Parent != NULL && Left.Parent->is(tok::r_paren)) - return Right.isNot(tok::l_brace) && Right.isNot(tok::semi) && - Right.isNot(tok::equal); + return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal); + + if (Right.is(tok::kw___attribute)) + return true; // We only break before r_brace if there was a corresponding break before // the l_brace, which is tracked by BreakBeforeClosingBrace. - if (Right.is(tok::r_brace)) - return false; - - if (Right.is(tok::r_paren) || Right.is(tok::greater)) + if (Right.isOneOf(tok::r_brace, tok::r_paren, tok::greater)) return false; if (Left.is(tok::identifier) && Right.is(tok::string_literal)) return true; - return (isBinaryOperator(Left) && Left.isNot(tok::lessless)) || - Left.is(tok::comma) || Right.is(tok::lessless) || - Right.is(tok::arrow) || Right.is(tok::period) || - Right.is(tok::colon) || Left.is(tok::coloncolon) || - Left.is(tok::semi) || Left.is(tok::l_brace) || + return (Left.isBinaryOperator() && Left.isNot(tok::lessless)) || + Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace, + tok::kw_class, tok::kw_struct) || + Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon) || (Left.is(tok::r_paren) && Left.Type != TT_CastRParen && - (Right.is(tok::identifier) || Right.is(tok::kw___attribute))) || + Right.isOneOf(tok::identifier, tok::kw___attribute)) || (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) || (Left.is(tok::l_square) && !Right.is(tok::r_square)); } +void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { + llvm::errs() << "AnnotatedTokens:\n"; + const AnnotatedToken *Tok = &Line.First; + while (Tok) { + llvm::errs() << " M=" << Tok->MustBreakBefore + << " C=" << Tok->CanBreakBefore << " T=" << Tok->Type + << " S=" << Tok->SpacesRequiredBefore + << " P=" << Tok->SplitPenalty + << " Name=" << Tok->FormatTok.Tok.getName() << " FakeLParens="; + for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i) + llvm::errs() << Tok->FakeLParens[i] << "/"; + llvm::errs() << " FakeRParens=" << Tok->FakeRParens << "\n"; + Tok = Tok->Children.empty() ? NULL : &Tok->Children[0]; + } + llvm::errs() << "----\n"; +} + } // namespace format } // namespace clang diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h index b79ee97da8..b364082391 100644 --- a/lib/Format/TokenAnnotator.h +++ b/lib/Format/TokenAnnotator.h @@ -34,6 +34,7 @@ enum TokenType { TT_ConditionalExpr, TT_CtorInitializerColon, TT_ImplicitStringLiteral, + TT_InlineASMColon, TT_InheritanceColon, TT_LineComment, TT_ObjCArrayLiteral, @@ -74,17 +75,61 @@ public: CanBreakBefore(false), MustBreakBefore(false), ClosesTemplateDeclaration(false), MatchingParen(NULL), ParameterCount(0), BindingStrength(0), SplitPenalty(0), - LongestObjCSelectorName(0), Parent(NULL), FakeLParens(0), - FakeRParens(0), LastInChainOfCalls(false) { - } + LongestObjCSelectorName(0), Parent(NULL), + FakeRParens(0), LastInChainOfCalls(false), + PartOfMultiVariableDeclStmt(false), NoMoreTokensOnLevel(false) {} bool is(tok::TokenKind Kind) const { return FormatTok.Tok.is(Kind); } + + bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const { + return is(K1) || is(K2); + } + + bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3) const { + return is(K1) || is(K2) || is(K3); + } + + bool isOneOf( + tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3, + tok::TokenKind K4, tok::TokenKind K5 = tok::NUM_TOKENS, + tok::TokenKind K6 = tok::NUM_TOKENS, tok::TokenKind K7 = tok::NUM_TOKENS, + tok::TokenKind K8 = tok::NUM_TOKENS, tok::TokenKind K9 = tok::NUM_TOKENS, + tok::TokenKind K10 = tok::NUM_TOKENS, + tok::TokenKind K11 = tok::NUM_TOKENS, + tok::TokenKind K12 = tok::NUM_TOKENS) const { + return is(K1) || is(K2) || is(K3) || is(K4) || is(K5) || is(K6) || is(K7) || + is(K8) || is(K9) || is(K10) || is(K11) || is(K12); + } + bool isNot(tok::TokenKind Kind) const { return FormatTok.Tok.isNot(Kind); } bool isObjCAtKeyword(tok::ObjCKeywordKind Kind) const { return FormatTok.Tok.isObjCAtKeyword(Kind); } + bool isAccessSpecifier(bool ColonRequired = true) const { + return isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private) && + (!ColonRequired || + (!Children.empty() && Children[0].is(tok::colon))); + } + + bool isObjCAccessSpecifier() const { + return is(tok::at) && !Children.empty() && + (Children[0].isObjCAtKeyword(tok::objc_public) || + Children[0].isObjCAtKeyword(tok::objc_protected) || + Children[0].isObjCAtKeyword(tok::objc_package) || + Children[0].isObjCAtKeyword(tok::objc_private)); + } + + /// \brief Returns whether \p Tok is ([{ or a template opening <. + bool opensScope() const; + /// \brief Returns whether \p Tok is )]} or a template opening >. + bool closesScope() const; + + bool isUnaryOperator() const; + bool isBinaryOperator() const; + bool isTrailingComment() const; + FormatToken FormatTok; TokenType Type; @@ -122,20 +167,41 @@ public: std::vector<AnnotatedToken> Children; AnnotatedToken *Parent; - /// \brief Insert this many fake ( before this token for correct indentation. - unsigned FakeLParens; + /// \brief Stores the number of required fake parentheses and the + /// corresponding operator precedence. + /// + /// If multiple fake parentheses start at a token, this vector stores them in + /// reverse order, i.e. inner fake parenthesis first. + SmallVector<prec::Level, 4> FakeLParens; /// \brief Insert this many fake ) after this token for correct indentation. unsigned FakeRParens; /// \brief Is this the last "." or "->" in a builder-type call? bool LastInChainOfCalls; - const AnnotatedToken *getPreviousNoneComment() const { - AnnotatedToken *Tok = Parent; - while (Tok != NULL && Tok->is(tok::comment)) - Tok = Tok->Parent; - return Tok; - } + /// \brief Is this token part of a \c DeclStmt defining multiple variables? + /// + /// Only set if \c Type == \c TT_StartOfName. + bool PartOfMultiVariableDeclStmt; + + /// \brief Set to \c true for "("-tokens if this is the last token other than + /// ")" in the next higher parenthesis level. + /// + /// If this is \c true, no more formatting decisions have to be made on the + /// next higher parenthesis level, enabling optimizations. + /// + /// Example: + /// \code + /// aaaaaa(aaaaaa()); + /// ^ // Set to true for this parenthesis. + /// \endcode + bool NoMoreTokensOnLevel; + + /// \brief Returns the previous token ignoring comments. + AnnotatedToken *getPreviousNoneComment() const; + + /// \brief Returns the next token ignoring comments. + const AnnotatedToken *getNextNoneComment() const; }; class AnnotatedLine { @@ -143,8 +209,8 @@ public: AnnotatedLine(const UnwrappedLine &Line) : First(Line.Tokens.front()), Level(Line.Level), InPPDirective(Line.InPPDirective), - MustBeDeclaration(Line.MustBeDeclaration), - MightBeFunctionDecl(false) { + MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false), + StartsDefinition(false) { assert(!Line.Tokens.empty()); AnnotatedToken *Current = &First; for (std::list<FormatToken>::const_iterator I = ++Line.Tokens.begin(), @@ -160,7 +226,8 @@ public: : First(Other.First), Type(Other.Type), Level(Other.Level), InPPDirective(Other.InPPDirective), MustBeDeclaration(Other.MustBeDeclaration), - MightBeFunctionDecl(Other.MightBeFunctionDecl) { + MightBeFunctionDecl(Other.MightBeFunctionDecl), + StartsDefinition(Other.StartsDefinition) { Last = &First; while (!Last->Children.empty()) { Last->Children[0].Parent = Last; @@ -176,6 +243,7 @@ public: bool InPPDirective; bool MustBeDeclaration; bool MightBeFunctionDecl; + bool StartsDefinition; }; inline prec::Level getPrecedence(const AnnotatedToken &Tok) { @@ -207,6 +275,8 @@ private: bool canBreakBefore(const AnnotatedLine &Line, const AnnotatedToken &Right); + void printDebugInfo(const AnnotatedLine &Line); + const FormatStyle &Style; SourceManager &SourceMgr; Lexer &Lex; diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index cdd77759fd..722af5d2b7 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -45,9 +45,11 @@ private: class ScopedMacroState : public FormatTokenSource { public: ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource, - FormatToken &ResetToken) + FormatToken &ResetToken, bool &StructuralError) : Line(Line), TokenSource(TokenSource), ResetToken(ResetToken), - PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource) { + PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource), + StructuralError(StructuralError), + PreviousStructuralError(StructuralError) { TokenSource = this; Line.Level = 0; Line.InPPDirective = true; @@ -58,6 +60,7 @@ public: ResetToken = Token; Line.InPPDirective = false; Line.Level = PreviousLineLevel; + StructuralError = PreviousStructuralError; } virtual FormatToken getNextToken() { @@ -71,9 +74,7 @@ public: } private: - bool eof() { - return Token.NewlinesBefore > 0 && Token.HasUnescapedNewline; - } + bool eof() { return Token.HasUnescapedNewline; } FormatToken createEOF() { FormatToken FormatTok; @@ -87,6 +88,8 @@ private: FormatToken &ResetToken; unsigned PreviousLineLevel; FormatTokenSource *PreviousTokenSource; + bool &StructuralError; + bool PreviousStructuralError; FormatToken Token; }; @@ -126,15 +129,14 @@ UnwrappedLineParser::UnwrappedLineParser( clang::DiagnosticsEngine &Diag, const FormatStyle &Style, FormatTokenSource &Tokens, UnwrappedLineConsumer &Callback) : Line(new UnwrappedLine), MustBreakBeforeNextToken(false), - CurrentLines(&Lines), Diag(Diag), Style(Style), Tokens(&Tokens), - Callback(Callback) {} + CurrentLines(&Lines), StructuralError(false), Diag(Diag), Style(Style), + Tokens(&Tokens), Callback(Callback) {} bool UnwrappedLineParser::parse() { DEBUG(llvm::dbgs() << "----\n"); readToken(); - bool Error = parseFile(); - for (std::vector<UnwrappedLine>::iterator I = Lines.begin(), - E = Lines.end(); + parseFile(); + for (std::vector<UnwrappedLine>::iterator I = Lines.begin(), E = Lines.end(); I != E; ++I) { Callback.consumeUnwrappedLine(*I); } @@ -142,22 +144,20 @@ bool UnwrappedLineParser::parse() { // Create line with eof token. pushToken(FormatTok); Callback.consumeUnwrappedLine(*Line); - - return Error; + return StructuralError; } -bool UnwrappedLineParser::parseFile() { - ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, - /*MustBeDeclaration=*/ true); - bool Error = parseLevel(/*HasOpeningBrace=*/false); +void UnwrappedLineParser::parseFile() { + ScopedDeclarationState DeclarationState( + *Line, DeclarationScopeStack, + /*MustBeDeclaration=*/ !Line->InPPDirective); + parseLevel(/*HasOpeningBrace=*/ false); // Make sure to format the remaining tokens. flushComments(true); addUnwrappedLine(); - return Error; } -bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { - bool Error = false; +void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { do { switch (FormatTok.Tok.getKind()) { case tok::comment: @@ -167,30 +167,27 @@ bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { case tok::l_brace: // FIXME: Add parameter whether this can happen - if this happens, we must // be in a non-declaration context. - Error |= parseBlock(/*MustBeDeclaration=*/ false); + parseBlock(/*MustBeDeclaration=*/ false); addUnwrappedLine(); break; case tok::r_brace: - if (HasOpeningBrace) { - return false; - } else { - Diag.Report(FormatTok.Tok.getLocation(), - Diag.getCustomDiagID(clang::DiagnosticsEngine::Error, - "unexpected '}'")); - Error = true; - nextToken(); - addUnwrappedLine(); - } + if (HasOpeningBrace) + return; + Diag.Report(FormatTok.Tok.getLocation(), + Diag.getCustomDiagID(clang::DiagnosticsEngine::Error, + "unexpected '}'")); + StructuralError = true; + nextToken(); + addUnwrappedLine(); break; default: parseStructuralElement(); break; } } while (!eof()); - return Error; } -bool UnwrappedLineParser::parseBlock(bool MustBeDeclaration, +void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels) { assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected"); nextToken(); @@ -200,21 +197,21 @@ bool UnwrappedLineParser::parseBlock(bool MustBeDeclaration, ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, MustBeDeclaration); Line->Level += AddLevels; - parseLevel(/*HasOpeningBrace=*/true); + parseLevel(/*HasOpeningBrace=*/ true); if (!FormatTok.Tok.is(tok::r_brace)) { Line->Level -= AddLevels; - return true; + StructuralError = true; + return; } - nextToken(); // Munch the closing brace. + nextToken(); // Munch the closing brace. Line->Level -= AddLevels; - return false; } void UnwrappedLineParser::parsePPDirective() { assert(FormatTok.Tok.is(tok::hash) && "'#' expected"); - ScopedMacroState MacroState(*Line, Tokens, FormatTok); + ScopedMacroState MacroState(*Line, Tokens, FormatTok, StructuralError); nextToken(); if (FormatTok.Tok.getIdentifierInfo() == NULL) { @@ -262,9 +259,35 @@ void UnwrappedLineParser::parsePPUnknown() { addUnwrappedLine(); } +// Here we blacklist certain tokens that are not usually the first token in an +// unwrapped line. This is used in attempt to distinguish macro calls without +// trailing semicolons from other constructs split to several lines. +bool tokenCanStartNewLine(clang::Token Tok) { + // Semicolon can be a null-statement, l_square can be a start of a macro or + // a C++11 attribute, but this doesn't seem to be common. + return Tok.isNot(tok::semi) && Tok.isNot(tok::l_brace) && + Tok.isNot(tok::l_square) && + // Tokens that can only be used as binary operators and a part of + // overloaded operator names. + Tok.isNot(tok::period) && Tok.isNot(tok::periodstar) && + Tok.isNot(tok::arrow) && Tok.isNot(tok::arrowstar) && + Tok.isNot(tok::less) && Tok.isNot(tok::greater) && + Tok.isNot(tok::slash) && Tok.isNot(tok::percent) && + Tok.isNot(tok::lessless) && Tok.isNot(tok::greatergreater) && + Tok.isNot(tok::equal) && Tok.isNot(tok::plusequal) && + Tok.isNot(tok::minusequal) && Tok.isNot(tok::starequal) && + Tok.isNot(tok::slashequal) && Tok.isNot(tok::percentequal) && + Tok.isNot(tok::ampequal) && Tok.isNot(tok::pipeequal) && + Tok.isNot(tok::caretequal) && Tok.isNot(tok::greatergreaterequal) && + Tok.isNot(tok::lesslessequal) && + // Colon is used in labels, base class lists, initializer lists, + // range-based for loops, ternary operator, but should never be the + // first token in an unwrapped line. + Tok.isNot(tok::colon); +} + void UnwrappedLineParser::parseStructuralElement() { assert(!FormatTok.Tok.is(tok::l_brace)); - int TokenNumber = 0; switch (FormatTok.Tok.getKind()) { case tok::at: nextToken(); @@ -299,7 +322,6 @@ void UnwrappedLineParser::parseStructuralElement() { return; case tok::kw_inline: nextToken(); - TokenNumber++; if (FormatTok.Tok.is(tok::kw_namespace)) { parseNamespace(); return; @@ -349,7 +371,6 @@ void UnwrappedLineParser::parseStructuralElement() { break; } do { - ++TokenNumber; switch (FormatTok.Tok.getKind()) { case tok::at: nextToken(); @@ -386,9 +407,20 @@ void UnwrappedLineParser::parseStructuralElement() { return; case tok::identifier: nextToken(); - if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) { - parseLabel(); - return; + if (Line->Tokens.size() == 1) { + if (FormatTok.Tok.is(tok::colon)) { + parseLabel(); + return; + } + // Recognize function-like macro usages without trailing semicolon. + if (FormatTok.Tok.is(tok::l_paren)) { + parseParens(); + if (FormatTok.HasUnescapedNewline && + tokenCanStartNewLine(FormatTok.Tok)) { + addUnwrappedLine(); + return; + } + } } break; case tok::equal: @@ -407,16 +439,36 @@ void UnwrappedLineParser::parseStructuralElement() { void UnwrappedLineParser::parseBracedList() { nextToken(); + // FIXME: Once we have an expression parser in the UnwrappedLineParser, + // replace this by using parseAssigmentExpression() inside. + bool StartOfExpression = true; do { + // FIXME: When we start to support lambdas, we'll want to parse them away + // here, otherwise our bail-out scenarios below break. The better solution + // might be to just implement a more or less complete expression parser. switch (FormatTok.Tok.getKind()) { case tok::l_brace: + if (!StartOfExpression) { + // Probably a missing closing brace. Bail out. + addUnwrappedLine(); + return; + } parseBracedList(); + StartOfExpression = false; break; case tok::r_brace: nextToken(); return; + case tok::semi: + // Probably a missing closing brace. Bail out. + return; + case tok::comma: + nextToken(); + StartOfExpression = true; + break; default: nextToken(); + StartOfExpression = false; break; } } while (!eof()); @@ -429,6 +481,11 @@ void UnwrappedLineParser::parseReturn() { switch (FormatTok.Tok.getKind()) { case tok::l_brace: parseBracedList(); + if (FormatTok.Tok.isNot(tok::semi)) { + // Assume missing ';'. + addUnwrappedLine(); + return; + } break; case tok::l_paren: parseParens(); @@ -574,9 +631,9 @@ void UnwrappedLineParser::parseLabel() { return; nextToken(); unsigned OldLineLevel = Line->Level; - if (Line->Level > 0) + if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0)) --Line->Level; - if (FormatTok.Tok.is(tok::l_brace)) { + if (CommentsBeforeNextToken.empty() && FormatTok.Tok.is(tok::l_brace)) { parseBlock(/*MustBeDeclaration=*/ false); if (FormatTok.Tok.is(tok::kw_break)) parseStructuralElement(); // "break;" after "}" goes on the same line. @@ -673,8 +730,7 @@ void UnwrappedLineParser::parseRecord() { // The actual identifier can be a nested name specifier, and in macros // it is often token-pasted. while (FormatTok.Tok.is(tok::identifier) || - FormatTok.Tok.is(tok::coloncolon) || - FormatTok.Tok.is(tok::hashhash)) + FormatTok.Tok.is(tok::coloncolon) || FormatTok.Tok.is(tok::hashhash)) nextToken(); // Note that parsing away template declarations here leads to incorrectly @@ -688,7 +744,7 @@ void UnwrappedLineParser::parseRecord() { // (this would still leave us with an ambiguity between template function // and class declarations). if (FormatTok.Tok.is(tok::colon) || FormatTok.Tok.is(tok::less)) { - while (FormatTok.Tok.isNot(tok::l_brace)) { + while (!eof() && FormatTok.Tok.isNot(tok::l_brace)) { if (FormatTok.Tok.is(tok::semi)) return; nextToken(); @@ -723,12 +779,12 @@ void UnwrappedLineParser::parseObjCUntilAtEnd() { void UnwrappedLineParser::parseObjCInterfaceOrImplementation() { nextToken(); - nextToken(); // interface name + nextToken(); // interface name // @interface can be followed by either a base class, or a category. if (FormatTok.Tok.is(tok::colon)) { nextToken(); - nextToken(); // base class name + nextToken(); // base class name } else if (FormatTok.Tok.is(tok::l_paren)) // Skip category, if present. parseParens(); @@ -749,7 +805,7 @@ void UnwrappedLineParser::parseObjCInterfaceOrImplementation() { void UnwrappedLineParser::parseObjCProtocol() { nextToken(); - nextToken(); // protocol name + nextToken(); // protocol name if (FormatTok.Tok.is(tok::less)) parseObjCProtocolList(); @@ -791,9 +847,7 @@ void UnwrappedLineParser::addUnwrappedLine() { } } -bool UnwrappedLineParser::eof() const { - return FormatTok.Tok.is(tok::eof); -} +bool UnwrappedLineParser::eof() const { return FormatTok.Tok.is(tok::eof); } void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) { bool JustComments = Line->Tokens.empty(); @@ -825,13 +879,16 @@ void UnwrappedLineParser::readToken() { do { FormatTok = Tokens->getNextToken(); while (!Line->InPPDirective && FormatTok.Tok.is(tok::hash) && - ((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) || - FormatTok.IsFirst)) { + (FormatTok.HasUnescapedNewline || FormatTok.IsFirst)) { // If there is an unfinished unwrapped line, we flush the preprocessor // directives only after that unwrapped line was finished later. - bool SwitchToPreprocessorLines = !Line->Tokens.empty() && - CurrentLines == &Lines; + bool SwitchToPreprocessorLines = + !Line->Tokens.empty() && CurrentLines == &Lines; ScopedLineState BlockState(*this, SwitchToPreprocessorLines); + // Comments stored before the preprocessor directive need to be output + // before the preprocessor directive, at the same level as the + // preprocessor directive, as we consider them to apply to the directive. + flushComments(FormatTok.NewlinesBefore > 0); parsePPDirective(); } if (!FormatTok.Tok.is(tok::comment)) diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h index f4fecc5ef0..0c618e24d4 100644 --- a/lib/Format/UnwrappedLineParser.h +++ b/lib/Format/UnwrappedLineParser.h @@ -34,7 +34,7 @@ struct FormatToken { FormatToken() : NewlinesBefore(0), HasUnescapedNewline(false), WhiteSpaceLength(0), LastNewlineOffset(0), TokenLength(0), IsFirst(false), - MustBreakBefore(false) {} + MustBreakBefore(false), TrailingWhiteSpaceLength(0) {} /// \brief The \c Token. Token Tok; @@ -76,6 +76,18 @@ struct FormatToken { /// This happens for example when a preprocessor directive ended directly /// before the token. bool MustBreakBefore; + + /// \brief Number of characters of trailing whitespace. + unsigned TrailingWhiteSpaceLength; + + /// \brief Returns actual token start location without leading escaped + /// newlines and whitespace. + /// + /// This can be different to Tok.getLocation(), which includes leading escaped + /// newlines. + SourceLocation getStartOfNonWhitespace() const { + return WhiteSpaceStart.getLocWithOffset(WhiteSpaceLength); + } }; /// \brief An unwrapped line is a sequence of \c Token, that we would like to @@ -125,9 +137,9 @@ public: bool parse(); private: - bool parseFile(); - bool parseLevel(bool HasOpeningBrace); - bool parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1); + void parseFile(); + void parseLevel(bool HasOpeningBrace); + void parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1); void parsePPDirective(); void parsePPDefine(); void parsePPUnknown(); @@ -187,6 +199,10 @@ private: // whether we are in a compound statement or not. std::vector<bool> DeclarationScopeStack; + // Will be true if we encounter an error that leads to possibily incorrect + // indentation levels. + bool StructuralError; + clang::DiagnosticsEngine &Diag; const FormatStyle &Style; FormatTokenSource *Tokens; diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp new file mode 100644 index 0000000000..a75c592bfe --- /dev/null +++ b/lib/Format/WhitespaceManager.cpp @@ -0,0 +1,211 @@ +//===--- WhitespaceManager.cpp - Format C++ code --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements WhitespaceManager class. +/// +//===----------------------------------------------------------------------===// + +#include "WhitespaceManager.h" +#include "llvm/ADT/STLExtras.h" + +namespace clang { +namespace format { + +void WhitespaceManager::replaceWhitespace(const AnnotatedToken &Tok, + unsigned NewLines, unsigned Spaces, + unsigned WhitespaceStartColumn) { + if (NewLines > 0) + alignEscapedNewlines(); + + // 2+ newlines mean an empty line separating logic scopes. + if (NewLines >= 2) + alignComments(); + + // Align line comments if they are trailing or if they continue other + // trailing comments. + if (Tok.isTrailingComment()) { + SourceLocation TokenEndLoc = Tok.FormatTok.getStartOfNonWhitespace() + .getLocWithOffset(Tok.FormatTok.TokenLength); + // Remove the comment's trailing whitespace. + if (Tok.FormatTok.TrailingWhiteSpaceLength != 0) + Replaces.insert(tooling::Replacement( + SourceMgr, TokenEndLoc, Tok.FormatTok.TrailingWhiteSpaceLength, "")); + + bool LineExceedsColumnLimit = + Spaces + WhitespaceStartColumn + Tok.FormatTok.TokenLength > + Style.ColumnLimit; + // Align comment with other comments. + if ((Tok.Parent != NULL || !Comments.empty()) && + !LineExceedsColumnLimit) { + unsigned MinColumn = + NewLines > 0 ? Spaces : WhitespaceStartColumn + Spaces; + unsigned MaxColumn = Style.ColumnLimit - Tok.FormatTok.TokenLength; + Comments.push_back(StoredToken( + Tok.FormatTok.WhiteSpaceStart, Tok.FormatTok.WhiteSpaceLength, + MinColumn, MaxColumn, NewLines, Spaces)); + return; + } + } + + // If this line does not have a trailing comment, align the stored comments. + if (Tok.Children.empty() && !Tok.isTrailingComment()) + alignComments(); + + storeReplacement(Tok.FormatTok.WhiteSpaceStart, + Tok.FormatTok.WhiteSpaceLength, + getNewLineText(NewLines, Spaces)); +} + +void WhitespaceManager::replacePPWhitespace(const AnnotatedToken &Tok, + unsigned NewLines, unsigned Spaces, + unsigned WhitespaceStartColumn) { + if (NewLines == 0) { + replaceWhitespace(Tok, NewLines, Spaces, WhitespaceStartColumn); + } else { + // The earliest position for "\" is 2 after the last token. + unsigned MinColumn = WhitespaceStartColumn + 2; + unsigned MaxColumn = Style.ColumnLimit; + EscapedNewlines.push_back(StoredToken( + Tok.FormatTok.WhiteSpaceStart, Tok.FormatTok.WhiteSpaceLength, + MinColumn, MaxColumn, NewLines, Spaces)); + } +} + +void WhitespaceManager::breakToken(const FormatToken &Tok, unsigned Offset, + unsigned ReplaceChars, StringRef Prefix, + StringRef Postfix, bool InPPDirective, + unsigned Spaces, + unsigned WhitespaceStartColumn) { + SourceLocation Location = + Tok.getStartOfNonWhitespace().getLocWithOffset(Offset); + if (InPPDirective) { + // The earliest position for "\" is 2 after the last token. + unsigned MinColumn = WhitespaceStartColumn + 2; + unsigned MaxColumn = Style.ColumnLimit; + StoredToken StoredTok = StoredToken(Location, ReplaceChars, MinColumn, + MaxColumn, /*NewLines=*/ 1, Spaces); + StoredTok.Prefix = Prefix; + StoredTok.Postfix = Postfix; + EscapedNewlines.push_back(StoredTok); + } else { + std::string ReplacementText = + (Prefix + getNewLineText(1, Spaces) + Postfix).str(); + Replaces.insert(tooling::Replacement(SourceMgr, Location, ReplaceChars, + ReplacementText)); + } +} + +const tooling::Replacements &WhitespaceManager::generateReplacements() { + alignComments(); + alignEscapedNewlines(); + return Replaces; +} + +void WhitespaceManager::addReplacement(const SourceLocation &SourceLoc, + unsigned ReplaceChars, StringRef Text) { + Replaces.insert( + tooling::Replacement(SourceMgr, SourceLoc, ReplaceChars, Text)); +} + +void WhitespaceManager::addUntouchableComment(unsigned Column) { + StoredToken Tok = StoredToken(SourceLocation(), 0, Column, Column, 0, 0); + Tok.Untouchable = true; + Comments.push_back(Tok); +} + +std::string WhitespaceManager::getNewLineText(unsigned NewLines, + unsigned Spaces) { + return std::string(NewLines, '\n') + std::string(Spaces, ' '); +} + +std::string WhitespaceManager::getNewLineText(unsigned NewLines, + unsigned Spaces, + unsigned WhitespaceStartColumn, + unsigned EscapedNewlineColumn) { + std::string NewLineText; + if (NewLines > 0) { + unsigned Offset = + std::min<int>(EscapedNewlineColumn - 1, WhitespaceStartColumn); + for (unsigned i = 0; i < NewLines; ++i) { + NewLineText += std::string(EscapedNewlineColumn - Offset - 1, ' '); + NewLineText += "\\\n"; + Offset = 0; + } + } + return NewLineText + std::string(Spaces, ' '); +} + +void WhitespaceManager::alignComments() { + unsigned MinColumn = 0; + unsigned MaxColumn = UINT_MAX; + token_iterator Start = Comments.begin(); + for (token_iterator I = Start, E = Comments.end(); I != E; ++I) { + if (I->MinColumn > MaxColumn || I->MaxColumn < MinColumn) { + alignComments(Start, I, MinColumn); + MinColumn = I->MinColumn; + MaxColumn = I->MaxColumn; + Start = I; + } else { + MinColumn = std::max(MinColumn, I->MinColumn); + MaxColumn = std::min(MaxColumn, I->MaxColumn); + } + } + alignComments(Start, Comments.end(), MinColumn); + Comments.clear(); +} + +void WhitespaceManager::alignComments(token_iterator I, token_iterator E, + unsigned Column) { + while (I != E) { + if (!I->Untouchable) { + unsigned Spaces = I->Spaces + Column - I->MinColumn; + storeReplacement(I->ReplacementLoc, I->ReplacementLength, + getNewLineText(I->NewLines, Spaces)); + } + ++I; + } +} + +void WhitespaceManager::alignEscapedNewlines() { + unsigned MinColumn; + if (Style.AlignEscapedNewlinesLeft) { + MinColumn = 0; + for (token_iterator I = EscapedNewlines.begin(), E = EscapedNewlines.end(); + I != E; ++I) { + if (I->MinColumn > MinColumn) + MinColumn = I->MinColumn; + } + } else { + MinColumn = Style.ColumnLimit; + } + + for (token_iterator I = EscapedNewlines.begin(), E = EscapedNewlines.end(); + I != E; ++I) { + // I->MinColumn - 2 is the end of the previous token (i.e. the + // WhitespaceStartColumn). + storeReplacement( + I->ReplacementLoc, I->ReplacementLength, + I->Prefix + getNewLineText(I->NewLines, I->Spaces, I->MinColumn - 2, + MinColumn) + I->Postfix); + + } + EscapedNewlines.clear(); +} + +void WhitespaceManager::storeReplacement(SourceLocation Loc, unsigned Length, + const std::string Text) { + // Don't create a replacement, if it does not change anything. + if (StringRef(SourceMgr.getCharacterData(Loc), Length) == Text) + return; + Replaces.insert(tooling::Replacement(SourceMgr, Loc, Length, Text)); +} + +} // namespace format +} // namespace clang diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h new file mode 100644 index 0000000000..5f3dc55eda --- /dev/null +++ b/lib/Format/WhitespaceManager.h @@ -0,0 +1,119 @@ +//===--- WhitespaceManager.h - Format C++ code ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief WhitespaceManager class manages whitespace around tokens and their +/// replacements. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FORMAT_WHITESPACEMANAGER_H +#define LLVM_CLANG_FORMAT_WHITESPACEMANAGER_H + +#include "TokenAnnotator.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Format/Format.h" +#include <string> + +namespace clang { +namespace format { + +/// \brief Manages the whitespaces around tokens and their replacements. +/// +/// This includes special handling for certain constructs, e.g. the alignment of +/// trailing line comments. +class WhitespaceManager { +public: + WhitespaceManager(SourceManager &SourceMgr, const FormatStyle &Style) + : SourceMgr(SourceMgr), Style(Style) {} + + /// \brief Replaces the whitespace in front of \p Tok. Only call once for + /// each \c AnnotatedToken. + void replaceWhitespace(const AnnotatedToken &Tok, unsigned NewLines, + unsigned Spaces, unsigned WhitespaceStartColumn); + + /// \brief Like \c replaceWhitespace, but additionally adds right-aligned + /// backslashes to escape newlines inside a preprocessor directive. + /// + /// This function and \c replaceWhitespace have the same behavior if + /// \c Newlines == 0. + void replacePPWhitespace(const AnnotatedToken &Tok, unsigned NewLines, + unsigned Spaces, unsigned WhitespaceStartColumn); + + /// \brief Inserts a line break into the middle of a token. + /// + /// Will break at \p Offset inside \p Tok, putting \p Prefix before the line + /// break and \p Postfix before the rest of the token starts in the next line. + /// + /// \p InPPDirective, \p Spaces, \p WhitespaceStartColumn and \p Style are + /// used to generate the correct line break. + void breakToken(const FormatToken &Tok, unsigned Offset, + unsigned ReplaceChars, StringRef Prefix, StringRef Postfix, + bool InPPDirective, unsigned Spaces, + unsigned WhitespaceStartColumn); + + /// \brief Returns all the \c Replacements created during formatting. + const tooling::Replacements &generateReplacements(); + + void addReplacement(const SourceLocation &SourceLoc, unsigned ReplaceChars, + StringRef Text); + + void addUntouchableComment(unsigned Column); + + /// \brief Try to align all stashed comments. + void alignComments(); + /// \brief Try to align all stashed escaped newlines. + void alignEscapedNewlines(); + +private: + std::string getNewLineText(unsigned NewLines, unsigned Spaces); + + std::string getNewLineText(unsigned NewLines, unsigned Spaces, + unsigned WhitespaceStartColumn, + unsigned EscapedNewlineColumn); + + /// \brief Structure to store tokens for later layout and alignment. + struct StoredToken { + StoredToken(SourceLocation ReplacementLoc, unsigned ReplacementLength, + unsigned MinColumn, unsigned MaxColumn, unsigned NewLines, + unsigned Spaces) + : ReplacementLoc(ReplacementLoc), ReplacementLength(ReplacementLength), + MinColumn(MinColumn), MaxColumn(MaxColumn), NewLines(NewLines), + Spaces(Spaces), Untouchable(false) {} + SourceLocation ReplacementLoc; + unsigned ReplacementLength; + unsigned MinColumn; + unsigned MaxColumn; + unsigned NewLines; + unsigned Spaces; + bool Untouchable; + std::string Prefix; + std::string Postfix; + }; + SmallVector<StoredToken, 16> Comments; + SmallVector<StoredToken, 16> EscapedNewlines; + typedef SmallVector<StoredToken, 16>::iterator token_iterator; + + /// \brief Put all the comments between \p I and \p E into \p Column. + void alignComments(token_iterator I, token_iterator E, unsigned Column); + + /// \brief Stores \p Text as the replacement for the whitespace in front of + /// \p Tok. + void storeReplacement(SourceLocation Loc, unsigned Length, + const std::string Text); + + SourceManager &SourceMgr; + tooling::Replacements Replaces; + const FormatStyle &Style; +}; + +} // namespace format +} // namespace clang + +#endif // LLVM_CLANG_FORMAT_WHITESPACEMANAGER_H diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 936bd2f8a4..4a63d76a73 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -463,6 +463,10 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "<class template> " << *CTD << '\n'; break; } + case Decl::OMPThreadPrivate: { + Out << "<omp threadprivate> " << '"' << *I << "\"\n"; + break; + } default: Out << "DeclKind: " << DK << '"' << *I << "\"\n"; llvm_unreachable("decl unhandled"); diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp index bfb30836d8..b6c644eba7 100644 --- a/lib/Frontend/ASTMerge.cpp +++ b/lib/Frontend/ASTMerge.cpp @@ -34,7 +34,7 @@ bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI, void ASTMergeAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); CI.getDiagnostics().getClient()->BeginSourceFile( - CI.getASTContext().getLangOpts()); + CI.getASTContext().getLangOpts()); CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument, &CI.getASTContext()); IntrusiveRefCntPtr<DiagnosticIDs> @@ -42,8 +42,9 @@ void ASTMergeAction::ExecuteAction() { for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) { IntrusiveRefCntPtr<DiagnosticsEngine> Diags(new DiagnosticsEngine(DiagIDs, &CI.getDiagnosticOpts(), - CI.getDiagnostics().getClient(), - /*ShouldOwnClient=*/false)); + new ForwardingDiagnosticConsumer( + *CI.getDiagnostics().getClient()), + /*ShouldOwnClient=*/true)); ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags, CI.getFileSystemOpts(), false); if (!Unit) diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 4a956ff3ab..8bd5172454 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -236,6 +236,11 @@ ASTUnit::ASTUnit(bool _MainFileIsAST) } ASTUnit::~ASTUnit() { + // If we loaded from an AST file, balance out the BeginSourceFile call. + if (MainFileIsAST && getDiagnostics().getClient()) { + getDiagnostics().getClient()->EndSourceFile(); + } + clearFileLevelDecls(); // Clean up the temporary files and the preamble file. @@ -581,25 +586,24 @@ private: } }; + /// \brief Diagnostic consumer that saves each diagnostic it is given. class StoredDiagnosticConsumer : public DiagnosticConsumer { SmallVectorImpl<StoredDiagnostic> &StoredDiags; - + SourceManager *SourceMgr; + public: explicit StoredDiagnosticConsumer( SmallVectorImpl<StoredDiagnostic> &StoredDiags) - : StoredDiags(StoredDiags) { } - + : StoredDiags(StoredDiags), SourceMgr(0) { } + + virtual void BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP = 0) { + if (PP) + SourceMgr = &PP->getSourceManager(); + } + virtual void HandleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info); - - DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { - // Just drop any diagnostics that come from cloned consumers; they'll - // have different source managers anyway. - // FIXME: We'd like to be able to capture these somehow, even if it's just - // file/line/column, because they could occur when parsing module maps or - // building modules on-demand. - return new IgnoringDiagConsumer(); - } }; /// \brief RAII object that optionally captures diagnostics, if @@ -635,7 +639,11 @@ void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level, // Default implementation (Warnings/errors count). DiagnosticConsumer::HandleDiagnostic(Level, Info); - StoredDiags.push_back(StoredDiagnostic(Level, Info)); + // Only record the diagnostic if it's part of the source manager we know + // about. This effectively drops diagnostics from modules we're building. + // FIXME: In the long run, ee don't want to drop source managers from modules. + if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) + StoredDiags.push_back(StoredDiagnostic(Level, Info)); } ASTDeserializationListener *ASTUnit::getDeserializationListener() { @@ -662,8 +670,7 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags, Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics); Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(), Client, - /*ShouldOwnClient=*/true, - /*ShouldCloneClient=*/false); + /*ShouldOwnClient=*/true); } else if (CaptureDiagnostics) { Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics)); } @@ -801,6 +808,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, break; case ASTReader::Failure: + case ASTReader::Missing: case ASTReader::OutOfDate: case ASTReader::VersionMismatch: case ASTReader::ConfigurationMismatch: @@ -834,6 +842,9 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, ReaderPtr->InitializeSema(*AST->TheSema); AST->Reader = ReaderPtr; + // Tell the diagnostic client that we have started a source file. + AST->getDiagnostics().getClient()->BeginSourceFile(Context.getLangOpts(),&PP); + return AST.take(); } @@ -1026,16 +1037,17 @@ public: } -static void checkAndRemoveNonDriverDiags(SmallVectorImpl<StoredDiagnostic> & - StoredDiagnostics) { +static bool isNonDriverDiag(const StoredDiagnostic &StoredDiag) { + return StoredDiag.getLocation().isValid(); +} + +static void +checkAndRemoveNonDriverDiags(SmallVectorImpl<StoredDiagnostic> &StoredDiags) { // Get rid of stored diagnostics except the ones from the driver which do not // have a source location. - for (unsigned I = 0; I < StoredDiagnostics.size(); ++I) { - if (StoredDiagnostics[I].getLocation().isValid()) { - StoredDiagnostics.erase(StoredDiagnostics.begin()+I); - --I; - } - } + StoredDiags.erase( + std::remove_if(StoredDiags.begin(), StoredDiags.end(), isNonDriverDiag), + StoredDiags.end()); } static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> & diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp index f414f93812..cde84caade 100644 --- a/lib/Frontend/ChainedIncludesSource.cpp +++ b/lib/Frontend/ChainedIncludesSource.cpp @@ -47,6 +47,7 @@ static ASTReader *createASTReader(CompilerInstance &CI, return Reader.take(); case ASTReader::Failure: + case ASTReader::Missing: case ASTReader::OutOfDate: case ASTReader::VersionMismatch: case ASTReader::ConfigurationMismatch: @@ -112,8 +113,6 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { OwningPtr<ASTConsumer> consumer; consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", 0, /*isysroot=*/"", &OS)); - Clang->getPreprocessor().setPPMutationListener( - consumer->GetPPMutationListener()); Clang->getASTContext().setASTMutationListener( consumer->GetASTMutationListener()); Clang->setASTConsumer(consumer.take()); @@ -144,6 +143,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { Clang->getASTConsumer().GetASTDeserializationListener())); if (!Reader) return 0; + Clang->setModuleManager(static_cast<ASTReader*>(Reader.get())); Clang->getASTContext().setExternalSource(Reader); } diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index ce6572aa1b..cf856fc2ab 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -44,6 +44,8 @@ #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" +#include <sys/stat.h> +#include <time.h> using namespace clang; @@ -62,7 +64,8 @@ void CompilerInstance::setInvocation(CompilerInvocation *Value) { bool CompilerInstance::shouldBuildGlobalModuleIndex() const { return (BuildGlobalModuleIndex || - (ModuleManager && ModuleManager->isGlobalIndexUnavailable())) && + (ModuleManager && ModuleManager->isGlobalIndexUnavailable() && + getFrontendOpts().GenerateGlobalModuleIndex)) && !ModuleBuildFailed; } @@ -152,18 +155,15 @@ static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts, } void CompilerInstance::createDiagnostics(DiagnosticConsumer *Client, - bool ShouldOwnClient, - bool ShouldCloneClient) { + bool ShouldOwnClient) { Diagnostics = createDiagnostics(&getDiagnosticOpts(), Client, - ShouldOwnClient, ShouldCloneClient, - &getCodeGenOpts()); + ShouldOwnClient, &getCodeGenOpts()); } IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(DiagnosticOptions *Opts, DiagnosticConsumer *Client, bool ShouldOwnClient, - bool ShouldCloneClient, const CodeGenOptions *CodeGenOpts) { IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> @@ -172,10 +172,7 @@ CompilerInstance::createDiagnostics(DiagnosticOptions *Opts, // Create the diagnostic client for reporting errors or for // implementing -verify. if (Client) { - if (ShouldCloneClient) - Diags->setClient(Client->clone(*Diags), ShouldOwnClient); - else - Diags->setClient(Client, ShouldOwnClient); + Diags->setClient(Client, ShouldOwnClient); } else Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); @@ -338,6 +335,7 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path, // Unrecoverable failure: don't even try to process the input file. break; + case ASTReader::Missing: case ASTReader::OutOfDate: case ASTReader::VersionMismatch: case ASTReader::ConfigurationMismatch: @@ -864,9 +862,10 @@ static void compileModule(CompilerInstance &ImportingInstance, // module. CompilerInstance Instance; Instance.setInvocation(&*Invocation); - Instance.createDiagnostics(&ImportingInstance.getDiagnosticClient(), - /*ShouldOwnClient=*/true, - /*ShouldCloneClient=*/true); + + Instance.createDiagnostics(new ForwardingDiagnosticConsumer( + ImportingInstance.getDiagnosticClient()), + /*ShouldOwnClient=*/true); // Note that this module is part of the module build stack, so that we // can detect cycles in the module graph. @@ -888,6 +887,7 @@ static void compileModule(CompilerInstance &ImportingInstance, llvm::CrashRecoveryContext CRC; CompileModuleMapData Data = { Instance, CreateModuleAction }; CRC.RunSafelyOnThread(&doCompileMapModule, &Data, ThreadStackSize); + // Delete the temporary module map file. // FIXME: Even though we're executing under crash protection, it would still @@ -904,6 +904,183 @@ static void compileModule(CompilerInstance &ImportingInstance, } } +/// \brief Diagnose differences between the current definition of the given +/// configuration macro and the definition provided on the command line. +static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro, + Module *Mod, SourceLocation ImportLoc) { + IdentifierInfo *Id = PP.getIdentifierInfo(ConfigMacro); + SourceManager &SourceMgr = PP.getSourceManager(); + + // If this identifier has never had a macro definition, then it could + // not have changed. + if (!Id->hadMacroDefinition()) + return; + + // If this identifier does not currently have a macro definition, + // check whether it had one on the command line. + if (!Id->hasMacroDefinition()) { + MacroDirective::DefInfo LatestDef = + PP.getMacroDirectiveHistory(Id)->getDefinition(); + for (MacroDirective::DefInfo Def = LatestDef; Def; + Def = Def.getPreviousDefinition()) { + FileID FID = SourceMgr.getFileID(Def.getLocation()); + if (FID.isInvalid()) + continue; + + // We only care about the predefines buffer. + if (FID != PP.getPredefinesFileID()) + continue; + + // This macro was defined on the command line, then #undef'd later. + // Complain. + PP.Diag(ImportLoc, diag::warn_module_config_macro_undef) + << true << ConfigMacro << Mod->getFullModuleName(); + if (LatestDef.isUndefined()) + PP.Diag(LatestDef.getUndefLocation(), diag::note_module_def_undef_here) + << true; + return; + } + + // Okay: no definition in the predefines buffer. + return; + } + + // This identifier has a macro definition. Check whether we had a definition + // on the command line. + MacroDirective::DefInfo LatestDef = + PP.getMacroDirectiveHistory(Id)->getDefinition(); + MacroDirective::DefInfo PredefinedDef; + for (MacroDirective::DefInfo Def = LatestDef; Def; + Def = Def.getPreviousDefinition()) { + FileID FID = SourceMgr.getFileID(Def.getLocation()); + if (FID.isInvalid()) + continue; + + // We only care about the predefines buffer. + if (FID != PP.getPredefinesFileID()) + continue; + + PredefinedDef = Def; + break; + } + + // If there was no definition for this macro in the predefines buffer, + // complain. + if (!PredefinedDef || + (!PredefinedDef.getLocation().isValid() && + PredefinedDef.getUndefLocation().isValid())) { + PP.Diag(ImportLoc, diag::warn_module_config_macro_undef) + << false << ConfigMacro << Mod->getFullModuleName(); + PP.Diag(LatestDef.getLocation(), diag::note_module_def_undef_here) + << false; + return; + } + + // If the current macro definition is the same as the predefined macro + // definition, it's okay. + if (LatestDef.getMacroInfo() == PredefinedDef.getMacroInfo() || + LatestDef.getMacroInfo()->isIdenticalTo(*PredefinedDef.getMacroInfo(),PP, + /*Syntactically=*/true)) + return; + + // The macro definitions differ. + PP.Diag(ImportLoc, diag::warn_module_config_macro_undef) + << false << ConfigMacro << Mod->getFullModuleName(); + PP.Diag(LatestDef.getLocation(), diag::note_module_def_undef_here) + << false; +} + +/// \brief Write a new timestamp file with the given path. +static void writeTimestampFile(StringRef TimestampFile) { + std::string ErrorInfo; + llvm::raw_fd_ostream Out(TimestampFile.str().c_str(), ErrorInfo, + llvm::raw_fd_ostream::F_Binary); +} + +/// \brief Prune the module cache of modules that haven't been accessed in +/// a long time. +static void pruneModuleCache(const HeaderSearchOptions &HSOpts) { + struct stat StatBuf; + llvm::SmallString<128> TimestampFile; + TimestampFile = HSOpts.ModuleCachePath; + llvm::sys::path::append(TimestampFile, "modules.timestamp"); + + // Try to stat() the timestamp file. + if (::stat(TimestampFile.c_str(), &StatBuf)) { + // If the timestamp file wasn't there, create one now. + if (errno == ENOENT) { + writeTimestampFile(TimestampFile); + } + return; + } + + // Check whether the time stamp is older than our pruning interval. + // If not, do nothing. + time_t TimeStampModTime = StatBuf.st_mtime; + time_t CurrentTime = time(0); + if (CurrentTime - TimeStampModTime <= time_t(HSOpts.ModuleCachePruneInterval)) + return; + + // Write a new timestamp file so that nobody else attempts to prune. + // There is a benign race condition here, if two Clang instances happen to + // notice at the same time that the timestamp is out-of-date. + writeTimestampFile(TimestampFile); + + // Walk the entire module cache, looking for unused module files and module + // indices. + llvm::error_code EC; + SmallString<128> ModuleCachePathNative; + llvm::sys::path::native(HSOpts.ModuleCachePath, ModuleCachePathNative); + for (llvm::sys::fs::directory_iterator + Dir(ModuleCachePathNative.str(), EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + // If we don't have a directory, there's nothing to look into. + bool IsDirectory; + if (llvm::sys::fs::is_directory(Dir->path(), IsDirectory) || !IsDirectory) + continue; + + // Walk all of the files within this directory. + bool RemovedAllFiles = true; + for (llvm::sys::fs::directory_iterator File(Dir->path(), EC), FileEnd; + File != FileEnd && !EC; File.increment(EC)) { + // We only care about module and global module index files. + if (llvm::sys::path::extension(File->path()) != ".pcm" && + llvm::sys::path::filename(File->path()) != "modules.idx") { + RemovedAllFiles = false; + continue; + } + + // Look at this file. If we can't stat it, there's nothing interesting + // there. + if (::stat(File->path().c_str(), &StatBuf)) { + RemovedAllFiles = false; + continue; + } + + // If the file has been used recently enough, leave it there. + time_t FileAccessTime = StatBuf.st_atime; + if (CurrentTime - FileAccessTime <= + time_t(HSOpts.ModuleCachePruneAfter)) { + RemovedAllFiles = false; + continue; + } + + // Remove the file. + bool Existed; + if (llvm::sys::fs::remove(File->path(), Existed) || !Existed) { + RemovedAllFiles = false; + } + } + + // If we removed all of the files in the directory, remove the directory + // itself. + if (RemovedAllFiles) { + bool Existed; + llvm::sys::fs::remove(Dir->path(), Existed); + } + } +} + ModuleLoadResult CompilerInstance::loadModule(SourceLocation ImportLoc, ModuleIdPath Path, @@ -916,7 +1093,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, // Make the named module visible. if (LastModuleImportResult) ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility, - ImportLoc); + ImportLoc, /*Complain=*/false); return LastModuleImportResult; } @@ -945,93 +1122,19 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, } else ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(ModuleName); - if (ModuleFileName.empty()) { - getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) - << ModuleName - << SourceRange(ImportLoc, ModuleNameLoc); - LastModuleImportLoc = ImportLoc; - LastModuleImportResult = ModuleLoadResult(); - return LastModuleImportResult; - } - - const FileEntry *ModuleFile - = getFileManager().getFile(ModuleFileName, /*OpenFile=*/false, - /*CacheFailure=*/false); - bool BuildingModule = false; - if (!ModuleFile && Module) { - // The module is not cached, but we have a module map from which we can - // build the module. - - // Check whether there is a cycle in the module graph. - ModuleBuildStack Path = getSourceManager().getModuleBuildStack(); - ModuleBuildStack::iterator Pos = Path.begin(), PosEnd = Path.end(); - for (; Pos != PosEnd; ++Pos) { - if (Pos->first == ModuleName) - break; - } - - if (Pos != PosEnd) { - SmallString<256> CyclePath; - for (; Pos != PosEnd; ++Pos) { - CyclePath += Pos->first; - CyclePath += " -> "; - } - CyclePath += ModuleName; - - getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle) - << ModuleName << CyclePath; - return ModuleLoadResult(); - } - - // Check whether we have already attempted to build this module (but - // failed). - if (getPreprocessorOpts().FailedModules && - getPreprocessorOpts().FailedModules->hasAlreadyFailed(ModuleName)) { - getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built) - << ModuleName - << SourceRange(ImportLoc, ModuleNameLoc); - ModuleBuildFailed = true; - return ModuleLoadResult(); - } - - BuildingModule = true; - compileModule(*this, ModuleNameLoc, Module, ModuleFileName); - ModuleFile = FileMgr->getFile(ModuleFileName, /*OpenFile=*/false, - /*CacheFailure=*/false); - - if (!ModuleFile && getPreprocessorOpts().FailedModules) - getPreprocessorOpts().FailedModules->addFailed(ModuleName); - } - - if (!ModuleFile) { - getDiagnostics().Report(ModuleNameLoc, - BuildingModule? diag::err_module_not_built - : diag::err_module_not_found) - << ModuleName - << SourceRange(ImportLoc, ModuleNameLoc); - ModuleBuildFailed = true; - return ModuleLoadResult(); - } - - // If there is already a module file associated with this module, make sure - // it is the same as the module file we're looking for. Otherwise, we - // have two module files for the same module. - if (const FileEntry *CurModuleFile = Module? Module->getASTFile() : 0) { - if (CurModuleFile != ModuleFile) { - getDiagnostics().Report(ModuleNameLoc, diag::err_module_file_conflict) - << ModuleName - << CurModuleFile->getName() - << ModuleFile->getName(); - ModuleBuildFailed = true; - return ModuleLoadResult(); - } - } - // If we don't already have an ASTReader, create one now. if (!ModuleManager) { if (!hasASTContext()) createASTContext(); + // If we're not recursively building a module, check whether we + // need to prune the module cache. + if (getSourceManager().getModuleBuildStack().empty() && + getHeaderSearchOpts().ModuleCachePruneInterval > 0 && + getHeaderSearchOpts().ModuleCachePruneAfter > 0) { + pruneModuleCache(getHeaderSearchOpts()); + } + std::string Sysroot = getHeaderSearchOpts().Sysroot; const PreprocessorOptions &PPOpts = getPreprocessorOpts(); ModuleManager = new ASTReader(getPreprocessor(), *Context, @@ -1044,8 +1147,6 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, getASTConsumer().GetASTDeserializationListener()); getASTContext().setASTMutationListener( getASTConsumer().GetASTMutationListener()); - getPreprocessor().setPPMutationListener( - getASTConsumer().GetPPMutationListener()); } OwningPtr<ExternalASTSource> Source; Source.reset(ModuleManager); @@ -1056,21 +1157,53 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, ModuleManager->StartTranslationUnit(&getASTConsumer()); } - // Try to load the module we found. - unsigned ARRFlags = ASTReader::ARR_None; - if (Module) - ARRFlags |= ASTReader::ARR_OutOfDate; - switch (ModuleManager->ReadAST(ModuleFile->getName(), - serialization::MK_Module, ImportLoc, - ARRFlags)) { + // Try to load the module file. + unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing; + switch (ModuleManager->ReadAST(ModuleFileName, serialization::MK_Module, + ImportLoc, ARRFlags)) { case ASTReader::Success: break; case ASTReader::OutOfDate: { - // The module file is out-of-date. Rebuild it. - getFileManager().invalidateCache(ModuleFile); + // The module file is out-of-date. Remove it, then rebuild it. bool Existed; llvm::sys::fs::remove(ModuleFileName, Existed); + } + // Fall through to build the module again. + + case ASTReader::Missing: { + // The module file is (now) missing. Build it. + + // If we don't have a module, we don't know how to build the module file. + // Complain and return. + if (!Module) { + getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) + << ModuleName + << SourceRange(ImportLoc, ModuleNameLoc); + ModuleBuildFailed = true; + return ModuleLoadResult(); + } + + // Check whether there is a cycle in the module graph. + ModuleBuildStack ModPath = getSourceManager().getModuleBuildStack(); + ModuleBuildStack::iterator Pos = ModPath.begin(), PosEnd = ModPath.end(); + for (; Pos != PosEnd; ++Pos) { + if (Pos->first == ModuleName) + break; + } + + if (Pos != PosEnd) { + SmallString<256> CyclePath; + for (; Pos != PosEnd; ++Pos) { + CyclePath += Pos->first; + CyclePath += " -> "; + } + CyclePath += ModuleName; + + getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle) + << ModuleName << CyclePath; + return ModuleLoadResult(); + } // Check whether we have already attempted to build this module (but // failed). @@ -1083,15 +1216,23 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, return ModuleLoadResult(); } + // Try to compile the module. compileModule(*this, ModuleNameLoc, Module, ModuleFileName); - // Try loading the module again. - ModuleFile = FileMgr->getFile(ModuleFileName, /*OpenFile=*/false, - /*CacheFailure=*/false); - if (!ModuleFile || - ModuleManager->ReadAST(ModuleFileName, + // Try to read the module file, now that we've compiled it. + ASTReader::ASTReadResult ReadResult + = ModuleManager->ReadAST(ModuleFileName, serialization::MK_Module, ImportLoc, - ASTReader::ARR_None) != ASTReader::Success) { + ASTReader::ARR_Missing); + if (ReadResult != ASTReader::Success) { + if (ReadResult == ASTReader::Missing) { + getDiagnostics().Report(ModuleNameLoc, + Module? diag::err_module_not_built + : diag::err_module_not_found) + << ModuleName + << SourceRange(ImportLoc, ModuleNameLoc); + } + if (getPreprocessorOpts().FailedModules) getPreprocessorOpts().FailedModules->addFailed(ModuleName); KnownModules[Path[0].first] = 0; @@ -1125,10 +1266,6 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, .findModule((Path[0].first->getName())); } - if (Module) { - Module->setASTFile(ModuleFile); - } - // Cache the result of this top-level module lookup for later. Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first; } @@ -1220,9 +1357,17 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, return ModuleLoadResult(); } - ModuleManager->makeModuleVisible(Module, Visibility, ImportLoc); + ModuleManager->makeModuleVisible(Module, Visibility, ImportLoc, + /*Complain=*/true); } - + + // Check for any configuration macros that have changed. + clang::Module *TopModule = Module->getTopLevelModule(); + for (unsigned I = 0, N = TopModule->ConfigMacros.size(); I != N; ++I) { + checkConfigMacro(getPreprocessor(), TopModule->ConfigMacros[I], + Module, ImportLoc); + } + // If this module import was due to an inclusion directive, create an // implicit import declaration to capture it in the AST. if (IsInclusionDirective && hasASTContext()) { @@ -1242,7 +1387,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, void CompilerInstance::makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, - SourceLocation ImportLoc){ - ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc); + SourceLocation ImportLoc, + bool Complain){ + ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc, Complain); } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 3c5954a696..42ea96f0f2 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -29,6 +29,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" #include "llvm/Support/Path.h" +#include "llvm/Support/system_error.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -68,6 +69,9 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, if (A->getOption().matches(options::OPT_O0)) return 0; + if (A->getOption().matches(options::OPT_Ofast)) + return 3; + assert (A->getOption().matches(options::OPT_O)); StringRef S(A->getValue()); @@ -80,8 +84,7 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, return DefaultOpt; } -static unsigned getOptimizationLevelSize(ArgList &Args, InputKind IK, - DiagnosticsEngine &Diags) { +static unsigned getOptimizationLevelSize(ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { if (A->getOption().matches(options::OPT_O)) { switch (A->getValue()[0]) { @@ -281,6 +284,7 @@ static bool ParseMigratorArgs(MigratorOptions &Opts, ArgList &Args) { static void ParseCommentArgs(CommentOptions &Opts, ArgList &Args) { Opts.BlockCommandNames = Args.getAllArgValues(OPT_fcomment_block_commands); + Opts.ParseAllComments = Args.hasArg(OPT_fparse_all_comments); } static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, @@ -317,23 +321,24 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); - Opts.ModulesAutolink = Args.hasArg(OPT_fmodules_autolink); Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables); Opts.UseRegisterSizedBitfieldAccess = Args.hasArg( OPT_fuse_register_sized_bitfield_access); Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing); + Opts.StructPathTBAA = Args.hasArg(OPT_struct_path_tbaa); Opts.DwarfDebugFlags = Args.getLastArgValue(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); - Opts.OptimizeSize = getOptimizationLevelSize(Args, IK, Diags); + Opts.OptimizeSize = getOptimizationLevelSize(Args); Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) || Args.hasArg(OPT_ffreestanding)); Opts.UnrollLoops = Args.hasArg(OPT_funroll_loops) || (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize); + Opts.Autolink = !Args.hasArg(OPT_fno_autolink); Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device); @@ -358,6 +363,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags); Opts.NoGlobalMerge = Args.hasArg(OPT_mno_global_merge); Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); + Opts.EnableSegmentedStacks = Args.hasArg(OPT_split_stacks); Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer); Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels); @@ -380,13 +386,14 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); Opts.SanitizeRecover = !Args.hasArg(OPT_fno_sanitize_recover); + Opts.DisableGCov = Args.hasArg(OPT_test_coverage); Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data); Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes); if (Opts.EmitGcovArcs || Opts.EmitGcovNotes) { Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file); Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum); - Opts.CoverageFunctionNamesInData = - Args.hasArg(OPT_coverage_function_names_in_data); + Opts.CoverageNoFunctionNamesInData = + Args.hasArg(OPT_coverage_no_function_names_in_data); if (Args.hasArg(OPT_coverage_version_EQ)) { StringRef CoverageVersion = Args.getLastArgValue(OPT_coverage_version_EQ); if (CoverageVersion.size() != 4) { @@ -394,10 +401,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, << Args.getLastArg(OPT_coverage_version_EQ)->getAsString(Args) << CoverageVersion; } else { - Opts.CoverageVersion[0] = CoverageVersion[3]; - Opts.CoverageVersion[1] = CoverageVersion[2]; - Opts.CoverageVersion[2] = CoverageVersion[1]; - Opts.CoverageVersion[3] = CoverageVersion[0]; + memcpy(Opts.CoverageVersion, CoverageVersion.data(), 4); } } } @@ -645,6 +649,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::InitOnly; break; case OPT_fsyntax_only: Opts.ProgramAction = frontend::ParseSyntaxOnly; break; + case OPT_module_file_info: + Opts.ProgramAction = frontend::ModuleFileInfo; break; case OPT_print_decl_contexts: Opts.ProgramAction = frontend::PrintDeclContext; break; case OPT_print_preamble: @@ -780,7 +786,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Case("objective-c-header", IK_ObjC) .Case("c++-header", IK_CXX) .Case("objective-c++-header", IK_ObjCXX) - .Case("ast", IK_AST) + .Cases("ast", "pcm", IK_AST) .Case("ir", IK_LLVM_IR) .Default(IK_None); if (DashX == IK_None) @@ -837,7 +843,10 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir); Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodules_cache_path); Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); - + Opts.ModuleCachePruneInterval + = Args.getLastArgIntValue(OPT_fmodules_prune_interval, 7*24*60*60); + Opts.ModuleCachePruneAfter + = Args.getLastArgIntValue(OPT_fmodules_prune_after, 31*24*60*60); for (arg_iterator it = Args.filtered_begin(OPT_fmodules_ignore_macro), ie = Args.filtered_end(); it != ie; ++it) { StringRef MacroDef = (*it)->getValue(); @@ -1171,9 +1180,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_pthread)) Opts.POSIXThreads = 1; - if (Args.hasArg(OPT_fdelayed_template_parsing)) - Opts.DelayedTemplateParsing = 1; - // The value-visibility mode defaults to "default". if (Arg *visOpt = Args.getLastArg(OPT_fvisibility)) { Opts.setValueVisibilityMode(parseVisibility(visOpt, Args, Diags)); @@ -1241,7 +1247,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.AccessControl = !Args.hasArg(OPT_fno_access_control); Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); Opts.MathErrno = Args.hasArg(OPT_fmath_errno); - Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 512, + Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 256, Diags); Opts.ConstexprCallDepth = Args.getLastArgIntValue(OPT_fconstexpr_depth, 512, Diags); @@ -1289,7 +1295,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // FIXME: Eliminate this dependency. unsigned Opt = getOptimizationLevel(Args, IK, Diags), - OptSize = getOptimizationLevelSize(Args, IK, Diags); + OptSize = getOptimizationLevelSize(Args); Opts.Optimize = Opt != 0; Opts.OptimizeSize = OptSize != 0; @@ -1463,6 +1469,7 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, case frontend::GeneratePCH: case frontend::GeneratePTH: case frontend::ParseSyntaxOnly: + case frontend::ModuleFileInfo: case frontend::PluginAction: case frontend::PrintDeclContext: case frontend::RewriteObjC: @@ -1625,6 +1632,8 @@ llvm::APInt ModuleSignature::getAsInteger() const { } std::string CompilerInvocation::getModuleHash() const { + // Note: For QoI reasons, the things we use as a hash here should all be + // dumped via the -module-info flag. using llvm::hash_code; using llvm::hash_value; using llvm::hash_combine; @@ -1678,5 +1687,21 @@ std::string CompilerInvocation::getModuleHash() const { hsOpts.UseStandardCXXIncludes, hsOpts.UseLibcxx); + // Darwin-specific hack: if we have a sysroot, use the contents of + // $sysroot/System/Library/CoreServices/SystemVersion.plist + // as part of the module hash. + if (!hsOpts.Sysroot.empty()) { + llvm::OwningPtr<llvm::MemoryBuffer> buffer; + SmallString<128> systemVersionFile; + systemVersionFile += hsOpts.Sysroot; + llvm::sys::path::append(systemVersionFile, "System"); + llvm::sys::path::append(systemVersionFile, "Library"); + llvm::sys::path::append(systemVersionFile, "CoreServices"); + llvm::sys::path::append(systemVersionFile, "SystemVersion.plist"); + if (!llvm::MemoryBuffer::getFile(systemVersionFile, buffer)) { + code = hash_combine(code, buffer.get()->getBuffer()); + } + } + return llvm::APInt(64, code).toString(36, /*Signed=*/false); } diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp index 53ea8befbc..628def68e5 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -151,12 +151,14 @@ void DependencyFileCallback::AddFilename(StringRef Filename) { Files.push_back(Filename); } -/// PrintFilename - GCC escapes spaces, but apparently not ' or " or other -/// scary characters. +/// PrintFilename - GCC escapes spaces, # and $, but apparently not ' or " or +/// other scary characters. static void PrintFilename(raw_ostream &OS, StringRef Filename) { for (unsigned i = 0, e = Filename.size(); i != e; ++i) { - if (Filename[i] == ' ') + if (Filename[i] == ' ' || Filename[i] == '#') OS << '\\'; + else if (Filename[i] == '$') // $ is escaped by $$. + OS << '$'; OS << Filename[i]; } } diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp index 3b4f55c6c4..4eee59548c 100644 --- a/lib/Frontend/DiagnosticRenderer.cpp +++ b/lib/Frontend/DiagnosticRenderer.cpp @@ -462,9 +462,8 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, Message << "expanded from here"; else Message << "expanded from macro '" << MacroName << "'"; - emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, - Message.str(), - SpellingRanges, ArrayRef<FixItHint>(), &SM); + emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(), + SpellingRanges, None, &SM); } DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {} diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 6d31c315b4..ece51a3570 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -188,6 +188,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, setCurrentInput(Input, AST); + // Inform the diagnostic client we are processing a source file. + CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0); + HasBegunSourceFile = true; + // Set the shared objects, these are reset when we finish processing the // file, otherwise the CompilerInstance will happily destroy them. CI.setFileManager(&AST->getFileManager()); @@ -283,8 +287,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, goto failure; CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener()); - CI.getPreprocessor().setPPMutationListener( - Consumer->GetPPMutationListener()); if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) { // Convert headers to PCH and chain them. @@ -292,6 +294,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, source.reset(ChainedIncludesSource::create(CI)); if (!source) goto failure; + CI.setModuleManager(static_cast<ASTReader*>( + &static_cast<ChainedIncludesSource*>(source.get())->getFinalReader())); CI.getASTContext().setExternalSource(source); } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 965e762d79..5c7567fa8c 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -19,6 +19,7 @@ #include "clang/Lex/Pragma.h" #include "clang/Lex/Preprocessor.h" #include "clang/Parse/Parser.h" +#include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/FileSystem.h" @@ -173,12 +174,12 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts, // Add includes for each of these headers. for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) { const FileEntry *Header = Module->Headers[I]; - Module->TopHeaders.insert(Header); + Module->addTopHeader(Header); addHeaderInclude(Header, Includes, LangOpts); } if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) { - Module->TopHeaders.insert(UmbrellaHeader); + Module->addTopHeader(UmbrellaHeader); if (Module->Parent) { // Include the umbrella header for submodules. addHeaderInclude(UmbrellaHeader, Includes, LangOpts); @@ -203,7 +204,7 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts, if (const FileEntry *Header = FileMgr.getFile(Dir->path())) { if (ModMap.isHeaderInUnavailableModule(Header)) continue; - Module->TopHeaders.insert(Header); + Module->addTopHeader(Header); } // Include this header umbrella header for submodules. @@ -316,6 +317,130 @@ ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, return new ASTConsumer(); } +ASTConsumer *DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + return new ASTConsumer(); +} + +namespace { + /// \brief AST reader listener that dumps module information for a module + /// file. + class DumpModuleInfoListener : public ASTReaderListener { + llvm::raw_ostream &Out; + + public: + DumpModuleInfoListener(llvm::raw_ostream &Out) : Out(Out) { } + +#define DUMP_BOOLEAN(Value, Text) \ + Out.indent(4) << Text << ": " << (Value? "Yes" : "No") << "\n" + + virtual bool ReadFullVersionInformation(StringRef FullVersion) { + Out.indent(2) + << "Generated by " + << (FullVersion == getClangFullRepositoryVersion()? "this" + : "a different") + << " Clang: " << FullVersion << "\n"; + return ASTReaderListener::ReadFullVersionInformation(FullVersion); + } + + virtual bool ReadLanguageOptions(const LangOptions &LangOpts, + bool Complain) { + Out.indent(2) << "Language options:\n"; +#define LANGOPT(Name, Bits, Default, Description) \ + DUMP_BOOLEAN(LangOpts.Name, Description); +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + Out.indent(4) << Description << ": " \ + << static_cast<unsigned>(LangOpts.get##Name()) << "\n"; +#define VALUE_LANGOPT(Name, Bits, Default, Description) \ + Out.indent(4) << Description << ": " << LangOpts.Name << "\n"; +#define BENIGN_LANGOPT(Name, Bits, Default, Description) +#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#include "clang/Basic/LangOptions.def" + return false; + } + + virtual bool ReadTargetOptions(const TargetOptions &TargetOpts, + bool Complain) { + Out.indent(2) << "Target options:\n"; + Out.indent(4) << " Triple: " << TargetOpts.Triple << "\n"; + Out.indent(4) << " CPU: " << TargetOpts.CPU << "\n"; + Out.indent(4) << " ABI: " << TargetOpts.ABI << "\n"; + Out.indent(4) << " C++ ABI: " << TargetOpts.CXXABI << "\n"; + Out.indent(4) << " Linker version: " << TargetOpts.LinkerVersion << "\n"; + + if (!TargetOpts.FeaturesAsWritten.empty()) { + Out.indent(4) << "Target features:\n"; + for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); + I != N; ++I) { + Out.indent(6) << TargetOpts.FeaturesAsWritten[I] << "\n"; + } + } + + return false; + } + + virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + bool Complain) { + Out.indent(2) << "Header search options:\n"; + Out.indent(4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n"; + DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes, + "Use builtin include directories [-nobuiltininc]"); + DUMP_BOOLEAN(HSOpts.UseStandardSystemIncludes, + "Use standard system include directories [-nostdinc]"); + DUMP_BOOLEAN(HSOpts.UseStandardCXXIncludes, + "Use standard C++ include directories [-nostdinc++]"); + DUMP_BOOLEAN(HSOpts.UseLibcxx, + "Use libc++ (rather than libstdc++) [-stdlib=]"); + return false; + } + + virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, + bool Complain, + std::string &SuggestedPredefines) { + Out.indent(2) << "Preprocessor options:\n"; + DUMP_BOOLEAN(PPOpts.UsePredefines, + "Uses compiler/target-specific predefines [-undef]"); + DUMP_BOOLEAN(PPOpts.DetailedRecord, + "Uses detailed preprocessing record (for indexing)"); + + if (!PPOpts.Macros.empty()) { + Out.indent(4) << "Predefined macros:\n"; + } + + for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator + I = PPOpts.Macros.begin(), IEnd = PPOpts.Macros.end(); + I != IEnd; ++I) { + Out.indent(6); + if (I->second) + Out << "-U"; + else + Out << "-D"; + Out << I->first << "\n"; + } + return false; + } +#undef DUMP_BOOLEAN + }; +} + +void DumpModuleInfoAction::ExecuteAction() { + // Set up the output file. + llvm::OwningPtr<llvm::raw_fd_ostream> OutFile; + StringRef OutputFileName = getCompilerInstance().getFrontendOpts().OutputFile; + if (!OutputFileName.empty() && OutputFileName != "-") { + std::string ErrorInfo; + OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str().c_str(), + ErrorInfo)); + } + llvm::raw_ostream &Out = OutFile.get()? *OutFile.get() : llvm::outs(); + + Out << "Information for module file '" << getCurrentFile() << "':\n"; + DumpModuleInfoListener Listener(Out); + ASTReader::readASTFileControlBlock(getCurrentFile(), + getCompilerInstance().getFileManager(), + Listener); +} + //===----------------------------------------------------------------------===// // Preprocessor Actions //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index ea4005f7c9..f1823c69e9 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -13,7 +13,7 @@ using namespace clang; InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) { return llvm::StringSwitch<InputKind>(Extension) - .Case("ast", IK_AST) + .Cases("ast", "pcm", IK_AST) .Case("c", IK_C) .Cases("S", "s", IK_Asm) .Case("i", IK_PreprocessedC) diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 35eec565f7..f4ca4d498a 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -410,16 +411,16 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp #endif break; case llvm::Triple::DragonFly: - AddPath("/usr/include/c++/4.1", CXXSystem, false); + if (llvm::sys::fs::exists("/usr/lib/gcc47")) + AddPath("/usr/include/c++/4.7", CXXSystem, false); + else + AddPath("/usr/include/c++/4.4", CXXSystem, false); break; case llvm::Triple::FreeBSD: // FreeBSD 8.0 // FreeBSD 7.3 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple); break; - case llvm::Triple::NetBSD: - AddGnuCPlusPlusIncludePaths("/usr/include/g++", "", "", "", triple); - break; case llvm::Triple::OpenBSD: { std::string t = triple.getTriple(); if (t.substr(0, 6) == "x86_64") diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index b74c3c0b1c..dc3ab53eda 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -302,12 +302,13 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, else if (!LangOpts.GNUMode && LangOpts.Digraphs) Builder.defineMacro("__STDC_VERSION__", "199409L"); } else { - // FIXME: LangOpts.CPlusPlus1y - + // FIXME: Use the right value for __cplusplus for C++1y once one is chosen. + if (LangOpts.CPlusPlus1y) + Builder.defineMacro("__cplusplus", "201305L"); // C++11 [cpp.predefined]p1: // The name __cplusplus is defined to the value 201103L when compiling a // C++ translation unit. - if (LangOpts.CPlusPlus11) + else if (LangOpts.CPlusPlus11) Builder.defineMacro("__cplusplus", "201103L"); // C++03 [cpp.predefined]p1: // The name __cplusplus is defined to the value 199711L when compiling a @@ -490,6 +491,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder); DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Builder); DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder); + DefineTypeSize("__SIZE_MAX__", TI.getSizeType(), TI, Builder); DefineTypeSizeof("__SIZEOF_DOUBLE__", TI.getDoubleWidth(), TI, Builder); DefineTypeSizeof("__SIZEOF_FLOAT__", TI.getFloatWidth(), TI, Builder); diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp index 0a22481cb6..2189b8658e 100644 --- a/lib/Frontend/LogDiagnosticPrinter.cpp +++ b/lib/Frontend/LogDiagnosticPrinter.cpp @@ -171,8 +171,3 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, Entries.push_back(DE); } -DiagnosticConsumer * -LogDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { - return new LogDiagnosticPrinter(OS, &*DiagOpts, /*OwnsOutputStream=*/false); -} - diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index d894939b4b..9fd3649435 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -127,10 +127,22 @@ public: virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID); + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FilenameRange, + const FileEntry *File, + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported); virtual void Ident(SourceLocation Loc, const std::string &str); + virtual void PragmaCaptured(SourceLocation Loc, StringRef Str); virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, const std::string &Str); - virtual void PragmaMessage(SourceLocation Loc, StringRef Str); + virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace, + PragmaMessageKind Kind, StringRef Str); + virtual void PragmaDebug(SourceLocation Loc, StringRef DebugType); virtual void PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace); virtual void PragmaDiagnosticPop(SourceLocation Loc, @@ -258,11 +270,12 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, if (IncludeLoc.isValid()) MoveToLine(IncludeLoc); } else if (Reason == PPCallbacks::SystemHeaderPragma) { - MoveToLine(NewLine); - - // TODO GCC emits the # directive for this directive on the line AFTER the - // directive and emits a bunch of spaces that aren't needed. Emulate this - // strange behavior. + // GCC emits the # directive for this directive on the line AFTER the + // directive and emits a bunch of spaces that aren't needed. This is because + // otherwise we will emit a line marker for THIS line, which requires an + // extra blank line after the directive to avoid making all following lines + // off by one. We can do better by simply incrementing NewLine here. + NewLine += 1; } CurLine = NewLine; @@ -305,6 +318,27 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, } } +void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FilenameRange, + const FileEntry *File, + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported) { + // When preprocessing, turn implicit imports into @imports. + // FIXME: This is a stop-gap until a more comprehensive "preprocessing with + // modules" solution is introduced. + if (Imported) { + startNewLineIfNeeded(); + MoveToLine(HashLoc); + OS << "@import " << Imported->getFullModuleName() << ";" + << " /* clang -E: implicit import for \"" << File->getName() << "\" */"; + EmittedTokensOnThisLine = true; + } +} + /// Ident - Handle #ident directives when read by the preprocessor. /// void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) { @@ -315,10 +349,19 @@ void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) { EmittedTokensOnThisLine = true; } +void PrintPPOutputPPCallbacks::PragmaCaptured(SourceLocation Loc, + StringRef Str) { + startNewLineIfNeeded(); + MoveToLine(Loc); + OS << "#pragma captured"; + + setEmittedDirectiveOnThisLine(); +} + /// MacroDefined - This hook is called whenever a macro definition is seen. void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) { - const MacroInfo *MI = MD->getInfo(); + const MacroInfo *MI = MD->getMacroInfo(); // Only print out macro definitions in -dD mode. if (!DumpDefines || // Ignore __FILE__ etc. @@ -367,12 +410,25 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc, } void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, + StringRef Namespace, + PragmaMessageKind Kind, StringRef Str) { startNewLineIfNeeded(); MoveToLine(Loc); - OS << "#pragma message("; - - OS << '"'; + OS << "#pragma "; + if (!Namespace.empty()) + OS << Namespace << ' '; + switch (Kind) { + case PMK_Message: + OS << "message(\""; + break; + case PMK_Warning: + OS << "warning \""; + break; + case PMK_Error: + OS << "error \""; + break; + } for (unsigned i = 0, e = Str.size(); i != e; ++i) { unsigned char Char = Str[i]; @@ -385,8 +441,19 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, << (char)('0'+ ((Char >> 0) & 7)); } OS << '"'; + if (Kind == PMK_Message) + OS << ')'; + setEmittedDirectiveOnThisLine(); +} + +void PrintPPOutputPPCallbacks::PragmaDebug(SourceLocation Loc, + StringRef DebugType) { + startNewLineIfNeeded(); + MoveToLine(Loc); + + OS << "#pragma clang __debug "; + OS << DebugType; - OS << ')'; setEmittedDirectiveOnThisLine(); } @@ -602,7 +669,7 @@ static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) { for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); I != E; ++I) { if (I->first->hasMacroDefinition()) - MacrosByID.push_back(id_macro_pair(I->first, I->second->getInfo())); + MacrosByID.push_back(id_macro_pair(I->first, I->second->getMacroInfo())); } llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare); diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp index 4bb662bb26..6514321f22 100644 --- a/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -114,10 +114,6 @@ public: virtual void finish(); - DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { - return new SDiagsWriter(State); - } - private: /// \brief Emit the preamble for the serialized diagnostics. void EmitPreamble(); diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp index c972461241..1572d0f1d0 100644 --- a/lib/Frontend/TextDiagnostic.cpp +++ b/lib/Frontend/TextDiagnostic.cpp @@ -958,7 +958,7 @@ static void highlightRange(const CharSourceRange &R, // Pick the last non-whitespace column. if (EndColNo > map.getSourceLine().size()) EndColNo = map.getSourceLine().size(); - while (EndColNo-1 && + while (EndColNo && (map.getSourceLine()[EndColNo-1] == ' ' || map.getSourceLine()[EndColNo-1] == '\t')) EndColNo = map.startOfPreviousColumn(EndColNo); @@ -1095,7 +1095,7 @@ void TextDiagnostic::emitSnippetAndCaret( unsigned ColNo = SM.getColumnNumber(FID, FileOffset); // Arbitrarily stop showing snippets when the line is too long. - static const ptrdiff_t MaxLineLengthToPrint = 4096; + static const size_t MaxLineLengthToPrint = 4096; if (ColNo > MaxLineLengthToPrint) return; @@ -1110,7 +1110,7 @@ void TextDiagnostic::emitSnippetAndCaret( ++LineEnd; // Arbitrarily stop showing snippets when the line is too long. - if (LineEnd - LineStart > MaxLineLengthToPrint) + if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint) return; // Copy the line of code into an std::string for ease of manipulation. diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp index 039475a2e0..5821436a30 100644 --- a/lib/Frontend/TextDiagnosticBuffer.cpp +++ b/lib/Frontend/TextDiagnosticBuffer.cpp @@ -75,6 +75,3 @@ void TextDiagnosticBuffer::FlushDiagnostics(DiagnosticsEngine &Diags) const { escapeDiag(it->second, Buf))); } -DiagnosticConsumer *TextDiagnosticBuffer::clone(DiagnosticsEngine &) const { - return new TextDiagnosticBuffer(); -} diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 010f649e6b..c22798af60 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -155,8 +155,3 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, OS.flush(); } - -DiagnosticConsumer * -TextDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { - return new TextDiagnosticPrinter(OS, &*DiagOpts, /*OwnsOutputStream=*/false); -} diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index 82f6e916e5..46745b6b9a 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -111,8 +111,13 @@ void VerifyDiagnosticConsumer::EndSourceFile() { void VerifyDiagnosticConsumer::HandleDiagnostic( DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { - if (Info.hasSourceManager()) + if (Info.hasSourceManager()) { + // If this diagnostic is for a different source manager, ignore it. + if (SrcManager && &Info.getSourceManager() != SrcManager) + return; + setSourceManager(Info.getSourceManager()); + } #ifndef NDEBUG // Debug build tracks unparsed files for possible @@ -278,8 +283,10 @@ private: /// /// Returns true if any valid directives were found. static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, - SourceLocation Pos, DiagnosticsEngine &Diags, + Preprocessor *PP, SourceLocation Pos, VerifyDiagnosticConsumer::DirectiveStatus &Status) { + DiagnosticsEngine &Diags = PP ? PP->getDiagnostics() : SM.getDiagnostics(); + // A single comment may contain multiple directives. bool FoundDirective = false; for (ParseHelper PH(S); !PH.Done();) { @@ -353,10 +360,30 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, else ExpectedLine -= Line; ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1); } - } else { + } else if (PH.Next(Line)) { // Absolute line number. - if (PH.Next(Line) && Line > 0) + if (Line > 0) ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1); + } else if (PP && PH.Search(":")) { + // Specific source file. + StringRef Filename(PH.C, PH.P-PH.C); + PH.Advance(); + + // Lookup file via Preprocessor, like a #include. + const DirectoryLookup *CurDir; + const FileEntry *FE = PP->LookupFile(Filename, false, NULL, CurDir, + NULL, NULL, 0); + if (!FE) { + Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), + diag::err_verify_missing_file) << Filename << KindStr; + continue; + } + + if (SM.translateFile(FE).isInvalid()) + SM.createFileID(FE, Pos, SrcMgr::C_User); + + if (PH.Next(Line) && Line > 0) + ExpectedLoc = SM.translateFileLineCol(FE, Line, 1); } if (ExpectedLoc.isInvalid()) { @@ -454,6 +481,11 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, SourceRange Comment) { SourceManager &SM = PP.getSourceManager(); + + // If this comment is for a different source manager, ignore it. + if (SrcManager && &SM != SrcManager) + return false; + SourceLocation CommentBegin = Comment.getBegin(); const char *CommentRaw = SM.getCharacterData(CommentBegin); @@ -465,7 +497,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, // Fold any "\<EOL>" sequences size_t loc = C.find('\\'); if (loc == StringRef::npos) { - ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics(), Status); + ParseDirective(C, &ED, SM, &PP, CommentBegin, Status); return false; } @@ -495,7 +527,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, } if (!C2.empty()) - ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics(), Status); + ParseDirective(C2, &ED, SM, &PP, CommentBegin, Status); return false; } @@ -530,8 +562,7 @@ static bool findDirectives(SourceManager &SM, FileID FID, if (Comment.empty()) continue; // Find first directive. - if (ParseDirective(Comment, 0, SM, Tok.getLocation(), - SM.getDiagnostics(), Status)) + if (ParseDirective(Comment, 0, SM, 0, Tok.getLocation(), Status)) return true; } return false; @@ -551,8 +582,13 @@ static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceM for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) { if (I->first.isInvalid() || !SourceMgr) OS << "\n (frontend)"; - else - OS << "\n Line " << SourceMgr->getPresumedLineNumber(I->first); + else { + OS << "\n "; + if (const FileEntry *File = SourceMgr->getFileEntryForID( + SourceMgr->getFileID(I->first))) + OS << " File " << File->getName(); + OS << " Line " << SourceMgr->getPresumedLineNumber(I->first); + } OS << ": " << I->second; } @@ -572,11 +608,12 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr llvm::raw_svector_ostream OS(Fmt); for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { Directive &D = **I; - OS << "\n Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc); + OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc) + << " Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc); if (D.DirectiveLoc != D.DiagnosticLoc) OS << " (directive at " - << SourceMgr.getFilename(D.DirectiveLoc) << ":" - << SourceMgr.getPresumedLineNumber(D.DirectiveLoc) << ")"; + << SourceMgr.getFilename(D.DirectiveLoc) << ':' + << SourceMgr.getPresumedLineNumber(D.DirectiveLoc) << ')'; OS << ": " << D.Text; } @@ -585,6 +622,22 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr return DL.size(); } +/// \brief Determine whether two source locations come from the same file. +static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc, + SourceLocation DiagnosticLoc) { + while (DiagnosticLoc.isMacroID()) + DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc); + + if (SM.isFromSameFile(DirectiveLoc, DiagnosticLoc)) + return true; + + const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc)); + if (!DiagFile && SM.isFromMainFile(DirectiveLoc)) + return true; + + return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc))); +} + /// CheckLists - Compare expected to seen diagnostic lists and return the /// the difference between them. /// @@ -607,6 +660,9 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, if (LineNo1 != LineNo2) continue; + if (!IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first)) + continue; + const std::string &RightText = II->second; if (D.match(RightText)) break; @@ -764,14 +820,6 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() { ED.Notes.clear(); } -DiagnosticConsumer * -VerifyDiagnosticConsumer::clone(DiagnosticsEngine &Diags) const { - if (!Diags.getClient()) - Diags.setClient(PrimaryClient->clone(Diags)); - - return new VerifyDiagnosticConsumer(Diags); -} - Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, StringRef Text, unsigned Min, unsigned Max) { diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp index ad8eb04768..b0d76da334 100644 --- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -62,6 +62,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { case GeneratePTH: return new GeneratePTHAction(); case InitOnly: return new InitOnlyAction(); case ParseSyntaxOnly: return new SyntaxOnlyAction(); + case ModuleFileInfo: return new DumpModuleInfoAction(); case PluginAction: { for (FrontendPluginRegistry::iterator it = diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt index ae689c37fa..8be33b7b4a 100644 --- a/lib/Headers/CMakeLists.txt +++ b/lib/Headers/CMakeLists.txt @@ -20,6 +20,8 @@ set(files nmmintrin.h pmmintrin.h popcntintrin.h + prfchwintrin.h + rdseedintrin.h rtmintrin.h smmintrin.h stdalign.h @@ -93,6 +95,14 @@ endif () add_custom_target(clang-headers ALL DEPENDS ${out_files}) set_target_properties(clang-headers PROPERTIES FOLDER "Misc") +if (other_output_dir) + if(UNIX) + add_custom_command(TARGET clang-headers POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${LLVM_BINARY_DIR}/lib/${CMAKE_CFG_INTDIR}" + COMMAND ${CMAKE_COMMAND} -E create_symlink "${LLVM_BINARY_DIR}/bin/lib/clang" "${LLVM_BINARY_DIR}/lib/${CMAKE_CFG_INTDIR}/clang") + endif() +endif () + install(FILES ${files} ${output_dir}/arm_neon.h PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ DESTINATION lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION}/include) diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h index 412d284f00..0683a65fac 100644 --- a/lib/Headers/avxintrin.h +++ b/lib/Headers/avxintrin.h @@ -1078,78 +1078,78 @@ _mm256_setzero_si256(void) /* Cast between vector types */ static __inline __m256 __attribute__((__always_inline__, __nodebug__)) -_mm256_castpd_ps(__m256d __in) +_mm256_castpd_ps(__m256d __a) { - return (__m256)__in; + return (__m256)__a; } static __inline __m256i __attribute__((__always_inline__, __nodebug__)) -_mm256_castpd_si256(__m256d __in) +_mm256_castpd_si256(__m256d __a) { - return (__m256i)__in; + return (__m256i)__a; } static __inline __m256d __attribute__((__always_inline__, __nodebug__)) -_mm256_castps_pd(__m256 __in) +_mm256_castps_pd(__m256 __a) { - return (__m256d)__in; + return (__m256d)__a; } static __inline __m256i __attribute__((__always_inline__, __nodebug__)) -_mm256_castps_si256(__m256 __in) +_mm256_castps_si256(__m256 __a) { - return (__m256i)__in; + return (__m256i)__a; } static __inline __m256 __attribute__((__always_inline__, __nodebug__)) -_mm256_castsi256_ps(__m256i __in) +_mm256_castsi256_ps(__m256i __a) { - return (__m256)__in; + return (__m256)__a; } static __inline __m256d __attribute__((__always_inline__, __nodebug__)) -_mm256_castsi256_pd(__m256i __in) +_mm256_castsi256_pd(__m256i __a) { - return (__m256d)__in; + return (__m256d)__a; } static __inline __m128d __attribute__((__always_inline__, __nodebug__)) -_mm256_castpd256_pd128(__m256d __in) +_mm256_castpd256_pd128(__m256d __a) { - return __builtin_shufflevector(__in, __in, 0, 1); + return __builtin_shufflevector(__a, __a, 0, 1); } static __inline __m128 __attribute__((__always_inline__, __nodebug__)) -_mm256_castps256_ps128(__m256 __in) +_mm256_castps256_ps128(__m256 __a) { - return __builtin_shufflevector(__in, __in, 0, 1, 2, 3); + return __builtin_shufflevector(__a, __a, 0, 1, 2, 3); } static __inline __m128i __attribute__((__always_inline__, __nodebug__)) -_mm256_castsi256_si128(__m256i __in) +_mm256_castsi256_si128(__m256i __a) { - return __builtin_shufflevector(__in, __in, 0, 1); + return __builtin_shufflevector(__a, __a, 0, 1); } static __inline __m256d __attribute__((__always_inline__, __nodebug__)) -_mm256_castpd128_pd256(__m128d __in) +_mm256_castpd128_pd256(__m128d __a) { __m128d __zero = _mm_setzero_pd(); - return __builtin_shufflevector(__in, __zero, 0, 1, 2, 2); + return __builtin_shufflevector(__a, __zero, 0, 1, 2, 2); } static __inline __m256 __attribute__((__always_inline__, __nodebug__)) -_mm256_castps128_ps256(__m128 __in) +_mm256_castps128_ps256(__m128 __a) { __m128 __zero = _mm_setzero_ps(); - return __builtin_shufflevector(__in, __zero, 0, 1, 2, 3, 4, 4, 4, 4); + return __builtin_shufflevector(__a, __zero, 0, 1, 2, 3, 4, 4, 4, 4); } static __inline __m256i __attribute__((__always_inline__, __nodebug__)) -_mm256_castsi128_si256(__m128i __in) +_mm256_castsi128_si256(__m128i __a) { __m128i __zero = _mm_setzero_si128(); - return __builtin_shufflevector(__in, __zero, 0, 1, 2, 2); + return __builtin_shufflevector(__a, __zero, 0, 1, 2, 2); } /* SIMD load ops (unaligned) */ diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h index 6d7d61d508..7b012384a2 100644 --- a/lib/Headers/cpuid.h +++ b/lib/Headers/cpuid.h @@ -25,9 +25,9 @@ #error this header is for x86 only #endif -static inline int __get_cpuid (unsigned int __level, unsigned int *__eax, - unsigned int *__ebx, unsigned int *__ecx, - unsigned int *__edx) { +static __inline int __get_cpuid (unsigned int __level, unsigned int *__eax, + unsigned int *__ebx, unsigned int *__ecx, + unsigned int *__edx) { __asm("cpuid" : "=a"(*__eax), "=b" (*__ebx), "=c"(*__ecx), "=d"(*__edx) : "0"(__level)); return 1; diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h index e18fae40ec..56c6c22855 100644 --- a/lib/Headers/emmintrin.h +++ b/lib/Headers/emmintrin.h @@ -1379,39 +1379,39 @@ _mm_movemask_pd(__m128d __a) __builtin_shufflevector(__a, __b, (i) & 1, (((i) & 2) >> 1) + 2); }) static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_castpd_ps(__m128d __in) +_mm_castpd_ps(__m128d __a) { - return (__m128)__in; + return (__m128)__a; } static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) -_mm_castpd_si128(__m128d __in) +_mm_castpd_si128(__m128d __a) { - return (__m128i)__in; + return (__m128i)__a; } static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) -_mm_castps_pd(__m128 __in) +_mm_castps_pd(__m128 __a) { - return (__m128d)__in; + return (__m128d)__a; } static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) -_mm_castps_si128(__m128 __in) +_mm_castps_si128(__m128 __a) { - return (__m128i)__in; + return (__m128i)__a; } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_castsi128_ps(__m128i __in) +_mm_castsi128_ps(__m128i __a) { - return (__m128)__in; + return (__m128)__a; } static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) -_mm_castsi128_pd(__m128i __in) +_mm_castsi128_pd(__m128i __a) { - return (__m128d)__in; + return (__m128d)__a; } static __inline__ void __attribute__((__always_inline__, __nodebug__)) diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h index cd733bfc71..fea7c3ba29 100644 --- a/lib/Headers/immintrin.h +++ b/lib/Headers/immintrin.h @@ -102,4 +102,13 @@ _rdrand64_step(unsigned long long *__p) #include <rtmintrin.h> #endif +/* FIXME: check __HLE__ as well when HLE is supported. */ +#if defined (__RTM__) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) +_xtest(void) +{ + return __builtin_ia32_xtest(); +} +#endif + #endif /* __IMMINTRIN_H */ diff --git a/lib/Headers/mm3dnow.h b/lib/Headers/mm3dnow.h index d5236f81ef..5242d99cbd 100644 --- a/lib/Headers/mm3dnow.h +++ b/lib/Headers/mm3dnow.h @@ -25,6 +25,7 @@ #define _MM3DNOW_H_INCLUDED #include <mmintrin.h> +#include <prfchwintrin.h> typedef float __v2sf __attribute__((__vector_size__(8))); diff --git a/lib/Headers/module.map b/lib/Headers/module.map index b24bccc120..aa219cb407 100644 --- a/lib/Headers/module.map +++ b/lib/Headers/module.map @@ -17,6 +17,7 @@ module _Builtin_intrinsics [system] { } explicit module cpuid { + requires x86 header "cpuid.h" } @@ -33,7 +34,6 @@ module _Builtin_intrinsics [system] { explicit module sse { requires sse export mmx - export * // note: for hackish <emmintrin.h> dependency header "xmmintrin.h" } diff --git a/lib/Headers/prfchwintrin.h b/lib/Headers/prfchwintrin.h new file mode 100644 index 0000000000..2d529c6634 --- /dev/null +++ b/lib/Headers/prfchwintrin.h @@ -0,0 +1,34 @@ +/*===---- prfchwintrin.h - PREFETCHW intrinsic -----------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#if !defined(__X86INTRIN_H) && !defined(_MM3DNOW_H_INCLUDED) +#error "Never use <prfchwintrin.h> directly; include <x86intrin.h> or <mm3dnow.h> instead." +#endif + +#if defined(__PRFCHW__) || defined(__3dNOW__) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) +_m_prefetchw(void *__P) +{ + __builtin_prefetch (__P, 1, 3 /* _MM_HINT_T0 */); +} +#endif diff --git a/lib/Headers/rdseedintrin.h b/lib/Headers/rdseedintrin.h new file mode 100644 index 0000000000..54aabd177a --- /dev/null +++ b/lib/Headers/rdseedintrin.h @@ -0,0 +1,48 @@ +/*===---- rdseedintrin.h - RDSEED intrinsics -------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __X86INTRIN_H +#error "Never use <rdseedintrin.h> directly; include <x86intrin.h> instead." +#endif + +#ifdef __RDSEED__ +static __inline__ int __attribute__((__always_inline__, __nodebug__)) +_rdseed16_step(unsigned short *__p) +{ + return __builtin_ia32_rdseed16_step(__p); +} + +static __inline__ int __attribute__((__always_inline__, __nodebug__)) +_rdseed32_step(unsigned int *__p) +{ + return __builtin_ia32_rdseed32_step(__p); +} + +#ifdef __x86_64__ +static __inline__ int __attribute__((__always_inline__, __nodebug__)) +_rdseed64_step(unsigned long long *__p) +{ + return __builtin_ia32_rdseed64_step(__p); +} +#endif +#endif /* __RDSEED__ */ diff --git a/lib/Headers/stddef.h b/lib/Headers/stddef.h index ad5dc21fb0..6a64d6d32a 100644 --- a/lib/Headers/stddef.h +++ b/lib/Headers/stddef.h @@ -26,17 +26,42 @@ #ifndef __STDDEF_H #define __STDDEF_H -#ifndef _PTRDIFF_T +#if !defined(_PTRDIFF_T) || __has_feature(modules) +/* Always define ptrdiff_t when modules are available. */ +#if !__has_feature(modules) #define _PTRDIFF_T +#endif typedef __PTRDIFF_TYPE__ ptrdiff_t; #endif -#ifndef _SIZE_T + +#if !defined(_SIZE_T) || __has_feature(modules) +/* Always define size_t when modules are available. */ +#if !__has_feature(modules) #define _SIZE_T +#endif typedef __SIZE_TYPE__ size_t; #endif + +/* ISO9899:2011 7.20 (C11 Annex K): Define rsize_t if __STDC_WANT_LIB_EXT1__ is + * enabled. */ +#if (defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1 && \ + !defined(_RSIZE_T)) || __has_feature(modules) +/* Always define rsize_t when modules are available. */ +#if !__has_feature(modules) +#define _RSIZE_T +#endif +typedef __SIZE_TYPE__ rsize_t; +#endif + #ifndef __cplusplus -#ifndef _WCHAR_T +/* Always define wchar_t when modules are available. */ +#if !defined(_WCHAR_T) || __has_feature(modules) +#if !__has_feature(modules) #define _WCHAR_T +#if defined(_MSC_EXTENSIONS) +#define _WCHAR_T_DEFINED +#endif +#endif typedef __WCHAR_TYPE__ wchar_t; #endif #endif @@ -66,9 +91,12 @@ using ::std::nullptr_t; /* Some C libraries expect to see a wint_t here. Others (notably MinGW) will use __WINT_TYPE__ directly; accommodate both by requiring __need_wint_t */ #if defined(__need_wint_t) -#if !defined(_WINT_T) +/* Always define wint_t when modules are available. */ +#if !defined(_WINT_T) || __has_feature(modules) +#if !__has_feature(modules) #define _WINT_T +#endif typedef __WINT_TYPE__ wint_t; -#endif /* _WINT_T */ +#endif #undef __need_wint_t #endif /* __need_wint_t */ diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h index 6f1a8761e1..11529c0c67 100644 --- a/lib/Headers/stdint.h +++ b/lib/Headers/stdint.h @@ -30,7 +30,48 @@ */ #if __STDC_HOSTED__ && \ defined(__has_include_next) && __has_include_next(<stdint.h>) + +// C99 7.18.3 Limits of other integer types +// +// Footnote 219, 220: C++ implementations should define these macros only when +// __STDC_LIMIT_MACROS is defined before <stdint.h> is included. +// +// Footnote 222: C++ implementations should define these macros only when +// __STDC_CONSTANT_MACROS is defined before <stdint.h> is included. +// +// C++11 [cstdint.syn]p2: +// +// The macros defined by <cstdint> are provided unconditionally. In particular, +// the symbols __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS (mentioned in +// footnotes 219, 220, and 222 in the C standard) play no role in C++. +// +// C11 removed the problematic footnotes. +// +// Work around this inconsistency by always defining those macros in C++ mode, +// so that a C library implementation which follows the C99 standard can be +// used in C++. +# ifdef __cplusplus +# if !defined(__STDC_LIMIT_MACROS) +# define __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS_DEFINED_BY_CLANG +# endif +# if !defined(__STDC_CONSTANT_MACROS) +# define __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS_DEFINED_BY_CLANG +# endif +# endif + # include_next <stdint.h> + +# ifdef __STDC_LIMIT_MACROS_DEFINED_BY_CLANG +# undef __STDC_LIMIT_MACROS +# undef __STDC_LIMIT_MACROS_DEFINED_BY_CLANG +# endif +# ifdef __STDC_CONSTANT_MACROS_DEFINED_BY_CLANG +# undef __STDC_CONSTANT_MACROS +# undef __STDC_CONSTANT_MACROS_DEFINED_BY_CLANG +# endif + #else /* C99 7.18.1.1 Exact-width integer types. @@ -626,6 +667,12 @@ typedef __UINTMAX_TYPE__ uintmax_t; #define PTRDIFF_MAX __INTN_MAX(__PTRDIFF_WIDTH__) #define SIZE_MAX __UINTN_MAX(__SIZE_WIDTH__) +/* ISO9899:2011 7.20 (C11 Annex K): Define RSIZE_MAX if __STDC_WANT_LIB_EXT1__ + * is enabled. */ +#if defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1 +#define RSIZE_MAX (SIZE_MAX >> 1) +#endif + /* C99 7.18.2.5 Limits of greatest-width integer types. */ #define INTMAX_MIN __INTN_MIN(__INTMAX_WIDTH__) #define INTMAX_MAX __INTN_MAX(__INTMAX_WIDTH__) diff --git a/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h index 68ce106be3..94fbe2fe23 100644 --- a/lib/Headers/x86intrin.h +++ b/lib/Headers/x86intrin.h @@ -46,6 +46,14 @@ #include <popcntintrin.h> #endif +#ifdef __RDSEED__ +#include <rdseedintrin.h> +#endif + +#ifdef __PRFCHW__ +#include <prfchwintrin.h> +#endif + #ifdef __SSE4A__ #include <ammintrin.h> #endif diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h index b3b23cb7d0..8c5fc9528c 100644 --- a/lib/Headers/xmmintrin.h +++ b/lib/Headers/xmmintrin.h @@ -983,10 +983,12 @@ do { \ #define _m_ _mm_ #define _m_ _mm_ +#if !__has_feature(modules) /* Ugly hack for backwards-compatibility (compatible with gcc) */ #ifdef __SSE2__ #include <emmintrin.h> #endif +#endif #endif /* __SSE__ */ diff --git a/lib/Headers/xopintrin.h b/lib/Headers/xopintrin.h index d107be4a42..9a5824c971 100644 --- a/lib/Headers/xopintrin.h +++ b/lib/Headers/xopintrin.h @@ -1,4 +1,4 @@ -/*===---- xopintrin.h - FMA4 intrinsics ------------------------------------=== +/*===---- xopintrin.h - XOP intrinsics -------------------------------------=== * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,7 @@ */ #ifndef __X86INTRIN_H -#error "Never use <fma4intrin.h> directly; include <x86intrin.h> instead." +#error "Never use <xopintrin.h> directly; include <x86intrin.h> instead." #endif #ifndef __XOPINTRIN_H diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index d4d14e8745..304bd6969a 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -47,7 +47,7 @@ HeaderSearch::HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts, const LangOptions &LangOpts, const TargetInfo *Target) : HSOpts(HSOpts), FileMgr(FM), FrameworkMap(64), - ModMap(FileMgr, *Diags.getClient(), LangOpts, Target) + ModMap(FileMgr, *Diags.getClient(), LangOpts, Target, *this) { AngledDirIdx = 0; SystemDirIdx = 0; @@ -181,8 +181,22 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) { if (Module) break; } + + // If we've already performed the exhaustive search for module maps in this + // search directory, don't do it again. + if (SearchDirs[Idx].haveSearchedAllModuleMaps()) + continue; + + // Load all module maps in the immediate subdirectories of this search + // directory. + loadSubdirectoryModuleMaps(SearchDirs[Idx]); + + // Look again for the module. + Module = ModMap.findModule(ModuleName); + if (Module) + break; } - + return Module; } @@ -806,6 +820,7 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI, const HeaderFileInfo &OtherHFI) { HFI.isImport |= OtherHFI.isImport; HFI.isPragmaOnce |= OtherHFI.isPragmaOnce; + HFI.isModuleHeader |= OtherHFI.isModuleHeader; HFI.NumIncludes += OtherHFI.NumIncludes; if (!HFI.ControllingMacro && !HFI.ControllingMacroID) { @@ -851,6 +866,14 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) { HFI.ControllingMacro || HFI.ControllingMacroID; } +void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE) { + if (FE->getUID() >= FileInfo.size()) + FileInfo.resize(FE->getUID()+1); + + HeaderFileInfo &HFI = FileInfo[FE->getUID()]; + HFI.isModuleHeader = true; +} + void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) { if (UID >= FileInfo.size()) FileInfo.resize(UID+1); @@ -948,7 +971,12 @@ bool HeaderSearch::hasModuleMap(StringRef FileName, } while (true); } -Module *HeaderSearch::findModuleForHeader(const FileEntry *File) { +Module *HeaderSearch::findModuleForHeader(const FileEntry *File) const { + if (ExternalSource) { + // Make sure the external source has handled header info about this file, + // which includes whether the file is part of a module. + (void)getFileInfo(File); + } if (Module *Mod = ModMap.findModuleForHeader(File)) return Mod; @@ -1112,13 +1140,7 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) { // Try to load module map files for immediate subdirectories of this search // directory. - llvm::error_code EC; - SmallString<128> DirNative; - llvm::sys::path::native(SearchDirs[Idx].getDir()->getName(), DirNative); - for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd; - Dir != DirEnd && !EC; Dir.increment(EC)) { - loadModuleMapFile(Dir->path()); - } + loadSubdirectoryModuleMaps(SearchDirs[Idx]); } // Populate the list of modules. @@ -1128,3 +1150,18 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) { Modules.push_back(M->getValue()); } } + +void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) { + if (SearchDir.haveSearchedAllModuleMaps()) + return; + + llvm::error_code EC; + SmallString<128> DirNative; + llvm::sys::path::native(SearchDir.getDir()->getName(), DirNative); + for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + loadModuleMapFile(Dir->path()); + } + + SearchDir.setSearchedAllModuleMaps(true); +} diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index ed4666aa21..9958287ba4 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -557,6 +557,7 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, SourceLocation FileLoc = SourceLocation::getFromRawEncoding(StartOffset); Lexer TheLexer(FileLoc, LangOpts, Buffer->getBufferStart(), Buffer->getBufferStart(), Buffer->getBufferEnd()); + TheLexer.SetCommentRetentionState(true); // StartLoc will differ from FileLoc if there is a BOM that was skipped. SourceLocation StartLoc = TheLexer.getSourceLocation(); @@ -565,6 +566,7 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, Token TheTok; Token IfStartTok; unsigned IfCount = 0; + SourceLocation ActiveCommentLoc; unsigned MaxLineOffset = 0; if (MaxLines) { @@ -612,13 +614,17 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, } // Comments are okay; skip over them. - if (TheTok.getKind() == tok::comment) + if (TheTok.getKind() == tok::comment) { + if (ActiveCommentLoc.isInvalid()) + ActiveCommentLoc = TheTok.getLocation(); continue; + } if (TheTok.isAtStartOfLine() && TheTok.getKind() == tok::hash) { // This is the start of a preprocessor directive. Token HashTok = TheTok; InPreprocessorDirective = true; + ActiveCommentLoc = SourceLocation(); // Figure out which directive this is. Since we're lexing raw tokens, // we don't have an identifier table available. Instead, just look at @@ -689,7 +695,14 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, break; } while (true); - SourceLocation End = IfCount? IfStartTok.getLocation() : TheTok.getLocation(); + SourceLocation End; + if (IfCount) + End = IfStartTok.getLocation(); + else if (ActiveCommentLoc.isValid()) + End = ActiveCommentLoc; // don't truncate a decl comment. + else + End = TheTok.getLocation(); + return std::make_pair(End.getRawEncoding() - StartLoc.getRawEncoding(), IfCount? IfStartTok.isAtStartOfLine() : TheTok.isAtStartOfLine()); diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index 91da8223c1..09f4a682f0 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -686,8 +686,13 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { // Handle simple binary numbers 0b01010 if (*s == 'b' || *s == 'B') { - // 0b101010 is a GCC extension. - PP.Diag(TokLoc, diag::ext_binary_literal); + // 0b101010 is a C++1y / GCC extension. + PP.Diag(TokLoc, + PP.getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_binary_literal + : PP.getLangOpts().CPlusPlus + ? diag::ext_binary_literal_cxx1y + : diag::ext_binary_literal); ++s; radix = 2; DigitsBegin = s; diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp index f6e781a936..d2dc04b36c 100644 --- a/lib/Lex/MacroArgs.cpp +++ b/lib/Lex/MacroArgs.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "MacroArgs.h" +#include "clang/Lex/MacroArgs.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h deleted file mode 100644 index 1fd295ebfa..0000000000 --- a/lib/Lex/MacroArgs.h +++ /dev/null @@ -1,125 +0,0 @@ -//===--- MacroArgs.h - Formal argument info for Macros ----------*- 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 MacroArgs interface. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_MACROARGS_H -#define LLVM_CLANG_MACROARGS_H - -#include "clang/Basic/LLVM.h" -#include "llvm/ADT/ArrayRef.h" -#include <vector> - -namespace clang { - class MacroInfo; - class Preprocessor; - class Token; - class SourceLocation; - -/// MacroArgs - An instance of this class captures information about -/// the formal arguments specified to a function-like macro invocation. -class MacroArgs { - /// NumUnexpArgTokens - The number of raw, unexpanded tokens for the - /// arguments. All of the actual argument tokens are allocated immediately - /// after the MacroArgs object in memory. This is all of the arguments - /// concatenated together, with 'EOF' markers at the end of each argument. - unsigned NumUnexpArgTokens; - - /// VarargsElided - True if this is a C99 style varargs macro invocation and - /// there was no argument specified for the "..." argument. If the argument - /// was specified (even empty) or this isn't a C99 style varargs function, or - /// if in strict mode and the C99 varargs macro had only a ... argument, this - /// is false. - bool VarargsElided; - - /// PreExpArgTokens - Pre-expanded tokens for arguments that need them. Empty - /// if not yet computed. This includes the EOF marker at the end of the - /// stream. - std::vector<std::vector<Token> > PreExpArgTokens; - - /// StringifiedArgs - This contains arguments in 'stringified' form. If the - /// stringified form of an argument has not yet been computed, this is empty. - std::vector<Token> StringifiedArgs; - - /// ArgCache - This is a linked list of MacroArgs objects that the - /// Preprocessor owns which we use to avoid thrashing malloc/free. - MacroArgs *ArgCache; - - MacroArgs(unsigned NumToks, bool varargsElided) - : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided), ArgCache(0) {} - ~MacroArgs() {} -public: - /// MacroArgs ctor function - Create a new MacroArgs object with the specified - /// macro and argument info. - static MacroArgs *create(const MacroInfo *MI, - ArrayRef<Token> UnexpArgTokens, - bool VarargsElided, Preprocessor &PP); - - /// destroy - Destroy and deallocate the memory for this object. - /// - void destroy(Preprocessor &PP); - - /// ArgNeedsPreexpansion - If we can prove that the argument won't be affected - /// by pre-expansion, return false. Otherwise, conservatively return true. - bool ArgNeedsPreexpansion(const Token *ArgTok, Preprocessor &PP) const; - - /// getUnexpArgument - Return a pointer to the first token of the unexpanded - /// token list for the specified formal. - /// - const Token *getUnexpArgument(unsigned Arg) const; - - /// getArgLength - Given a pointer to an expanded or unexpanded argument, - /// return the number of tokens, not counting the EOF, that make up the - /// argument. - static unsigned getArgLength(const Token *ArgPtr); - - /// getPreExpArgument - Return the pre-expanded form of the specified - /// argument. - const std::vector<Token> & - 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. - const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP, - SourceLocation ExpansionLocStart, - SourceLocation ExpansionLocEnd); - - /// getNumArguments - Return the number of arguments passed into this macro - /// invocation. - unsigned getNumArguments() const { return NumUnexpArgTokens; } - - - /// isVarargsElidedUse - Return true if this is a C99 style varargs macro - /// invocation and there was no argument specified for the "..." argument. If - /// the argument was specified (even empty) or this isn't a C99 style varargs - /// function, or if in strict mode and the C99 varargs macro had only a ... - /// argument, this returns false. - bool isVarargsElidedUse() const { return VarargsElided; } - - /// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of - /// tokens into the literal string token that should be produced by the C # - /// preprocessor operator. If Charify is true, then it should be turned into - /// a character literal for the Microsoft charize (#@) extension. - /// - static Token StringifyArgument(const Token *ArgToks, - Preprocessor &PP, bool Charify, - SourceLocation ExpansionLocStart, - SourceLocation ExpansionLocEnd); - - - /// deallocate - This should only be called by the Preprocessor when managing - /// its freelist. - MacroArgs *deallocate(); -}; - -} // end namespace clang - -#endif diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp index ed6cc6edaf..b61ff71d17 100644 --- a/lib/Lex/MacroInfo.cpp +++ b/lib/Lex/MacroInfo.cpp @@ -28,7 +28,8 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) IsDisabled(false), IsUsed(false), IsAllowRedefinitionsWithoutWarning(false), - IsWarnIfUnused(false) { + IsWarnIfUnused(false), + FromASTFile(false) { } unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const { @@ -60,11 +61,17 @@ unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const { return DefinitionLength; } -/// isIdenticalTo - Return true if the specified macro definition is equal to -/// this macro in spelling, arguments, and whitespace. This is used to emit -/// duplicate definition warnings. This implements the rules in C99 6.10.3. +/// \brief Return true if the specified macro definition is equal to +/// this macro in spelling, arguments, and whitespace. /// -bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const { +/// \param Syntactically if true, the macro definitions can be identical even +/// if they use different identifiers for the function macro parameters. +/// Otherwise the comparison is lexical and this implements the rules in +/// C99 6.10.3. +bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP, + bool Syntactically) const { + bool Lexically = !Syntactically; + // Check # tokens in replacement, number of args, and various flags all match. if (ReplacementTokens.size() != Other.ReplacementTokens.size() || getNumArgs() != Other.getNumArgs() || @@ -73,10 +80,12 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const { isGNUVarargs() != Other.isGNUVarargs()) return false; - // Check arguments. - for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end(); - I != E; ++I, ++OI) - if (*I != *OI) return false; + if (Lexically) { + // Check arguments. + for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end(); + I != E; ++I, ++OI) + if (*I != *OI) return false; + } // Check all the tokens. for (unsigned i = 0, e = ReplacementTokens.size(); i != e; ++i) { @@ -94,7 +103,16 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const { // If this is an identifier, it is easy. if (A.getIdentifierInfo() || B.getIdentifierInfo()) { - if (A.getIdentifierInfo() != B.getIdentifierInfo()) + if (A.getIdentifierInfo() == B.getIdentifierInfo()) + continue; + if (Lexically) + return false; + // With syntactic equivalence the parameter names can be different as long + // as they are used in the same place. + int AArgNum = getArgumentNum(A.getIdentifierInfo()); + if (AArgNum == -1) + return false; + if (AArgNum != Other.getArgumentNum(B.getIdentifierInfo())) return false; continue; } @@ -107,14 +125,40 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const { return true; } -const MacroDirective * +MacroDirective::DefInfo MacroDirective::getDefinition(bool AllowHidden) { + MacroDirective *MD = this; + SourceLocation UndefLoc; + Optional<bool> isPublic; + for (; MD; MD = MD->getPrevious()) { + if (!AllowHidden && MD->isHidden()) + continue; + + if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) + return DefInfo(DefMD, UndefLoc, + !isPublic.hasValue() || isPublic.getValue()); + + if (UndefMacroDirective *UndefMD = dyn_cast<UndefMacroDirective>(MD)) { + UndefLoc = UndefMD->getLocation(); + continue; + } + + VisibilityMacroDirective *VisMD = cast<VisibilityMacroDirective>(MD); + if (!isPublic.hasValue()) + isPublic = VisMD->isPublic(); + } + + return DefInfo(); +} + +const MacroDirective::DefInfo MacroDirective::findDirectiveAtLoc(SourceLocation L, SourceManager &SM) const { assert(L.isValid() && "SourceLocation is invalid."); - for (const MacroDirective *MD = this; MD; MD = MD->Previous) { - if (MD->getLocation().isInvalid() || // For macros defined on the command line. - SM.isBeforeInTranslationUnit(MD->getLocation(), L)) - return (MD->UndefLocation.isInvalid() || - SM.isBeforeInTranslationUnit(L, MD->UndefLocation)) ? MD : NULL; + for (DefInfo Def = getDefinition(); Def; Def = Def.getPreviousDefinition()) { + if (Def.getLocation().isInvalid() || // For macros defined on the command line. + SM.isBeforeInTranslationUnit(Def.getLocation(), L)) + return (!Def.isUndefined() || + SM.isBeforeInTranslationUnit(L, Def.getUndefLocation())) + ? Def : DefInfo(); } - return NULL; + return DefInfo(); } diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index 81cb94de51..3e7a44c0e3 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -18,6 +18,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" +#include "clang/Lex/HeaderSearch.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/LiteralSupport.h" @@ -44,45 +45,55 @@ ModuleMap::resolveExport(Module *Mod, return Module::ExportDecl(0, true); } + // Resolve the module-id. + Module *Context = resolveModuleId(Unresolved.Id, Mod, Complain); + if (!Context) + return Module::ExportDecl(); + + return Module::ExportDecl(Context, Unresolved.Wildcard); +} + +Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod, + bool Complain) const { // Find the starting module. - Module *Context = lookupModuleUnqualified(Unresolved.Id[0].first, Mod); + Module *Context = lookupModuleUnqualified(Id[0].first, Mod); if (!Context) { if (Complain) - Diags->Report(Unresolved.Id[0].second, - diag::err_mmap_missing_module_unqualified) - << Unresolved.Id[0].first << Mod->getFullModuleName(); - - return Module::ExportDecl(); + Diags->Report(Id[0].second, diag::err_mmap_missing_module_unqualified) + << Id[0].first << Mod->getFullModuleName(); + + return 0; } // Dig into the module path. - for (unsigned I = 1, N = Unresolved.Id.size(); I != N; ++I) { - Module *Sub = lookupModuleQualified(Unresolved.Id[I].first, - Context); + for (unsigned I = 1, N = Id.size(); I != N; ++I) { + Module *Sub = lookupModuleQualified(Id[I].first, Context); if (!Sub) { if (Complain) - Diags->Report(Unresolved.Id[I].second, - diag::err_mmap_missing_module_qualified) - << Unresolved.Id[I].first << Context->getFullModuleName() - << SourceRange(Unresolved.Id[0].second, Unresolved.Id[I-1].second); - - return Module::ExportDecl(); + Diags->Report(Id[I].second, diag::err_mmap_missing_module_qualified) + << Id[I].first << Context->getFullModuleName() + << SourceRange(Id[0].second, Id[I-1].second); + + return 0; } - + Context = Sub; } - - return Module::ExportDecl(Context, Unresolved.Wildcard); + + return Context; } -ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC, - const LangOptions &LangOpts, const TargetInfo *Target) - : LangOpts(LangOpts), Target(Target), BuiltinIncludeDir(0) +ModuleMap::ModuleMap(FileManager &FileMgr, DiagnosticConsumer &DC, + const LangOptions &LangOpts, const TargetInfo *Target, + HeaderSearch &HeaderInfo) + : LangOpts(LangOpts), Target(Target), HeaderInfo(HeaderInfo), + BuiltinIncludeDir(0) { IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs); Diags = IntrusiveRefCntPtr<DiagnosticsEngine>( new DiagnosticsEngine(DiagIDs, new DiagnosticOptions)); - Diags->setClient(DC.clone(*Diags), /*ShouldOwnClient=*/true); + Diags->setClient(new ForwardingDiagnosticConsumer(DC), + /*ShouldOwnClient=*/true); SourceMgr = new SourceManager(*Diags, FileMgr); } @@ -139,6 +150,24 @@ static StringRef sanitizeFilenameAsIdentifier(StringRef Name, return Name; } +/// \brief Determine whether the given file name is the name of a builtin +/// header, supplied by Clang to replace, override, or augment existing system +/// headers. +static bool isBuiltinHeader(StringRef FileName) { + return llvm::StringSwitch<bool>(FileName) + .Case("float.h", true) + .Case("iso646.h", true) + .Case("limits.h", true) + .Case("stdalign.h", true) + .Case("stdarg.h", true) + .Case("stdbool.h", true) + .Case("stddef.h", true) + .Case("stdint.h", true) + .Case("tgmath.h", true) + .Case("unwind.h", true) + .Default(false); +} + Module *ModuleMap::findModuleForHeader(const FileEntry *File) { HeadersMap::iterator Known = Headers.find(File); if (Known != Headers.end()) { @@ -148,6 +177,25 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) { return Known->second.getModule(); } + + // If we've found a builtin header within Clang's builtin include directory, + // load all of the module maps to see if it will get associated with a + // specific module (e.g., in /usr/include). + if (File->getDir() == BuiltinIncludeDir && + isBuiltinHeader(llvm::sys::path::filename(File->getName()))) { + SmallVector<Module *, 4> AllModules; + HeaderInfo.collectAllModules(AllModules); + + // Check again. + Known = Headers.find(File); + if (Known != Headers.end()) { + // If a header is not available, don't report that it maps to anything. + if (!Known->second.isAvailable()) + return 0; + + return Known->second.getModule(); + } + } const DirectoryEntry *Dir = File->getDir(); SmallVector<const DirectoryEntry *, 2> SkippedDirs; @@ -202,7 +250,7 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) { llvm::sys::path::stem(File->getName()), NameBuf); Result = findOrCreateModule(Name, Result, /*IsFramework=*/false, Explicit).first; - Result->TopHeaders.insert(File); + Result->addTopHeader(File); // If inferred submodules export everything they import, add a // wildcard to the set of exports. @@ -553,10 +601,12 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) { void ModuleMap::addHeader(Module *Mod, const FileEntry *Header, bool Excluded) { - if (Excluded) + if (Excluded) { Mod->ExcludedHeaders.push_back(Header); - else + } else { Mod->Headers.push_back(Header); + HeaderInfo.MarkFileModuleHeader(Header); + } Headers[Header] = KnownHeader(Mod, Excluded); } @@ -598,6 +648,25 @@ bool ModuleMap::resolveExports(Module *Mod, bool Complain) { return HadError; } +bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) { + bool HadError = false; + for (unsigned I = 0, N = Mod->UnresolvedConflicts.size(); I != N; ++I) { + Module *OtherMod = resolveModuleId(Mod->UnresolvedConflicts[I].Id, + Mod, Complain); + if (!OtherMod) { + HadError = true; + continue; + } + + Module::Conflict Conflict; + Conflict.Other = OtherMod; + Conflict.Message = Mod->UnresolvedConflicts[I].Message; + Mod->Conflicts.push_back(Conflict); + } + Mod->UnresolvedConflicts.clear(); + return HadError; +} + Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) { if (Loc.isInvalid()) return 0; @@ -638,6 +707,8 @@ namespace clang { struct MMToken { enum TokenKind { Comma, + ConfigMacros, + Conflict, EndOfFile, HeaderKeyword, Identifier, @@ -682,10 +753,13 @@ namespace clang { /// \brief The set of attributes that can be attached to a module. struct Attributes { - Attributes() : IsSystem() { } + Attributes() : IsSystem(), IsExhaustive() { } /// \brief Whether this is a system module. unsigned IsSystem : 1; + + /// \brief Whether this is an exhaustive set of configuration macros. + unsigned IsExhaustive : 1; }; @@ -734,6 +808,8 @@ namespace clang { void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc); void parseExportDecl(); void parseLinkDecl(); + void parseConfigMacros(); + void parseConflict(); void parseInferredModuleDecl(bool Framework, bool Explicit); bool parseOptionalAttributes(Attributes &Attrs); @@ -771,11 +847,13 @@ retry: Tok.StringData = LToken.getRawIdentifierData(); Tok.StringLength = LToken.getLength(); Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString()) - .Case("header", MMToken::HeaderKeyword) + .Case("config_macros", MMToken::ConfigMacros) + .Case("conflict", MMToken::Conflict) .Case("exclude", MMToken::ExcludeKeyword) .Case("explicit", MMToken::ExplicitKeyword) .Case("export", MMToken::ExportKeyword) .Case("framework", MMToken::FrameworkKeyword) + .Case("header", MMToken::HeaderKeyword) .Case("link", MMToken::LinkKeyword) .Case("module", MMToken::ModuleKeyword) .Case("requires", MMToken::RequiresKeyword) @@ -932,7 +1010,9 @@ namespace { /// \brief An unknown attribute. AT_unknown, /// \brief The 'system' attribute. - AT_system + AT_system, + /// \brief The 'exhaustive' attribute. + AT_exhaustive }; } @@ -1089,7 +1169,15 @@ void ModuleMapParser::parseModuleDecl() { case MMToken::RBrace: Done = true; break; - + + case MMToken::ConfigMacros: + parseConfigMacros(); + break; + + case MMToken::Conflict: + parseConflict(); + break; + case MMToken::ExplicitKeyword: case MMToken::FrameworkKeyword: case MMToken::ModuleKeyword: @@ -1216,24 +1304,6 @@ static void appendSubframeworkPaths(Module *Mod, } } -/// \brief Determine whether the given file name is the name of a builtin -/// header, supplied by Clang to replace, override, or augment existing system -/// headers. -static bool isBuiltinHeader(StringRef FileName) { - return llvm::StringSwitch<bool>(FileName) - .Case("float.h", true) - .Case("iso646.h", true) - .Case("limits.h", true) - .Case("stdalign.h", true) - .Case("stdarg.h", true) - .Case("stdbool.h", true) - .Case("stddef.h", true) - .Case("stdint.h", true) - .Case("tgmath.h", true) - .Case("unwind.h", true) - .Default(false); -} - /// \brief Parse a header declaration. /// /// header-declaration: @@ -1484,6 +1554,109 @@ void ModuleMapParser::parseLinkDecl() { IsFramework)); } +/// \brief Parse a configuration macro declaration. +/// +/// module-declaration: +/// 'config_macros' attributes[opt] config-macro-list? +/// +/// config-macro-list: +/// identifier (',' identifier)? +void ModuleMapParser::parseConfigMacros() { + assert(Tok.is(MMToken::ConfigMacros)); + SourceLocation ConfigMacrosLoc = consumeToken(); + + // Only top-level modules can have configuration macros. + if (ActiveModule->Parent) { + Diags.Report(ConfigMacrosLoc, diag::err_mmap_config_macro_submodule); + } + + // Parse the optional attributes. + Attributes Attrs; + parseOptionalAttributes(Attrs); + if (Attrs.IsExhaustive && !ActiveModule->Parent) { + ActiveModule->ConfigMacrosExhaustive = true; + } + + // If we don't have an identifier, we're done. + if (!Tok.is(MMToken::Identifier)) + return; + + // Consume the first identifier. + if (!ActiveModule->Parent) { + ActiveModule->ConfigMacros.push_back(Tok.getString().str()); + } + consumeToken(); + + do { + // If there's a comma, consume it. + if (!Tok.is(MMToken::Comma)) + break; + consumeToken(); + + // We expect to see a macro name here. + if (!Tok.is(MMToken::Identifier)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_config_macro); + break; + } + + // Consume the macro name. + if (!ActiveModule->Parent) { + ActiveModule->ConfigMacros.push_back(Tok.getString().str()); + } + consumeToken(); + } while (true); +} + +/// \brief Format a module-id into a string. +static std::string formatModuleId(const ModuleId &Id) { + std::string result; + { + llvm::raw_string_ostream OS(result); + + for (unsigned I = 0, N = Id.size(); I != N; ++I) { + if (I) + OS << "."; + OS << Id[I].first; + } + } + + return result; +} + +/// \brief Parse a conflict declaration. +/// +/// module-declaration: +/// 'conflict' module-id ',' string-literal +void ModuleMapParser::parseConflict() { + assert(Tok.is(MMToken::Conflict)); + SourceLocation ConflictLoc = consumeToken(); + Module::UnresolvedConflict Conflict; + + // Parse the module-id. + if (parseModuleId(Conflict.Id)) + return; + + // Parse the ','. + if (!Tok.is(MMToken::Comma)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_comma) + << SourceRange(ConflictLoc); + return; + } + consumeToken(); + + // Parse the message. + if (!Tok.is(MMToken::StringLiteral)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_message) + << formatModuleId(Conflict.Id); + return; + } + Conflict.Message = Tok.getString().str(); + consumeToken(); + + // Add this unresolved conflict. + ActiveModule->UnresolvedConflicts.push_back(Conflict); +} + /// \brief Parse an inferred module declaration (wildcard modules). /// /// module-declaration: @@ -1663,6 +1836,7 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) { // Decode the attribute name. AttributeKind Attribute = llvm::StringSwitch<AttributeKind>(Tok.getString()) + .Case("exhaustive", AT_exhaustive) .Case("system", AT_system) .Default(AT_unknown); switch (Attribute) { @@ -1674,6 +1848,10 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) { case AT_system: Attrs.IsSystem = true; break; + + case AT_exhaustive: + Attrs.IsExhaustive = true; + break; } consumeToken(); @@ -1725,6 +1903,8 @@ bool ModuleMapParser::parseModuleMapFile() { break; case MMToken::Comma: + case MMToken::ConfigMacros: + case MMToken::Conflict: case MMToken::ExcludeKeyword: case MMToken::ExportKeyword: case MMToken::HeaderKeyword: diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 8379ca8719..50a0cb55f7 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -57,11 +57,42 @@ MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) { return MI; } -MacroDirective *Preprocessor::AllocateMacroDirective(MacroInfo *MI, - SourceLocation Loc, - bool isImported) { - MacroDirective *MD = BP.Allocate<MacroDirective>(); - new (MD) MacroDirective(MI, Loc, isImported); +MacroInfo *Preprocessor::AllocateDeserializedMacroInfo(SourceLocation L, + unsigned SubModuleID) { + LLVM_STATIC_ASSERT(llvm::AlignOf<MacroInfo>::Alignment >= sizeof(SubModuleID), + "alignment for MacroInfo is less than the ID"); + DeserializedMacroInfoChain *MIChain = + BP.Allocate<DeserializedMacroInfoChain>(); + MIChain->Next = DeserialMIChainHead; + DeserialMIChainHead = MIChain; + + MacroInfo *MI = &MIChain->MI; + new (MI) MacroInfo(L); + MI->FromASTFile = true; + MI->setOwningModuleID(SubModuleID); + return MI; +} + +DefMacroDirective * +Preprocessor::AllocateDefMacroDirective(MacroInfo *MI, SourceLocation Loc, + bool isImported) { + DefMacroDirective *MD = BP.Allocate<DefMacroDirective>(); + new (MD) DefMacroDirective(MI, Loc, isImported); + return MD; +} + +UndefMacroDirective * +Preprocessor::AllocateUndefMacroDirective(SourceLocation UndefLoc) { + UndefMacroDirective *MD = BP.Allocate<UndefMacroDirective>(); + new (MD) UndefMacroDirective(UndefLoc); + return MD; +} + +VisibilityMacroDirective * +Preprocessor::AllocateVisibilityMacroDirective(SourceLocation Loc, + bool isPublic) { + VisibilityMacroDirective *MD = BP.Allocate<VisibilityMacroDirective>(); + new (MD) VisibilityMacroDirective(Loc, isPublic); return MD; } @@ -765,7 +796,8 @@ void Preprocessor::HandleDirective(Token &Result) { /// GetLineValue - Convert a numeric token into an unsigned value, emitting /// Diagnostic DiagID if it is invalid, and returning the value in Val. static bool GetLineValue(Token &DigitTok, unsigned &Val, - unsigned DiagID, Preprocessor &PP) { + unsigned DiagID, Preprocessor &PP, + bool IsGNULineDirective=false) { if (DigitTok.isNot(tok::numeric_constant)) { PP.Diag(DigitTok, DiagID); @@ -789,7 +821,7 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val, for (unsigned i = 0; i != ActualLength; ++i) { if (!isDigit(DigitTokBegin[i])) { PP.Diag(PP.AdvanceToTokenCharacter(DigitTok.getLocation(), i), - diag::err_pp_line_digit_sequence); + diag::err_pp_line_digit_sequence) << IsGNULineDirective; PP.DiscardUntilEndOfDirective(); return true; } @@ -804,7 +836,8 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val, } if (DigitTokBegin[0] == '0' && Val) - PP.Diag(DigitTok.getLocation(), diag::warn_pp_line_decimal); + PP.Diag(DigitTok.getLocation(), diag::warn_pp_line_decimal) + << IsGNULineDirective; return false; } @@ -970,7 +1003,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) { // line # limit other than it fit in 32-bits. unsigned LineNo; if (GetLineValue(DigitTok, LineNo, diag::err_pp_linemarker_requires_integer, - *this)) + *this, true)) return; Token StrTok; @@ -1106,23 +1139,19 @@ void Preprocessor::HandleMacroPublicDirective(Token &Tok) { // Check to see if this is the last token on the #__public_macro line. CheckEndOfDirective("__public_macro"); + IdentifierInfo *II = MacroNameTok.getIdentifierInfo(); // Okay, we finally have a valid identifier to undef. - MacroDirective *MD = getMacroDirective(MacroNameTok.getIdentifierInfo()); + MacroDirective *MD = getMacroDirective(II); // If the macro is not defined, this is an error. if (MD == 0) { - Diag(MacroNameTok, diag::err_pp_visibility_non_macro) - << MacroNameTok.getIdentifierInfo(); + Diag(MacroNameTok, diag::err_pp_visibility_non_macro) << II; return; } // Note that this macro has now been exported. - MD->setVisibility(/*IsPublic=*/true, MacroNameTok.getLocation()); - - // If this macro definition came from a PCH file, mark it - // as having changed since serialization. - if (MD->isImported()) - MD->setChangedAfterLoad(); + appendMacroDirective(II, AllocateVisibilityMacroDirective( + MacroNameTok.getLocation(), /*IsPublic=*/true)); } /// \brief Handle a #private directive. @@ -1137,23 +1166,19 @@ void Preprocessor::HandleMacroPrivateDirective(Token &Tok) { // Check to see if this is the last token on the #__private_macro line. CheckEndOfDirective("__private_macro"); + IdentifierInfo *II = MacroNameTok.getIdentifierInfo(); // Okay, we finally have a valid identifier to undef. - MacroDirective *MD = getMacroDirective(MacroNameTok.getIdentifierInfo()); + MacroDirective *MD = getMacroDirective(II); // If the macro is not defined, this is an error. if (MD == 0) { - Diag(MacroNameTok, diag::err_pp_visibility_non_macro) - << MacroNameTok.getIdentifierInfo(); + Diag(MacroNameTok, diag::err_pp_visibility_non_macro) << II; return; } // Note that this macro has now been marked private. - MD->setVisibility(/*IsPublic=*/false, MacroNameTok.getLocation()); - - // If this macro definition came from a PCH file, mark it - // as having changed since serialization. - if (MD->isImported()) - MD->setChangedAfterLoad(); + appendMacroDirective(II, AllocateVisibilityMacroDirective( + MacroNameTok.getLocation(), /*IsPublic=*/false)); } //===----------------------------------------------------------------------===// @@ -1929,9 +1954,9 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { if (OtherMI->isBuiltinMacro()) Diag(MacroNameTok, diag::ext_pp_redef_builtin_macro); // Macros must be identical. This means all tokens and whitespace - // separation must be the same. C99 6.10.3.2. + // separation must be the same. C99 6.10.3p2. else if (!OtherMI->isAllowRedefinitionsWithoutWarning() && - !MI->isIdenticalTo(*OtherMI, *this)) { + !MI->isIdenticalTo(*OtherMI, *this, /*Syntactic=*/LangOpts.MicrosoftExt)) { Diag(MI->getDefinitionLoc(), diag::ext_pp_macro_redef) << MacroNameTok.getIdentifierInfo(); Diag(OtherMI->getDefinitionLoc(), diag::note_previous_definition); @@ -1941,7 +1966,8 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { WarnUnusedMacroLocs.erase(OtherMI->getDefinitionLoc()); } - MacroDirective *MD = setMacroDirective(MacroNameTok.getIdentifierInfo(), MI); + DefMacroDirective *MD = + appendDefMacroDirective(MacroNameTok.getIdentifierInfo(), MI); assert(!MI->isUsed()); // If we need warning for not using the macro, add its location in the @@ -1975,7 +2001,7 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) { // Okay, we finally have a valid identifier to undef. MacroDirective *MD = getMacroDirective(MacroNameTok.getIdentifierInfo()); - const MacroInfo *MI = MD ? MD->getInfo() : 0; + const MacroInfo *MI = MD ? MD->getMacroInfo() : 0; // If the callbacks want to know, tell them about the macro #undef. // Note: no matter if the macro was defined or not. @@ -1991,20 +2017,8 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) { if (MI->isWarnIfUnused()) WarnUnusedMacroLocs.erase(MI->getDefinitionLoc()); - UndefineMacro(MacroNameTok.getIdentifierInfo(), MD, - MacroNameTok.getLocation()); -} - -void Preprocessor::UndefineMacro(IdentifierInfo *II, MacroDirective *MD, - SourceLocation UndefLoc) { - MD->setUndefLoc(UndefLoc); - if (MD->isImported()) { - MD->setChangedAfterLoad(); - if (Listener) - Listener->UndefinedMacro(MD); - } - - clearMacroInfo(II); + appendMacroDirective(MacroNameTok.getIdentifierInfo(), + AllocateUndefMacroDirective(MacroNameTok.getLocation())); } @@ -2039,7 +2053,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, IdentifierInfo *MII = MacroNameTok.getIdentifierInfo(); MacroDirective *MD = getMacroDirective(MII); - MacroInfo *MI = MD ? MD->getInfo() : 0; + MacroInfo *MI = MD ? MD->getMacroInfo() : 0; if (CurPPLexer->getConditionalStackDepth() == 0) { // If the start of a top-level #ifdef and if the macro is not defined, @@ -2082,7 +2096,6 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, /// void Preprocessor::HandleIfDirective(Token &IfToken, bool ReadAnyTokensBeforeDirective) { - SaveAndRestore<bool> PPDir(ParsingIfOrElifDirective, true); ++NumIf; // Parse and evaluate the conditional expression. @@ -2174,7 +2187,6 @@ void Preprocessor::HandleElseDirective(Token &Result) { /// HandleElifDirective - Implements the \#elif directive. /// void Preprocessor::HandleElifDirective(Token &ElifToken) { - SaveAndRestore<bool> PPDir(ParsingIfOrElifDirective, true); ++NumElse; // #elif directive in a non-skipping conditional... start skipping. diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp index 49f4cbf71a..d9ce8bff23 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -24,6 +24,7 @@ #include "clang/Lex/MacroInfo.h" #include "llvm/ADT/APSInt.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SaveAndRestore.h" using namespace clang; namespace { @@ -115,7 +116,7 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT, // If there is a macro, mark it used. if (Result.Val != 0 && ValueLive) { Macro = PP.getMacroDirective(II); - PP.markMacroAsUsed(Macro->getInfo()); + PP.markMacroAsUsed(Macro->getMacroInfo()); } // Invoke the 'defined' callback. @@ -730,6 +731,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, /// to "!defined(X)" return X in IfNDefMacro. bool Preprocessor:: EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { + SaveAndRestore<bool> PPDir(ParsingIfOrElifDirective, true); // Save the current state of 'DisableMacroExpansion' and reset it to false. If // 'DisableMacroExpansion' is true, then we must be in a macro argument list // in which case a directive is undefined behavior. We want macros to be able diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 8e54f019ba..24c6217ced 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Preprocessor.h" -#include "MacroArgs.h" +#include "clang/Lex/MacroArgs.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -41,127 +41,31 @@ Preprocessor::getMacroDirectiveHistory(const IdentifierInfo *II) const { return Pos->second; } -/// \brief Specify a macro for this identifier. -MacroDirective * -Preprocessor::setMacroDirective(IdentifierInfo *II, MacroInfo *MI, - SourceLocation Loc, bool isImported) { - assert(MI && "MacroInfo should be non-zero!"); +void Preprocessor::appendMacroDirective(IdentifierInfo *II, MacroDirective *MD){ + assert(MD && "MacroDirective should be non-zero!"); + assert(!MD->getPrevious() && "Already attached to a MacroDirective history."); - MacroDirective *MD = AllocateMacroDirective(MI, Loc, isImported); MacroDirective *&StoredMD = Macros[II]; MD->setPrevious(StoredMD); StoredMD = MD; - II->setHasMacroDefinition(true); - if (II->isFromAST()) + II->setHasMacroDefinition(MD->isDefined()); + bool isImportedMacro = isa<DefMacroDirective>(MD) && + cast<DefMacroDirective>(MD)->isImported(); + if (II->isFromAST() && !isImportedMacro) II->setChangedSinceDeserialization(); - - return MD; } -void Preprocessor::addLoadedMacroInfo(IdentifierInfo *II, MacroDirective *MD, - MacroDirective *Hint) { - assert(MD && "Missing macro?"); - assert(MD->isImported() && "Macro is not from an AST?"); - assert(!MD->getPrevious() && "Macro already in chain?"); - +void Preprocessor::setLoadedMacroDirective(IdentifierInfo *II, + MacroDirective *MD) { + assert(II && MD); MacroDirective *&StoredMD = Macros[II]; - - // Easy case: this is the first macro definition for this macro. - if (!StoredMD) { - StoredMD = MD; - - if (MD->isDefined()) - II->setHasMacroDefinition(true); - return; - } - - // If this macro is a definition and this identifier has been neither - // defined nor undef'd in the current translation unit, add this macro - // to the end of the chain of definitions. - if (MD->isDefined() && StoredMD->isImported()) { - // Simple case: if this is the first actual definition, just put it at - // th beginning. - if (!StoredMD->isDefined()) { - MD->setPrevious(StoredMD); - StoredMD = MD; - - II->setHasMacroDefinition(true); - return; - } - - // Find the end of the definition chain. - MacroDirective *Prev; - MacroDirective *PrevPrev = StoredMD; - bool Ambiguous = StoredMD->isAmbiguous(); - bool MatchedOther = false; - do { - Prev = PrevPrev; - - // If the macros are not identical, we have an ambiguity. - if (!Prev->getInfo()->isIdenticalTo(*MD->getInfo(), *this)) { - if (!Ambiguous) { - Ambiguous = true; - StoredMD->setAmbiguous(true); - } - } else { - MatchedOther = true; - } - } while ((PrevPrev = Prev->getPrevious()) && - PrevPrev->isDefined()); - - // If there are ambiguous definitions, and we didn't match any other - // definition, then mark us as ambiguous. - if (Ambiguous && !MatchedOther) - MD->setAmbiguous(true); - - // Wire this macro information into the chain. - MD->setPrevious(Prev->getPrevious()); - Prev->setPrevious(MD); - return; - } - - // The macro is not a definition; put it at the end of the list. - MacroDirective *Prev = Hint? Hint : StoredMD; - while (Prev->getPrevious()) - Prev = Prev->getPrevious(); - Prev->setPrevious(MD); -} - -void Preprocessor::makeLoadedMacroInfoVisible(IdentifierInfo *II, - MacroDirective *MD) { - assert(MD->isImported() && "Macro must be from the AST"); - - MacroDirective *&StoredMD = Macros[II]; - if (StoredMD == MD) { - // Easy case: this is the first macro anyway. - II->setHasMacroDefinition(MD->isDefined()); - return; - } - - // Go find the macro and pull it out of the list. - // FIXME: Yes, this is O(N), and making a pile of macros visible or hidden - // would be quadratic, but it's extremely rare. - MacroDirective *Prev = StoredMD; - while (Prev->getPrevious() != MD) - Prev = Prev->getPrevious(); - Prev->setPrevious(MD->getPrevious()); - MD->setPrevious(0); - - // Add the macro back to the list. - addLoadedMacroInfo(II, MD); - - II->setHasMacroDefinition(StoredMD->isDefined()); - if (II->isFromAST()) - II->setChangedSinceDeserialization(); -} - -/// \brief Undefine a macro for this identifier. -void Preprocessor::clearMacroInfo(IdentifierInfo *II) { - assert(II->hasMacroDefinition() && "Macro is not defined!"); - assert(Macros[II]->getUndefLoc().isValid() && "Macro is still defined!"); - II->setHasMacroDefinition(false); - if (II->isFromAST()) - II->setChangedSinceDeserialization(); + assert(!StoredMD && + "the macro history was modified before initializing it from a pch"); + StoredMD = MD; + // Setup the identifier as having associated macro history. + II->setHasMacroDefinition(true); + if (!MD->isDefined()) + II->setHasMacroDefinition(false); } /// RegisterBuiltinMacro - Register the specified identifier in the identifier @@ -173,7 +77,7 @@ static IdentifierInfo *RegisterBuiltinMacro(Preprocessor &PP, const char *Name){ // Mark it as being a macro that is builtin. MacroInfo *MI = PP.AllocateMacroInfo(SourceLocation()); MI->setIsBuiltinMacro(); - PP.setMacroDirective(Id, MI); + PP.appendDefMacroDirective(Id, MI); return Id; } @@ -307,7 +211,9 @@ bool Preprocessor::isNextPPTokenLParen() { /// expanded as a macro, handle it and return the next token as 'Identifier'. bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, MacroDirective *MD) { - MacroInfo *MI = MD->getInfo(); + MacroDirective::DefInfo Def = MD->getDefinition(); + assert(Def.isValid()); + MacroInfo *MI = Def.getMacroInfo(); // If this is a macro expansion in the "#if !defined(x)" line for the file, // then the macro could expand to different things in other contexts, we need @@ -317,7 +223,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, // If this is a builtin macro, like __LINE__ or _Pragma, handle it specially. if (MI->isBuiltinMacro()) { if (Callbacks) Callbacks->MacroExpands(Identifier, MD, - Identifier.getLocation()); + Identifier.getLocation(),/*Args=*/0); ExpandBuiltinMacro(Identifier); return false; } @@ -371,36 +277,34 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, DelayedMacroExpandsCallbacks.push_back( MacroExpandsInfo(Identifier, MD, ExpansionRange)); } else { - Callbacks->MacroExpands(Identifier, MD, ExpansionRange); + Callbacks->MacroExpands(Identifier, MD, ExpansionRange, Args); if (!DelayedMacroExpandsCallbacks.empty()) { for (unsigned i=0, e = DelayedMacroExpandsCallbacks.size(); i!=e; ++i) { MacroExpandsInfo &Info = DelayedMacroExpandsCallbacks[i]; - Callbacks->MacroExpands(Info.Tok, Info.MD, Info.Range); + // FIXME: We lose macro args info with delayed callback. + Callbacks->MacroExpands(Info.Tok, Info.MD, Info.Range, /*Args=*/0); } DelayedMacroExpandsCallbacks.clear(); } } } - // FIXME: Temporarily disable this warning that is currently bogus with a PCH - // that redefined a macro without undef'ing it first (test/PCH/macro-redef.c). -#if 0 // If the macro definition is ambiguous, complain. - if (MI->isAmbiguous()) { + if (Def.getDirective()->isAmbiguous()) { Diag(Identifier, diag::warn_pp_ambiguous_macro) << Identifier.getIdentifierInfo(); Diag(MI->getDefinitionLoc(), diag::note_pp_ambiguous_macro_chosen) << Identifier.getIdentifierInfo(); - for (MacroInfo *PrevMI = MI->getPreviousDefinition(); - PrevMI && PrevMI->isDefined(); - PrevMI = PrevMI->getPreviousDefinition()) { - if (PrevMI->isAmbiguous()) { - Diag(PrevMI->getDefinitionLoc(), diag::note_pp_ambiguous_macro_other) + for (MacroDirective::DefInfo PrevDef = Def.getPreviousDefinition(); + PrevDef && !PrevDef.isUndefined(); + PrevDef = PrevDef.getPreviousDefinition()) { + if (PrevDef.getDirective()->isAmbiguous()) { + Diag(PrevDef.getMacroInfo()->getDefinitionLoc(), + diag::note_pp_ambiguous_macro_other) << Identifier.getIdentifierInfo(); } } } -#endif // If we started lexing a macro, enter the macro expansion body. @@ -848,6 +752,8 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("c_atomic", LangOpts.C11) .Case("c_generic_selections", LangOpts.C11) .Case("c_static_assert", LangOpts.C11) + .Case("c_thread_local", + LangOpts.C11 && PP.getTargetInfo().isTLSSupported()) // C++11 features .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus11) .Case("cxx_alias_templates", LangOpts.CPlusPlus11) @@ -865,7 +771,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_explicit_conversions", LangOpts.CPlusPlus11) .Case("cxx_generalized_initializers", LangOpts.CPlusPlus11) .Case("cxx_implicit_moves", LangOpts.CPlusPlus11) - //.Case("cxx_inheriting_constructors", false) + .Case("cxx_inheriting_constructors", LangOpts.CPlusPlus11) .Case("cxx_inline_namespaces", LangOpts.CPlusPlus11) .Case("cxx_lambdas", LangOpts.CPlusPlus11) .Case("cxx_local_type_template_args", LangOpts.CPlusPlus11) @@ -879,11 +785,23 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_rvalue_references", LangOpts.CPlusPlus11) .Case("cxx_strong_enums", LangOpts.CPlusPlus11) .Case("cxx_static_assert", LangOpts.CPlusPlus11) + .Case("cxx_thread_local", + LangOpts.CPlusPlus11 && PP.getTargetInfo().isTLSSupported()) .Case("cxx_trailing_return", LangOpts.CPlusPlus11) .Case("cxx_unicode_literals", LangOpts.CPlusPlus11) .Case("cxx_unrestricted_unions", LangOpts.CPlusPlus11) .Case("cxx_user_literals", LangOpts.CPlusPlus11) .Case("cxx_variadic_templates", LangOpts.CPlusPlus11) + // C++1y features + .Case("cxx_binary_literals", LangOpts.CPlusPlus1y) + //.Case("cxx_contextual_conversions", LangOpts.CPlusPlus1y) + //.Case("cxx_generalized_capture", LangOpts.CPlusPlus1y) + //.Case("cxx_generic_lambda", LangOpts.CPlusPlus1y) + //.Case("cxx_relaxed_constexpr", LangOpts.CPlusPlus1y) + //.Case("cxx_return_type_deduction", LangOpts.CPlusPlus1y) + //.Case("cxx_runtime_array", LangOpts.CPlusPlus1y) + .Case("cxx_aggregate_nsdmi", LangOpts.CPlusPlus1y) + //.Case("cxx_variable_templates", LangOpts.CPlusPlus1y) // Type traits .Case("has_nothrow_assign", LangOpts.CPlusPlus) .Case("has_nothrow_copy", LangOpts.CPlusPlus) @@ -944,7 +862,7 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) { .Case("c_atomic", true) .Case("c_generic_selections", true) .Case("c_static_assert", true) - // C++0x features supported by other languages as extensions. + // C++11 features supported by other languages as extensions. .Case("cxx_atomic", LangOpts.CPlusPlus) .Case("cxx_deleted_functions", LangOpts.CPlusPlus) .Case("cxx_explicit_conversions", LangOpts.CPlusPlus) @@ -955,6 +873,8 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_range_for", LangOpts.CPlusPlus) .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus) .Case("cxx_rvalue_references", LangOpts.CPlusPlus) + // C++1y features supported by other languages as extensions. + .Case("cxx_binary_literals", true) .Default(false); } diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index 2094dd1e1c..b2ae4c9c44 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -254,14 +254,15 @@ void Preprocessor::Handle_Pragma(Token &Tok) { "Invalid string token!"); // Remove escaped quotes and escapes. - for (unsigned i = 1, e = StrVal.size(); i < e-2; ++i) { - if (StrVal[i] == '\\' && - (StrVal[i+1] == '\\' || StrVal[i+1] == '"')) { + unsigned ResultPos = 1; + for (unsigned i = 1, e = StrVal.size() - 2; i != e; ++i) { + if (StrVal[i] != '\\' || + (StrVal[i + 1] != '\\' && StrVal[i + 1] != '"')) { // \\ -> '\' and \" -> '"'. - StrVal.erase(StrVal.begin()+i); - --e; + StrVal[ResultPos++] = StrVal[i]; } } + StrVal.erase(StrVal.begin() + ResultPos, StrVal.end() - 2); } // Remove the front quote, replacing it with a space, so that the pragma @@ -434,8 +435,9 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) { // Emit a line marker. This will change any source locations from this point // forward to realize they are in a system header. // Create a line note with this information. - SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine(), FilenameID, - false, false, true, false); + SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine()+1, + FilenameID, /*IsEntry=*/false, /*IsExit=*/false, + /*IsSystem=*/true, /*IsExternC=*/false); } /// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah. @@ -491,126 +493,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { } } -/// \brief Handle the microsoft \#pragma comment extension. -/// -/// The syntax is: -/// \code -/// #pragma comment(linker, "foo") -/// \endcode -/// 'linker' is one of five identifiers: compiler, exestr, lib, linker, user. -/// "foo" is a string, which is fully macro expanded, and permits string -/// concatenation, embedded escape characters etc. See MSDN for more details. -void Preprocessor::HandlePragmaComment(Token &Tok) { - SourceLocation CommentLoc = Tok.getLocation(); - Lex(Tok); - if (Tok.isNot(tok::l_paren)) { - Diag(CommentLoc, diag::err_pragma_comment_malformed); - return; - } - - // Read the identifier. - Lex(Tok); - if (Tok.isNot(tok::identifier)) { - Diag(CommentLoc, diag::err_pragma_comment_malformed); - return; - } - - // Verify that this is one of the 5 whitelisted options. - // FIXME: warn that 'exestr' is deprecated. - const IdentifierInfo *II = Tok.getIdentifierInfo(); - if (!II->isStr("compiler") && !II->isStr("exestr") && !II->isStr("lib") && - !II->isStr("linker") && !II->isStr("user")) { - Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); - return; - } - - // Read the optional string if present. - Lex(Tok); - std::string ArgumentString; - if (Tok.is(tok::comma) && !LexStringLiteral(Tok, ArgumentString, - "pragma comment", - /*MacroExpansion=*/true)) - return; - - // FIXME: If the kind is "compiler" warn if the string is present (it is - // ignored). - // FIXME: 'lib' requires a comment string. - // FIXME: 'linker' requires a comment string, and has a specific list of - // things that are allowable. - - if (Tok.isNot(tok::r_paren)) { - Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); - return; - } - Lex(Tok); // eat the r_paren. - - if (Tok.isNot(tok::eod)) { - Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); - return; - } - - // If the pragma is lexically sound, notify any interested PPCallbacks. - if (Callbacks) - Callbacks->PragmaComment(CommentLoc, II, ArgumentString); -} - -/// HandlePragmaMessage - Handle the microsoft and gcc \#pragma message -/// extension. The syntax is: -/// \code -/// #pragma message(string) -/// \endcode -/// OR, in GCC mode: -/// \code -/// #pragma message string -/// \endcode -/// string is a string, which is fully macro expanded, and permits string -/// concatenation, embedded escape characters, etc... See MSDN for more details. -void Preprocessor::HandlePragmaMessage(Token &Tok) { - SourceLocation MessageLoc = Tok.getLocation(); - Lex(Tok); - bool ExpectClosingParen = false; - switch (Tok.getKind()) { - case tok::l_paren: - // We have a MSVC style pragma message. - ExpectClosingParen = true; - // Read the string. - Lex(Tok); - break; - case tok::string_literal: - // We have a GCC style pragma message, and we just read the string. - break; - default: - Diag(MessageLoc, diag::err_pragma_message_malformed); - return; - } - - std::string MessageString; - if (!FinishLexStringLiteral(Tok, MessageString, "pragma message", - /*MacroExpansion=*/true)) - return; - - if (ExpectClosingParen) { - if (Tok.isNot(tok::r_paren)) { - Diag(Tok.getLocation(), diag::err_pragma_message_malformed); - return; - } - Lex(Tok); // eat the r_paren. - } - - if (Tok.isNot(tok::eod)) { - Diag(Tok.getLocation(), diag::err_pragma_message_malformed); - return; - } - - // Output the message. - Diag(MessageLoc, diag::warn_pragma_message) << MessageString; - - // If the pragma is lexically sound, notify any interested PPCallbacks. - if (Callbacks) - Callbacks->PragmaMessage(MessageLoc, MessageString); -} - -/// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro. +/// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro. /// Return the IdentifierInfo* associated with the macro to push or pop. IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) { // Remember the pragma token location. @@ -703,9 +586,10 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) { if (iter != PragmaPushMacroInfo.end()) { // Forget the MacroInfo currently associated with IdentInfo. if (MacroDirective *CurrentMD = getMacroDirective(IdentInfo)) { - if (CurrentMD->getInfo()->isWarnIfUnused()) - WarnUnusedMacroLocs.erase(CurrentMD->getInfo()->getDefinitionLoc()); - UndefineMacro(IdentInfo, CurrentMD, MessageLoc); + MacroInfo *MI = CurrentMD->getMacroInfo(); + if (MI->isWarnIfUnused()) + WarnUnusedMacroLocs.erase(MI->getDefinitionLoc()); + appendMacroDirective(IdentInfo, AllocateUndefMacroDirective(MessageLoc)); } // Get the MacroInfo we want to reinstall. @@ -713,10 +597,8 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) { if (MacroToReInstall) { // Reinstall the previously pushed macro. - setMacroDirective(IdentInfo, MacroToReInstall, MessageLoc, - /*isImported=*/false); - } else if (IdentInfo->hasMacroDefinition()) { - clearMacroInfo(IdentInfo); + appendDefMacroDirective(IdentInfo, MacroToReInstall, MessageLoc, + /*isImported=*/false); } // Pop PragmaPushMacroInfo stack. @@ -996,10 +878,40 @@ struct PragmaDebugHandler : public PragmaHandler { llvm::CrashRecoveryContext *CRC =llvm::CrashRecoveryContext::GetCurrent(); if (CRC) CRC->HandleCrash(); + } else if (II->isStr("captured")) { + HandleCaptured(PP); } else { PP.Diag(Tok, diag::warn_pragma_debug_unexpected_command) << II->getName(); } + + PPCallbacks *Callbacks = PP.getPPCallbacks(); + if (Callbacks) + Callbacks->PragmaDebug(Tok.getLocation(), II->getName()); + } + + void HandleCaptured(Preprocessor &PP) { + // Skip if emitting preprocessed output. + if (PP.isPreprocessedOutput()) + return; + + Token Tok; + PP.LexUnexpandedToken(Tok); + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) + << "pragma clang __debug captured"; + return; + } + + SourceLocation NameLoc = Tok.getLocation(); + Token *Toks = PP.getPreprocessorAllocator().Allocate<Token>(1); + Toks->startToken(); + Toks->setKind(tok::annot_pragma_captured); + Toks->setLocation(NameLoc); + + PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, + /*OwnsTokens=*/false); } // Disable MSVC warning about runtime stack overflow. @@ -1087,15 +999,6 @@ public: } }; -/// PragmaCommentHandler - "\#pragma comment ...". -struct PragmaCommentHandler : public PragmaHandler { - PragmaCommentHandler() : PragmaHandler("comment") {} - virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, - Token &CommentTok) { - PP.HandlePragmaComment(CommentTok); - } -}; - /// PragmaIncludeAliasHandler - "\#pragma include_alias("...")". struct PragmaIncludeAliasHandler : public PragmaHandler { PragmaIncludeAliasHandler() : PragmaHandler("include_alias") {} @@ -1105,12 +1008,88 @@ struct PragmaIncludeAliasHandler : public PragmaHandler { } }; -/// PragmaMessageHandler - "\#pragma message("...")". +/// PragmaMessageHandler - Handle the microsoft and gcc \#pragma message +/// extension. The syntax is: +/// \code +/// #pragma message(string) +/// \endcode +/// OR, in GCC mode: +/// \code +/// #pragma message string +/// \endcode +/// string is a string, which is fully macro expanded, and permits string +/// concatenation, embedded escape characters, etc... See MSDN for more details. +/// Also handles \#pragma GCC warning and \#pragma GCC error which take the same +/// form as \#pragma message. struct PragmaMessageHandler : public PragmaHandler { - PragmaMessageHandler() : PragmaHandler("message") {} +private: + const PPCallbacks::PragmaMessageKind Kind; + const StringRef Namespace; + + static const char* PragmaKind(PPCallbacks::PragmaMessageKind Kind, + bool PragmaNameOnly = false) { + switch (Kind) { + case PPCallbacks::PMK_Message: + return PragmaNameOnly ? "message" : "pragma message"; + case PPCallbacks::PMK_Warning: + return PragmaNameOnly ? "warning" : "pragma warning"; + case PPCallbacks::PMK_Error: + return PragmaNameOnly ? "error" : "pragma error"; + } + llvm_unreachable("Unknown PragmaMessageKind!"); + } + +public: + PragmaMessageHandler(PPCallbacks::PragmaMessageKind Kind, + StringRef Namespace = StringRef()) + : PragmaHandler(PragmaKind(Kind, true)), Kind(Kind), Namespace(Namespace) {} + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, - Token &CommentTok) { - PP.HandlePragmaMessage(CommentTok); + Token &Tok) { + SourceLocation MessageLoc = Tok.getLocation(); + PP.Lex(Tok); + bool ExpectClosingParen = false; + switch (Tok.getKind()) { + case tok::l_paren: + // We have a MSVC style pragma message. + ExpectClosingParen = true; + // Read the string. + PP.Lex(Tok); + break; + case tok::string_literal: + // We have a GCC style pragma message, and we just read the string. + break; + default: + PP.Diag(MessageLoc, diag::err_pragma_message_malformed) << Kind; + return; + } + + std::string MessageString; + if (!PP.FinishLexStringLiteral(Tok, MessageString, PragmaKind(Kind), + /*MacroExpansion=*/true)) + return; + + if (ExpectClosingParen) { + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_message_malformed) << Kind; + return; + } + PP.Lex(Tok); // eat the r_paren. + } + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_message_malformed) << Kind; + return; + } + + // Output the message. + PP.Diag(MessageLoc, (Kind == PPCallbacks::PMK_Error) + ? diag::err_pragma_message + : diag::warn_pragma_message) << MessageString; + + // If the pragma is lexically sound, notify any interested PPCallbacks. + if (PPCallbacks *Callbacks = PP.getPPCallbacks()) + Callbacks->PragmaMessage(MessageLoc, Namespace, Kind, MessageString); } }; @@ -1258,13 +1237,17 @@ void Preprocessor::RegisterBuiltinPragmas() { AddPragmaHandler(new PragmaMarkHandler()); AddPragmaHandler(new PragmaPushMacroHandler()); AddPragmaHandler(new PragmaPopMacroHandler()); - AddPragmaHandler(new PragmaMessageHandler()); + AddPragmaHandler(new PragmaMessageHandler(PPCallbacks::PMK_Message)); // #pragma GCC ... AddPragmaHandler("GCC", new PragmaPoisonHandler()); AddPragmaHandler("GCC", new PragmaSystemHeaderHandler()); AddPragmaHandler("GCC", new PragmaDependencyHandler()); AddPragmaHandler("GCC", new PragmaDiagnosticHandler("GCC")); + AddPragmaHandler("GCC", new PragmaMessageHandler(PPCallbacks::PMK_Warning, + "GCC")); + AddPragmaHandler("GCC", new PragmaMessageHandler(PPCallbacks::PMK_Error, + "GCC")); // #pragma clang ... AddPragmaHandler("clang", new PragmaPoisonHandler()); AddPragmaHandler("clang", new PragmaSystemHeaderHandler()); @@ -1279,7 +1262,6 @@ void Preprocessor::RegisterBuiltinPragmas() { // MS extensions. if (LangOpts.MicrosoftExt) { - AddPragmaHandler(new PragmaCommentHandler()); AddPragmaHandler(new PragmaIncludeAliasHandler()); AddPragmaHandler(new PragmaRegionHandler("region")); AddPragmaHandler(new PragmaRegionHandler("endregion")); diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp index b834d6cfb8..426b922562 100644 --- a/lib/Lex/PreprocessingRecord.cpp +++ b/lib/Lex/PreprocessingRecord.cpp @@ -385,31 +385,35 @@ void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok, const MacroDirective *MD) { // This is not actually a macro expansion but record it as a macro reference. if (MD) - addMacroExpansion(MacroNameTok, MD->getInfo(), MacroNameTok.getLocation()); + addMacroExpansion(MacroNameTok, MD->getMacroInfo(), + MacroNameTok.getLocation()); } void PreprocessingRecord::Ifndef(SourceLocation Loc, const Token &MacroNameTok, const MacroDirective *MD) { // This is not actually a macro expansion but record it as a macro reference. if (MD) - addMacroExpansion(MacroNameTok, MD->getInfo(), MacroNameTok.getLocation()); + addMacroExpansion(MacroNameTok, MD->getMacroInfo(), + MacroNameTok.getLocation()); } void PreprocessingRecord::Defined(const Token &MacroNameTok, const MacroDirective *MD) { // This is not actually a macro expansion but record it as a macro reference. if (MD) - addMacroExpansion(MacroNameTok, MD->getInfo(), MacroNameTok.getLocation()); + addMacroExpansion(MacroNameTok, MD->getMacroInfo(), + MacroNameTok.getLocation()); } void PreprocessingRecord::MacroExpands(const Token &Id,const MacroDirective *MD, - SourceRange Range) { - addMacroExpansion(Id, MD->getInfo(), Range); + SourceRange Range, + const MacroArgs *Args) { + addMacroExpansion(Id, MD->getMacroInfo(), Range); } void PreprocessingRecord::MacroDefined(const Token &Id, const MacroDirective *MD) { - const MacroInfo *MI = MD->getInfo(); + const MacroInfo *MI = MD->getMacroInfo(); SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc()); MacroDefinition *Def = new (*this) MacroDefinition(Id.getIdentifierInfo(), R); @@ -421,7 +425,7 @@ void PreprocessingRecord::MacroUndefined(const Token &Id, const MacroDirective *MD) { // Note: MI may be null (when #undef'ining an undefined macro). if (MD) - MacroDefinitions.erase(MD->getInfo()); + MacroDefinitions.erase(MD->getMacroInfo()); } void PreprocessingRecord::InclusionDirective( diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index af000ec1d1..66f23f1018 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -26,7 +26,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Preprocessor.h" -#include "MacroArgs.h" +#include "clang/Lex/MacroArgs.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -54,8 +54,6 @@ using namespace clang; //===----------------------------------------------------------------------===// ExternalPreprocessorSource::~ExternalPreprocessorSource() { } -PPMutationListener::~PPMutationListener() { } - Preprocessor::Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts, DiagnosticsEngine &diags, LangOptions &opts, const TargetInfo *target, SourceManager &SM, @@ -68,8 +66,9 @@ Preprocessor::Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts, Identifiers(opts, IILookup), IncrementalProcessing(IncrProcessing), CodeComplete(0), CodeCompletionFile(0), CodeCompletionOffset(0), CodeCompletionReached(0), SkipMainFilePreamble(0, true), CurPPLexer(0), - CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), Listener(0), - MacroArgCache(0), Record(0), MIChainHead(0), MICache(0) { + CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), + MacroArgCache(0), Record(0), MIChainHead(0), MICache(0), + DeserialMIChainHead(0) { OwnsHeaderSearch = OwnsHeaders; ScratchBuf = new ScratchBuffer(SourceMgr); @@ -155,6 +154,9 @@ Preprocessor::~Preprocessor() { for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i) delete TokenLexerCache[i]; + for (DeserializedMacroInfoChain *I = DeserialMIChainHead ; I ; I = I->Next) + I->MI.Destroy(); + // Free any cached MacroArgs. for (MacroArgs *ArgList = MacroArgCache; ArgList; ) ArgList = ArgList->deallocate(); @@ -306,15 +308,15 @@ StringRef Preprocessor::getLastMacroWithSpelling( StringRef BestSpelling; for (Preprocessor::macro_iterator I = macro_begin(), E = macro_end(); I != E; ++I) { - if (!I->second->getInfo()->isObjectLike()) + if (!I->second->getMacroInfo()->isObjectLike()) continue; - const MacroDirective * - MD = I->second->findDirectiveAtLoc(Loc, SourceMgr); - if (!MD) + const MacroDirective::DefInfo + Def = I->second->findDirectiveAtLoc(Loc, SourceMgr); + if (!Def) continue; - if (!MacroDefinitionEquals(MD->getInfo(), Tokens)) + if (!MacroDefinitionEquals(Def.getMacroInfo(), Tokens)) continue; - SourceLocation Location = I->second->getInfo()->getDefinitionLoc(); + SourceLocation Location = Def.getLocation(); // Choose the macro defined latest. if (BestLocation.isInvalid() || (Location.isValid() && @@ -643,7 +645,7 @@ void Preprocessor::HandleIdentifier(Token &Identifier) { // If this is a macro to be expanded, do it. if (MacroDirective *MD = getMacroDirective(&II)) { - MacroInfo *MI = MD->getInfo(); + MacroInfo *MI = MD->getMacroInfo(); if (!DisableMacroExpansion) { if (!Identifier.isExpandDisabled() && MI->isEnabled()) { if (!HandleMacroExpandedIdentifier(Identifier, MD)) diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index 5b41fe9b8d..07753c7d7c 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/TokenLexer.h" -#include "MacroArgs.h" +#include "clang/Lex/MacroArgs.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/MacroInfo.h" diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt index 55e2aebca8..01c0694d03 100644 --- a/lib/Parse/CMakeLists.txt +++ b/lib/Parse/CMakeLists.txt @@ -7,6 +7,7 @@ add_clang_library(clangParse ParseExprCXX.cpp ParseInit.cpp ParseObjc.cpp + ParseOpenMP.cpp ParsePragma.cpp ParseStmt.cpp ParseTemplate.cpp @@ -16,6 +17,7 @@ add_clang_library(clangParse add_dependencies(clangParse ClangAttrClasses + ClangAttrExprArgs ClangAttrLateParsed ClangAttrList ClangAttrParsedAttrList diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp index 5e769c5691..7cd8a21ac4 100644 --- a/lib/Parse/ParseAST.cpp +++ b/lib/Parse/ParseAST.cpp @@ -55,10 +55,21 @@ void PrettyStackTraceParserEntry::print(raw_ostream &OS) const { const Preprocessor &PP = P.getPreprocessor(); Tok.getLocation().print(OS, PP.getSourceManager()); - if (Tok.isAnnotation()) - OS << ": at annotation token \n"; - else - OS << ": current parser token '" << PP.getSpelling(Tok) << "'\n"; + if (Tok.isAnnotation()) { + OS << ": at annotation token\n"; + } else { + // Do the equivalent of PP.getSpelling(Tok) except for the parts that would + // allocate memory. + bool Invalid = false; + const SourceManager &SM = P.getPreprocessor().getSourceManager(); + unsigned Length = Tok.getLength(); + const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid); + if (Invalid) { + OS << ": unknown current parser token\n"; + return; + } + OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n"; + } } } // namespace diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index e15ab0ae98..5fc4189742 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -19,6 +19,13 @@ #include "clang/Sema/Scope.h" using namespace clang; +/// Get the FunctionDecl for a function or function template decl. +static FunctionDecl *getFunctionDecl(Decl *D) { + if (FunctionDecl *fn = dyn_cast<FunctionDecl>(D)) + return fn; + return cast<FunctionTemplateDecl>(D)->getTemplatedDecl(); +} + /// ParseCXXInlineMethodDef - We parsed and verified that the specified /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. @@ -50,8 +57,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, if (FnD) { Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, false, true); - bool TypeSpecContainsAuto - = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + bool TypeSpecContainsAuto = D.getDeclSpec().containsPlaceholderType(); if (Init.isUsable()) Actions.AddInitializerToDecl(FnD, Init.get(), false, TypeSpecContainsAuto); @@ -117,11 +123,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, if (FnD) { LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(FnD); - FunctionDecl *FD = 0; - if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(FnD)) - FD = FunTmpl->getTemplatedDecl(); - else - FD = cast<FunctionDecl>(FnD); + FunctionDecl *FD = getFunctionDecl(FnD); Actions.CheckForFunctionRedefinition(FD); LateParsedTemplateMap[FD] = LPT; @@ -176,6 +178,19 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, getCurrentClass().LateParsedDeclarations.pop_back(); } + // If this is a friend function, mark that it's late-parsed so that + // it's still known to be a definition even before we attach the + // parsed body. Sema needs to treat friend function definitions + // differently during template instantiation, and it's possible for + // the containing class to be instantiated before all its member + // function definitions are parsed. + // + // If you remove this, you can remove the code that clears the flag + // after parsing the member. + if (D.getDeclSpec().isFriendSpecified()) { + getFunctionDecl(FnD)->setLateTemplateParsed(true); + } + return FnD; } @@ -263,8 +278,11 @@ void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() { void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (HasTemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + ++CurTemplateDepthTracker; + } // The current scope is still active if we're the top-level class. // Otherwise we'll need to push and enter a new scope. @@ -285,9 +303,11 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // If this is a member template, introduce the template parameter scope. ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - if (LM.TemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (LM.TemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); - + ++CurTemplateDepthTracker; + } // Start the delayed C++ method declaration Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); @@ -363,9 +383,11 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { void Parser::ParseLexedMethodDefs(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (HasTemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); - + ++CurTemplateDepthTracker; + } bool HasClassScope = !Class.TopLevelClass; ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope); @@ -378,9 +400,11 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { void Parser::ParseLexedMethodDef(LexedMethod &LM) { // If this is a member template, introduce the template parameter scope. ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - if (LM.TemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (LM.TemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), LM.D); - + ++CurTemplateDepthTracker; + } // Save the current token position. SourceLocation origLoc = Tok.getLocation(); @@ -391,7 +415,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && "Inline method not starting with '{', ':' or 'try'"); @@ -425,8 +449,18 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { } else Actions.ActOnDefaultCtorInitializers(LM.D); + assert((Actions.getDiagnostics().hasErrorOccurred() || + !isa<FunctionTemplateDecl>(LM.D) || + cast<FunctionTemplateDecl>(LM.D)->getTemplateParameters()->getDepth() + < TemplateParameterDepth) && + "TemplateParameterDepth should be greater than the depth of " + "current template being instantiated!"); + ParseFunctionStatementBody(LM.D, FnScope); + // Clear the late-template-parsed bit if we set it before. + if (LM.D) getFunctionDecl(LM.D)->setLateTemplateParsed(false); + if (Tok.getLocation() != origLoc) { // Due to parsing error, we either went over the cached tokens or // there are still cached tokens left. If it's the latter case skip the @@ -447,9 +481,11 @@ void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (HasTemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); - + ++CurTemplateDepthTracker; + } // Set or update the scope flags. bool AlreadyHasClassScope = Class.TopLevelClass; unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope; @@ -491,7 +527,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); SourceLocation EqualLoc; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 5202e694d8..6a87b78879 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -178,6 +178,12 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, } } +/// \brief Determine whether the given attribute has all expression arguments. +static bool attributeHasExprArgs(const IdentifierInfo &II) { + return llvm::StringSwitch<bool>(II.getName()) +#include "clang/Parse/AttrExprArgs.inc" + .Default(false); +} /// Parse the arguments to a parameterized GNU attribute or /// a C++11 attribute in "gnu" namespace. @@ -247,6 +253,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, TypeParsed = true; break; } + // If the attribute has all expression arguments, and not a "parameter", + // break out to handle it below. + if (attributeHasExprArgs(*AttrName)) + break; ParmName = Tok.getIdentifierInfo(); ParmLoc = ConsumeToken(); break; @@ -364,6 +374,7 @@ bool Parser::IsSimpleMicrosoftDeclSpec(IdentifierInfo *Ident) { .Case("novtable", true) .Case("selectany", true) .Case("thread", true) + .Case("safebuffers", true ) .Default(false); } @@ -394,17 +405,119 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, // The property declspec is more complex in that it can take one or two // assignment expressions as a parameter, but the lhs of the assignment // must be named get or put. - // - // For right now, we will just skip to the closing right paren of the - // property expression. - // - // FIXME: we should deal with __declspec(property) at some point because it - // is used in the platform SDK headers for the Parallel Patterns Library - // and ATL. - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, - Ident->getNameStart(), tok::r_paren)) + if (Tok.isNot(tok::l_paren)) { + Diag(Tok.getLocation(), diag::err_expected_lparen_after) + << Ident->getNameStart(); return; + } + BalancedDelimiterTracker T(*this, tok::l_paren); + T.expectAndConsume(diag::err_expected_lparen_after, + Ident->getNameStart(), tok::r_paren); + + enum AccessorKind { + AK_Invalid = -1, + AK_Put = 0, AK_Get = 1 // indices into AccessorNames + }; + IdentifierInfo *AccessorNames[] = { 0, 0 }; + bool HasInvalidAccessor = false; + + // Parse the accessor specifications. + while (true) { + // Stop if this doesn't look like an accessor spec. + if (!Tok.is(tok::identifier)) { + // If the user wrote a completely empty list, use a special diagnostic. + if (Tok.is(tok::r_paren) && !HasInvalidAccessor && + AccessorNames[AK_Put] == 0 && AccessorNames[AK_Get] == 0) { + Diag(Loc, diag::err_ms_property_no_getter_or_putter); + break; + } + + Diag(Tok.getLocation(), diag::err_ms_property_unknown_accessor); + break; + } + + AccessorKind Kind; + SourceLocation KindLoc = Tok.getLocation(); + StringRef KindStr = Tok.getIdentifierInfo()->getName(); + if (KindStr == "get") { + Kind = AK_Get; + } else if (KindStr == "put") { + Kind = AK_Put; + + // Recover from the common mistake of using 'set' instead of 'put'. + } else if (KindStr == "set") { + Diag(KindLoc, diag::err_ms_property_has_set_accessor) + << FixItHint::CreateReplacement(KindLoc, "put"); + Kind = AK_Put; + + // Handle the mistake of forgetting the accessor kind by skipping + // this accessor. + } else if (NextToken().is(tok::comma) || NextToken().is(tok::r_paren)) { + Diag(KindLoc, diag::err_ms_property_missing_accessor_kind); + ConsumeToken(); + HasInvalidAccessor = true; + goto next_property_accessor; + + // Otherwise, complain about the unknown accessor kind. + } else { + Diag(KindLoc, diag::err_ms_property_unknown_accessor); + HasInvalidAccessor = true; + Kind = AK_Invalid; + + // Try to keep parsing unless it doesn't look like an accessor spec. + if (!NextToken().is(tok::equal)) break; + } + + // Consume the identifier. + ConsumeToken(); + + // Consume the '='. + if (Tok.is(tok::equal)) { + ConsumeToken(); + } else { + Diag(Tok.getLocation(), diag::err_ms_property_expected_equal) + << KindStr; + break; + } + + // Expect the method name. + if (!Tok.is(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_ms_property_expected_accessor_name); + break; + } + + if (Kind == AK_Invalid) { + // Just drop invalid accessors. + } else if (AccessorNames[Kind] != NULL) { + // Complain about the repeated accessor, ignore it, and keep parsing. + Diag(KindLoc, diag::err_ms_property_duplicate_accessor) << KindStr; + } else { + AccessorNames[Kind] = Tok.getIdentifierInfo(); + } + ConsumeToken(); + + next_property_accessor: + // Keep processing accessors until we run out. + if (Tok.is(tok::comma)) { + ConsumeAnyToken(); + continue; + + // If we run into the ')', stop without consuming it. + } else if (Tok.is(tok::r_paren)) { + break; + } else { + Diag(Tok.getLocation(), diag::err_ms_property_expected_comma_or_rparen); + break; + } + } + + // Only add the property attribute if it was well-formed. + if (!HasInvalidAccessor) { + Attrs.addNewPropertyAttr(Ident, Loc, 0, SourceLocation(), 0, + SourceLocation(), + AccessorNames[AK_Get], AccessorNames[AK_Put], + AttributeList::AS_Declspec); + } T.skipToEnd(); } else { // We don't recognize this as a valid declspec, but instead of creating the @@ -931,7 +1044,7 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, LA.Toks.push_back(Tok); PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) { // FIXME: Do not warn on C++11 attributes, once we start supporting @@ -1489,35 +1602,42 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, MaybeParseGNUAttributes(D, &LateParsedAttrs); // Check to see if we have a function *definition* which must have a body. - if (AllowFunctionDefinitions && D.isFunctionDeclarator() && + if (D.isFunctionDeclarator() && // Look at the next token to make sure that this isn't a function // declaration. We have to check this because __attribute__ might be the // start of a function definition in GCC-extended K&R C. !isDeclarationAfterDeclarator()) { - if (isStartOfFunctionDefinition(D)) { - if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { - Diag(Tok, diag::err_function_declared_typedef); + if (AllowFunctionDefinitions) { + if (isStartOfFunctionDefinition(D)) { + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { + Diag(Tok, diag::err_function_declared_typedef); - // Recover by treating the 'typedef' as spurious. - DS.ClearStorageClassSpecs(); - } + // Recover by treating the 'typedef' as spurious. + DS.ClearStorageClassSpecs(); + } - Decl *TheDecl = - ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs); - return Actions.ConvertDeclToDeclGroup(TheDecl); - } + Decl *TheDecl = + ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs); + return Actions.ConvertDeclToDeclGroup(TheDecl); + } - if (isDeclarationSpecifier()) { - // If there is an invalid declaration specifier right after the function - // prototype, then we must be in a missing semicolon case where this isn't - // actually a body. Just fall through into the code that handles it as a - // prototype, and let the top-level code handle the erroneous declspec - // where it would otherwise expect a comma or semicolon. + if (isDeclarationSpecifier()) { + // If there is an invalid declaration specifier right after the function + // prototype, then we must be in a missing semicolon case where this isn't + // actually a body. Just fall through into the code that handles it as a + // prototype, and let the top-level code handle the erroneous declspec + // where it would otherwise expect a comma or semicolon. + } else { + Diag(Tok, diag::err_expected_fn_body); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } } else { - Diag(Tok, diag::err_expected_fn_body); - SkipUntil(tok::semi); - return DeclGroupPtrTy(); + if (Tok.is(tok::l_brace)) { + Diag(Tok, diag::err_function_definition_not_allowed); + SkipUntil(tok::r_brace, true, true); + } } } @@ -1527,14 +1647,23 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // C++0x [stmt.iter]p1: Check if we have a for-range-declarator. If so, we // must parse and analyze the for-range-initializer before the declaration is // analyzed. - if (FRI && Tok.is(tok::colon)) { - FRI->ColonLoc = ConsumeToken(); - if (Tok.is(tok::l_brace)) - FRI->RangeExpr = ParseBraceInitializer(); - else - FRI->RangeExpr = ParseExpression(); + // + // Handle the Objective-C for-in loop variable similarly, although we + // don't need to parse the container in advance. + if (FRI && (Tok.is(tok::colon) || isTokIdentifier_in())) { + bool IsForRangeLoop = false; + if (Tok.is(tok::colon)) { + IsForRangeLoop = true; + FRI->ColonLoc = ConsumeToken(); + if (Tok.is(tok::l_brace)) + FRI->RangeExpr = ParseBraceInitializer(); + else + FRI->RangeExpr = ParseExpression(); + } + Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); - Actions.ActOnCXXForRangeDecl(ThisDecl); + if (IsForRangeLoop) + Actions.ActOnCXXForRangeDecl(ThisDecl); Actions.FinalizeDeclaration(ThisDecl); D.complete(ThisDecl); return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1); @@ -1691,8 +1820,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, } } - bool TypeContainsAuto = - D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType(); // Parse declarator '=' initializer. // If a '==' or '+=' is found, suggest a fixit to '='. @@ -1839,7 +1967,8 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, if (DS.getStorageClassSpecLoc().isValid()) Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass); else - Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass); + Diag(DS.getThreadStorageClassSpecLoc(), + diag::err_typename_invalid_storageclass); DS.ClearStorageClassSpecs(); } @@ -1920,10 +2049,9 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // error, do lookahead to try to do better recovery. This never applies // within a type specifier. Outside of C++, we allow this even if the // language doesn't "officially" support implicit int -- we support - // implicit int as an extension in C99 and C11. Allegedly, MS also - // supports implicit int in C++ mode. + // implicit int as an extension in C99 and C11. if (DSC != DSC_type_specifier && DSC != DSC_trailing && - (!getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt) && + !getLangOpts().CPlusPlus && isValidAfterIdentifierInDeclarator(NextToken())) { // If this token is valid for implicit int, e.g. "static x = 4", then // we just avoid eating the identifier, so it will be parsed as the @@ -2172,6 +2300,8 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, /// 'auto' /// 'register' /// [C++] 'mutable' +/// [C++11] 'thread_local' +/// [C11] '_Thread_local' /// [GNU] '__thread' /// function-specifier: [C99 6.7.4] /// [C99] 'inline' @@ -2608,7 +2738,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, PrevSpec, DiagID); break; case tok::kw_extern: - if (DS.isThreadSpecified()) + if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread) Diag(Tok, diag::ext_thread_before) << "extern"; isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc, PrevSpec, DiagID); @@ -2618,7 +2748,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Loc, PrevSpec, DiagID); break; case tok::kw_static: - if (DS.isThreadSpecified()) + if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread) Diag(Tok, diag::ext_thread_before) << "static"; isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc, PrevSpec, DiagID); @@ -2647,7 +2777,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, PrevSpec, DiagID); break; case tok::kw___thread: - isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID); + isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS___thread, Loc, + PrevSpec, DiagID); + break; + case tok::kw_thread_local: + isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS_thread_local, Loc, + PrevSpec, DiagID); + break; + case tok::kw__Thread_local: + isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS__Thread_local, + Loc, PrevSpec, DiagID); break; // function-specifier @@ -2905,8 +3044,17 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; case tok::kw__Atomic: - ParseAtomicSpecifier(DS); - continue; + // C11 6.7.2.4/4: + // If the _Atomic keyword is immediately followed by a left parenthesis, + // it is interpreted as a type specifier (with a type name), not as a + // type qualifier. + if (NextToken().is(tok::l_paren)) { + ParseAtomicSpecifier(DS); + continue; + } + isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID, + getLangOpts()); + break; // OpenCL qualifiers: case tok::kw_private: @@ -3057,6 +3205,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, unsigned TagType, Decl *TagDecl) { PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc, "parsing struct/union body"); + assert(!getLangOpts().CPlusPlus && "C++ declarations not supported"); BalancedDelimiterTracker T(*this, tok::l_brace); if (T.consumeOpen()) @@ -3065,9 +3214,8 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); - // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in - // C++. - if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) { + // Empty structs are an extension in C (C99 6.7.2.1p7). + if (Tok.is(tok::r_brace)) { Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union); Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union); } @@ -3084,6 +3232,23 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } + // Parse _Static_assert declaration. + if (Tok.is(tok::kw__Static_assert)) { + SourceLocation DeclEnd; + ParseStaticAssertDeclaration(DeclEnd); + continue; + } + + if (Tok.is(tok::annot_pragma_pack)) { + HandlePragmaPack(); + continue; + } + + if (Tok.is(tok::annot_pragma_align)) { + HandlePragmaAlign(); + continue; + } + if (!Tok.is(tok::at)) { struct CFieldCallback : FieldCallback { Parser &P; @@ -3211,9 +3376,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, bool IsScopedUsingClassTag = false; // In C++11, recognize 'enum class' and 'enum struct'. - if (getLangOpts().CPlusPlus11 && - (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) { - Diag(Tok, diag::warn_cxx98_compat_scoped_enum); + if (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct)) { + Diag(Tok, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_scoped_enum + : diag::ext_scoped_enum); IsScopedUsingClassTag = Tok.is(tok::kw_class); ScopedEnumKWLoc = ConsumeToken(); @@ -3253,7 +3418,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType); if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), - /*EnteringContext=*/false)) + /*EnteringContext=*/true)) return; if (SS.isSet() && Tok.isNot(tok::identifier)) { @@ -3598,8 +3763,8 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { MaybeParseGNUAttributes(attrs); Actions.ActOnEnumBody(StartLoc, T.getOpenLocation(), T.getCloseLocation(), - EnumDecl, EnumConstantDecls.data(), - EnumConstantDecls.size(), getCurScope(), + EnumDecl, EnumConstantDecls, + getCurScope(), attrs.getList()); EnumScope.Exit(); @@ -3814,7 +3979,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw_private: return getLangOpts().OpenCL; - // C11 _Atomic() + // C11 _Atomic case tok::kw__Atomic: return true; } @@ -3878,6 +4043,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_auto: case tok::kw_register: case tok::kw___thread: + case tok::kw_thread_local: + case tok::kw__Thread_local: // Modules case tok::kw___module_private__: @@ -3959,7 +4126,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::annot_decltype: case tok::kw_constexpr: - // C11 _Atomic() + // C11 _Atomic case tok::kw__Atomic: return true; @@ -4099,7 +4266,8 @@ bool Parser::isConstructorDeclarator() { /// void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool VendorAttributesAllowed, - bool CXX11AttributesAllowed) { + bool CXX11AttributesAllowed, + bool AtomicAllowed) { if (getLangOpts().CPlusPlus11 && CXX11AttributesAllowed && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); @@ -4132,6 +4300,12 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, getLangOpts()); break; + case tok::kw__Atomic: + if (!AtomicAllowed) + goto DoneWithTypeQuals; + isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID, + getLangOpts()); + break; // OpenCL qualifiers: case tok::kw_private: @@ -4346,6 +4520,10 @@ void Parser::ParseDeclaratorInternal(Declarator &D, if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) Diag(DS.getVolatileSpecLoc(), diag::err_invalid_reference_qualifier_application) << "volatile"; + // 'restrict' is permitted as an extension. + if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) + Diag(DS.getAtomicSpecLoc(), + diag::err_invalid_reference_qualifier_application) << "_Atomic"; } // Recursively parse the declarator. @@ -4368,7 +4546,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, } } - // Remember that we parsed a reference type. It doesn't have type-quals. + // Remember that we parsed a reference type. D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc, Kind == tok::amp), DS.getAttributes(), @@ -4809,7 +4987,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D, // with the virt-specifier-seq and pure-specifier in the same way. // Parse cv-qualifier-seq[opt]. - ParseTypeQualifierListOpt(DS, false /*no attributes*/, false); + ParseTypeQualifierListOpt(DS, /*VendorAttributesAllowed*/ false, + /*CXX11AttributesAllowed*/ false, + /*AtomicAllowed*/ false); if (!DS.getSourceRange().getEnd().isInvalid()) { EndLoc = DS.getSourceRange().getEnd(); ConstQualifierLoc = DS.getConstSpecLoc(); @@ -4833,16 +5013,19 @@ void Parser::ParseFunctionDeclarator(Declarator &D, // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq // and the end of the function-definition, member-declarator, or // declarator. + // FIXME: currently, "static" case isn't handled correctly. bool IsCXX11MemberFunction = getLangOpts().CPlusPlus11 && - (D.getContext() == Declarator::MemberContext || - (D.getContext() == Declarator::FileContext && - D.getCXXScopeSpec().isValid() && - Actions.CurContext->isRecord())); + (D.getContext() == Declarator::MemberContext + ? !D.getDeclSpec().isFriendSpecified() + : D.getContext() == Declarator::FileContext && + D.getCXXScopeSpec().isValid() && + Actions.CurContext->isRecord()); Sema::CXXThisScopeRAII ThisScope(Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), DS.getTypeQualifiers() | - (D.getDeclSpec().isConstexprSpecified() + (D.getDeclSpec().isConstexprSpecified() && + !getLangOpts().CPlusPlus1y ? Qualifiers::Const : 0), IsCXX11MemberFunction); @@ -5348,14 +5531,13 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { /// _Atomic ( type-name ) /// void Parser::ParseAtomicSpecifier(DeclSpec &DS) { - assert(Tok.is(tok::kw__Atomic) && "Not an atomic specifier"); + assert(Tok.is(tok::kw__Atomic) && NextToken().is(tok::l_paren) && + "Not an atomic specifier"); SourceLocation StartLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, "_Atomic")) { - SkipUntil(tok::r_paren); + if (T.consumeOpen()) return; - } TypeResult Result = ParseTypeName(); if (Result.isInvalid()) { diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index f040b9bfff..f1fbbb15fe 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -468,7 +468,10 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, } // Parse nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + IdentifierInfo *LastII = 0; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false, + /*MayBePseudoDtor=*/0, /*IsTypename=*/false, + /*LastII=*/&LastII); // Check nested-name specifier. if (SS.isInvalid()) { @@ -476,18 +479,31 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } + SourceLocation TemplateKWLoc; + UnqualifiedId Name; + // Parse the unqualified-id. We allow parsing of both constructor and // destructor names and allow the action module to diagnose any semantic // errors. - SourceLocation TemplateKWLoc; - UnqualifiedId Name; - if (ParseUnqualifiedId(SS, - /*EnteringContext=*/false, - /*AllowDestructorName=*/true, - /*AllowConstructorName=*/true, - ParsedType(), - TemplateKWLoc, - Name)) { + // + // C++11 [class.qual]p2: + // [...] in a using-declaration that is a member-declaration, if the name + // specified after the nested-name-specifier is the same as the identifier + // or the simple-template-id's template-name in the last component of the + // nested-name-specifier, the name is [...] considered to name the + // constructor. + if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext && + Tok.is(tok::identifier) && NextToken().is(tok::semi) && + SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() && + !SS.getScopeRep()->getAsNamespace() && + !SS.getScopeRep()->getAsNamespaceAlias()) { + SourceLocation IdLoc = ConsumeToken(); + ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII); + Name.setConstructorName(Type, IdLoc, IdLoc); + } else if (ParseUnqualifiedId(SS, /*EnteringContext=*/ false, + /*AllowDestructorName=*/ true, + /*AllowConstructorName=*/ true, ParsedType(), + TemplateKWLoc, Name)) { SkipUntil(tok::semi); return 0; } @@ -658,15 +674,15 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ T.getCloseLocation()); } -/// ParseDecltypeSpecifier - Parse a C++0x decltype specifier. +/// ParseDecltypeSpecifier - Parse a C++11 decltype specifier. /// /// 'decltype' ( expression ) +/// 'decltype' ( 'auto' ) [C++1y] /// SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { assert((Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) && "Not a decltype specifier"); - ExprResult Result; SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc; @@ -693,29 +709,44 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { StartLoc : T.getOpenLocation(); } - // Parse the expression - - // C++0x [dcl.type.simple]p4: - // The operand of the decltype specifier is an unevaluated operand. - EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, - 0, /*IsDecltype=*/true); - Result = ParseExpression(); - if (Result.isInvalid()) { - DS.SetTypeSpecError(); - if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true)) { - EndLoc = ConsumeParen(); - } else { - if (PP.isBacktrackEnabled() && Tok.is(tok::semi)) { - // Backtrack to get the location of the last token before the semi. - PP.RevertCachedTokens(2); - ConsumeToken(); // the semi. - EndLoc = ConsumeAnyToken(); - assert(Tok.is(tok::semi)); + // Check for C++1y 'decltype(auto)'. + if (Tok.is(tok::kw_auto)) { + // No need to disambiguate here: an expression can't start with 'auto', + // because the typename-specifier in a function-style cast operation can't + // be 'auto'. + Diag(Tok.getLocation(), + getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_decltype_auto_type_specifier + : diag::ext_decltype_auto_type_specifier); + ConsumeToken(); + } else { + // Parse the expression + + // C++11 [dcl.type.simple]p4: + // The operand of the decltype specifier is an unevaluated operand. + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, + 0, /*IsDecltype=*/true); + Result = ParseExpression(); + if (Result.isInvalid()) { + DS.SetTypeSpecError(); + if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true, + /*DontConsume=*/true)) { + EndLoc = ConsumeParen(); } else { - EndLoc = Tok.getLocation(); + if (PP.isBacktrackEnabled() && Tok.is(tok::semi)) { + // Backtrack to get the location of the last token before the semi. + PP.RevertCachedTokens(2); + ConsumeToken(); // the semi. + EndLoc = ConsumeAnyToken(); + assert(Tok.is(tok::semi)); + } else { + EndLoc = Tok.getLocation(); + } } + return EndLoc; } - return EndLoc; + + Result = Actions.ActOnDecltypeExpression(Result.take()); } // Match the ')' @@ -727,7 +758,6 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { return T.getCloseLocation(); } - Result = Actions.ActOnDecltypeExpression(Result.take()); if (Result.isInvalid()) { DS.SetTypeSpecError(); return T.getCloseLocation(); @@ -735,12 +765,16 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { EndLoc = T.getCloseLocation(); } + assert(!Result.isInvalid()); const char *PrevSpec = 0; unsigned DiagID; // Check for duplicate type specifiers (e.g. "int decltype(a)"). - if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec, - DiagID, Result.release())) { + if (Result.get() + ? DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec, + DiagID, Result.release()) + : DS.SetTypeSpecType(DeclSpec::TST_decltype_auto, StartLoc, PrevSpec, + DiagID)) { Diag(StartLoc, DiagID) << PrevSpec; DS.SetTypeSpecError(); } @@ -757,8 +791,10 @@ void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS, PP.EnterToken(Tok); Tok.setKind(tok::annot_decltype); - setExprAnnotation(Tok, DS.getTypeSpecType() == TST_decltype ? - DS.getRepAsExpr() : ExprResult()); + setExprAnnotation(Tok, + DS.getTypeSpecType() == TST_decltype ? DS.getRepAsExpr() : + DS.getTypeSpecType() == TST_decltype_auto ? ExprResult() : + ExprError()); Tok.setAnnotationEndLoc(EndLoc); Tok.setLocation(StartLoc); PP.AnnotateCachedTokens(Tok); @@ -2251,11 +2287,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SkipUntil(tok::comma, true, true); else if (ThisDecl) Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(), - DS.getTypeSpecType() == DeclSpec::TST_auto); + DS.containsPlaceholderType()); } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) { // No initializer. - Actions.ActOnUninitializedDecl(ThisDecl, - DS.getTypeSpecType() == DeclSpec::TST_auto); + Actions.ActOnUninitializedDecl(ThisDecl, DS.containsPlaceholderType()); } if (ThisDecl) { @@ -2525,6 +2560,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, continue; } + if (Tok.is(tok::annot_pragma_openmp)) { + ParseOpenMPDeclarativeDirective(); + continue; + } + AccessSpecifier AS = getAccessSpecifierIfPresent(); if (AS != AS_none) { // Current token is a C++ access specifier. diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 7775909cf5..9521ffbc0e 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -691,8 +691,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = getExprAnnotation(Tok); ConsumeToken(); break; - + case tok::kw_decltype: + // Annotate the token and tail recurse. + if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + assert(Tok.isNot(tok::kw_decltype)); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant @@ -1188,10 +1194,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_union: case tok::kw___is_final: case tok::kw___has_trivial_constructor: + case tok::kw___has_trivial_move_constructor: case tok::kw___has_trivial_copy: case tok::kw___has_trivial_assign: + case tok::kw___has_trivial_move_assign: case tok::kw___has_trivial_destructor: case tok::kw___has_nothrow_assign: + case tok::kw___has_nothrow_move_assign: case tok::kw___has_nothrow_copy: case tok::kw___has_nothrow_constructor: case tok::kw___has_virtual_destructor: @@ -1405,8 +1414,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { CommaLocsTy CommaLocs; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteCall(getCurScope(), LHS.get(), - ArrayRef<Expr *>()); + Actions.CodeCompleteCall(getCurScope(), LHS.get(), None); cutOffParsing(); return ExprError(); } @@ -1958,12 +1966,16 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Tok.is(tok::kw___bridge_retained) || Tok.is(tok::kw___bridge_retain))); if (BridgeCast && !getLangOpts().ObjCAutoRefCount) { - StringRef BridgeCastName = Tok.getName(); - SourceLocation BridgeKeywordLoc = ConsumeToken(); - if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) - Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc) - << BridgeCastName - << FixItHint::CreateReplacement(BridgeKeywordLoc, ""); + if (Tok.isNot(tok::kw___bridge)) { + StringRef BridgeCastName = Tok.getName(); + SourceLocation BridgeKeywordLoc = ConsumeToken(); + if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) + Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc) + << BridgeCastName + << FixItHint::CreateReplacement(BridgeKeywordLoc, ""); + } + else + ConsumeToken(); // consume __bridge BridgeCast = false; } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index f72e68e2a1..f259d5f59b 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -168,19 +168,26 @@ void Parser::CheckForLParenAfterColonColon() { /// if we do end up determining that we are parsing a destructor name, /// the last component of the nested-name-specifier is not parsed as /// part of the scope specifier. - -/// member access expression, e.g., the \p T:: in \p p->T::m. +/// +/// \param IsTypename If \c true, this nested-name-specifier is known to be +/// part of a type name. This is used to improve error recovery. +/// +/// \param LastII When non-NULL, points to an IdentifierInfo* that will be +/// filled in with the leading identifier in the last component of the +/// nested-name-specifier, if any. /// /// \returns true if there was an error parsing a scope specifier bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext, bool *MayBePseudoDestructor, - bool IsTypename) { + bool IsTypename, + IdentifierInfo **LastII) { assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); if (Tok.is(tok::annot_cxxscope)) { + assert(!LastII && "want last identifier but have already annotated scope"); Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS); @@ -188,6 +195,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, return false; } + if (LastII) + *LastII = 0; + bool HasScopeSpecifier = false; if (Tok.is(tok::coloncolon)) { @@ -334,6 +344,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, return false; } + if (LastII) + *LastII = TemplateId->Name; + // Consume the template-id token. ConsumeToken(); @@ -405,6 +418,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, return false; } + if (LastII) + *LastII = &II; + // We have an identifier followed by a '::'. Lookup this name // as the name in a nested-name-specifier. SourceLocation IdLoc = ConsumeToken(); @@ -1439,7 +1455,9 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, if (!InitExpr.isInvalid()) Actions.AddInitializerToDecl(DeclOut, InitExpr.take(), !CopyInitialization, - DS.getTypeSpecType() == DeclSpec::TST_auto); + DS.containsPlaceholderType()); + else + Actions.ActOnInitializerError(DeclOut); // FIXME: Build a reference to this declaration? Convert it to bool? // (This is currently handled by Sema). @@ -2017,7 +2035,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // Parse the conversion-declarator, which is merely a sequence of // ptr-operators. - Declarator D(DS, Declarator::TypeNameContext); + Declarator D(DS, Declarator::ConversionIdContext); ParseDeclaratorInternal(D, /*DirectDeclParser=*/0); // Finish up the type. @@ -2495,11 +2513,15 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { switch(kind) { default: llvm_unreachable("Not a known unary type trait."); case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign; + case tok::kw___has_nothrow_move_assign: return UTT_HasNothrowMoveAssign; case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor; case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy; case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign; + case tok::kw___has_trivial_move_assign: return UTT_HasTrivialMoveAssign; case tok::kw___has_trivial_constructor: return UTT_HasTrivialDefaultConstructor; + case tok::kw___has_trivial_move_constructor: + return UTT_HasTrivialMoveConstructor; case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy; case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor; case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor; diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 3b967174bc..8311aa2207 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -412,7 +412,7 @@ ExprResult Parser::ParseBraceInitializer() { if (!getLangOpts().CPlusPlus) Diag(LBraceLoc, diag::ext_gnu_empty_initializer); // Match the '}'. - return Actions.ActOnInitList(LBraceLoc, MultiExprArg(), ConsumeBrace()); + return Actions.ActOnInitList(LBraceLoc, None, ConsumeBrace()); } bool InitExprsOk = true; diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index ddb6a707f5..4a572f1993 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -22,6 +22,18 @@ #include "llvm/ADT/StringExtras.h" using namespace clang; +/// Skips attributes after an Objective-C @ directive. Emits a diagnostic. +void Parser::MaybeSkipAttributes(tok::ObjCKeywordKind Kind) { + ParsedAttributes attrs(AttrFactory); + if (Tok.is(tok::kw___attribute)) { + if (Kind == tok::objc_interface || Kind == tok::objc_protocol) + Diag(Tok, diag::err_objc_postfix_attribute_hint) + << (Kind == tok::objc_protocol); + else + Diag(Tok, diag::err_objc_postfix_attribute); + ParseGNUAttributes(attrs); + } +} /// ParseObjCAtDirectives - Handle parts of the external-declaration production: /// external-declaration: [C99 6.9] @@ -93,6 +105,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { while (1) { + MaybeSkipAttributes(tok::objc_class); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::semi); @@ -179,6 +192,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, return 0; } + MaybeSkipAttributes(tok::objc_interface); + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing class or category name. return 0; @@ -1228,6 +1243,22 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { return Result; } +void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc, + BalancedDelimiterTracker &T, + SmallVectorImpl<Decl *> &AllIvarDecls, + bool RBraceMissing) { + if (!RBraceMissing) + T.consumeClose(); + + Actions.ActOnObjCContainerStartDefinition(interfaceDecl); + Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls); + Actions.ActOnObjCContainerFinishDefinition(); + // Call ActOnFields() even if we don't have any decls. This is useful + // for code rewriting tools that need to be aware of the empty list. + Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl, + AllIvarDecls, + T.getOpenLocation(), T.getCloseLocation(), 0); +} /// objc-class-instance-variables: /// '{' objc-instance-variable-decl-list[opt] '}' @@ -1260,7 +1291,6 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, BalancedDelimiterTracker T(*this, tok::l_brace); T.consumeOpen(); - // While we still have something to read, read the instance variables. while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // Each iteration of this loop reads one objc-instance-variable-decl. @@ -1288,6 +1318,17 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, visibility = Tok.getObjCKeywordID(); ConsumeToken(); continue; + + case tok::objc_end: + Diag(Tok, diag::err_objc_unexpected_atend); + Tok.setLocation(Tok.getLocation().getLocWithOffset(-1)); + Tok.setKind(tok::at); + Tok.setLength(1); + PP.EnterToken(Tok); + HelperActionsForIvarDeclarations(interfaceDecl, atLoc, + T, AllIvarDecls, true); + return; + default: Diag(Tok, diag::err_objc_illegal_visibility_spec); continue; @@ -1337,16 +1378,8 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, SkipUntil(tok::r_brace, true, true); } } - T.consumeClose(); - - Actions.ActOnObjCContainerStartDefinition(interfaceDecl); - Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls); - Actions.ActOnObjCContainerFinishDefinition(); - // Call ActOnFields() even if we don't have any decls. This is useful - // for code rewriting tools that need to be aware of the empty list. - Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl, - AllIvarDecls, - T.getOpenLocation(), T.getCloseLocation(), 0); + HelperActionsForIvarDeclarations(interfaceDecl, atLoc, + T, AllIvarDecls, false); return; } @@ -1379,6 +1412,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, return DeclGroupPtrTy(); } + MaybeSkipAttributes(tok::objc_protocol); + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing protocol name. return DeclGroupPtrTy(); @@ -1470,6 +1505,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { return DeclGroupPtrTy(); } + MaybeSkipAttributes(tok::objc_implementation); + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing class or category name. return DeclGroupPtrTy(); @@ -1528,6 +1565,13 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { if (Tok.is(tok::l_brace)) // we have ivars ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc); + else if (Tok.is(tok::less)) { // we have illegal '<' try to recover + Diag(Tok, diag::err_unexpected_protocol_qualifier); + // try to recover. + AttributeFactory attr; + DeclSpec DS(attr); + (void)ParseObjCProtocolQualifiers(DS); + } } assert(ObjCImpDecl); @@ -1638,7 +1682,7 @@ Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { /// Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { assert(Tok.isObjCAtKeyword(tok::objc_synthesize) && - "ParseObjCPropertyDynamic(): Expected '@synthesize'"); + "ParseObjCPropertySynthesize(): Expected '@synthesize'"); ConsumeToken(); // consume synthesize while (true) { @@ -2464,7 +2508,14 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, return ExprError(); } - ExprResult Res(ParseAssignmentExpression()); + ExprResult Expr; + if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + Expr = ParseBraceInitializer(); + } else + Expr = ParseAssignmentExpression(); + + ExprResult Res(Expr); if (Res.isInvalid()) { // We must manually skip to a ']', otherwise the expression skipper will // stop at the ']' when it skips to the ';'. We want it to skip beyond @@ -2710,7 +2761,9 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { if (Tok.is(tok::colon)) { ConsumeToken(); } else { - return ExprError(Diag(Tok, diag::err_expected_colon)); + Diag(Tok, diag::err_expected_colon); + SkipUntil(tok::r_brace); + return ExprError(); } ExprResult ValueExpr(ParseAssignmentExpression()); @@ -2878,7 +2931,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); assert((Tok.is(tok::l_brace) || Tok.is(tok::kw_try) || Tok.is(tok::colon)) && diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp new file mode 100644 index 0000000000..507a6b1bcd --- /dev/null +++ b/lib/Parse/ParseOpenMP.cpp @@ -0,0 +1,118 @@ +//===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This file implements parsing of all OpenMP directives and clauses. +/// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTConsumer.h" +#include "clang/Parse/Parser.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "RAIIObjectsForParser.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// OpenMP declarative directives. +//===----------------------------------------------------------------------===// + +/// \brief Parses OpenMP declarative directive +/// threadprivate-directive +/// annot_pragma_openmp threadprivate simple-variable-list +/// +Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { + assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + + SourceLocation Loc = ConsumeToken(); + SmallVector<DeclarationNameInfo, 5> Identifiers; + OpenMPDirectiveKind Kind = Tok.isAnnotation() ? + OMPD_unknown : + getOpenMPDirectiveKind(PP.getSpelling(Tok)); + switch(Kind) { + case OMPD_threadprivate: + ConsumeToken(); + if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers)) { + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_threadprivate); + SkipUntil(tok::annot_pragma_openmp_end, false, true); + } + ConsumeToken(); + return Actions.ActOnOpenMPThreadprivateDirective(Loc, + getCurScope(), + Identifiers); + } + break; + case OMPD_unknown: + Diag(Tok, diag::err_omp_unknown_directive); + break; + default: + Diag(Tok, diag::err_omp_unexpected_directive) + << getOpenMPDirectiveName(Kind); + break; + } + SkipUntil(tok::annot_pragma_openmp_end, false); + return DeclGroupPtrTy(); +} + +/// \brief Parses list of simple variables for '#pragma omp threadprivate' +/// directive +/// simple-variable-list: +/// ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end +/// +bool Parser::ParseOpenMPSimpleVarList( + OpenMPDirectiveKind Kind, + SmallVectorImpl<DeclarationNameInfo> &IdList) { + // Parse '('. + bool IsCorrect = true; + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPDirectiveName(Kind))) { + SkipUntil(tok::annot_pragma_openmp_end, false, true); + return false; + } + + // Read tokens while ')' or annot_pragma_openmp_end is not found. + do { + CXXScopeSpec SS; + SourceLocation TemplateKWLoc; + UnqualifiedId Name; + // Read var name. + Token PrevTok = Tok; + + if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), + TemplateKWLoc, Name)) { + IsCorrect = false; + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + false, true); + } + else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + IsCorrect = false; + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + false, true); + Diag(PrevTok.getLocation(), diag::err_expected_unqualified_id) + << getLangOpts().CPlusPlus + << SourceRange(PrevTok.getLocation(), PrevTokLocation); + } else { + IdList.push_back(Actions.GetNameFromUnqualifiedId(Name)); + } + // Consume ','. + if (Tok.is(tok::comma)) { + ConsumeToken(); + } + } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)); + + if (IsCorrect || Tok.is(tok::r_paren)) { + IsCorrect = !T.consumeClose() && IsCorrect; + } + + return !IsCorrect && IdList.empty(); +} diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index 641654b221..3d1249aa68 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -15,6 +15,8 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" +#include "clang/Sema/Scope.h" +#include "llvm/ADT/StringSwitch.h" using namespace clang; /// \brief Handle the annotation token produced for #pragma unused(...) @@ -122,6 +124,33 @@ void Parser::HandlePragmaFPContract() { ConsumeToken(); // The annotation token. } +StmtResult Parser::HandlePragmaCaptured() +{ + assert(Tok.is(tok::annot_pragma_captured)); + ConsumeToken(); + + if (Tok.isNot(tok::l_brace)) { + PP.Diag(Tok, diag::err_expected_lbrace); + return StmtError(); + } + + SourceLocation Loc = Tok.getLocation(); + + ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope); + Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default, + /*NumParams=*/1); + + StmtResult R = ParseCompoundStatement(); + CapturedRegionScope.Exit(); + + if (R.isInvalid()) { + Actions.ActOnCapturedRegionError(); + return StmtError(); + } + + return Actions.ActOnCapturedRegionEnd(R.get()); +} + namespace { typedef llvm::PointerIntPair<IdentifierInfo *, 1, bool> OpenCLExtData; } @@ -151,6 +180,8 @@ void Parser::HandlePragmaOpenCLExtension() { } } + + // #pragma GCC visibility comes in two variants: // 'push' '(' [visibility] ')' // 'pop' @@ -718,3 +749,112 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, /*OwnsTokens=*/false); } +/// \brief Handle '#pragma omp ...' when OpenMP is disabled. +/// +void +PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &FirstTok) { + if (PP.getDiagnostics().getDiagnosticLevel(diag::warn_pragma_omp_ignored, + FirstTok.getLocation()) != + DiagnosticsEngine::Ignored) { + PP.Diag(FirstTok, diag::warn_pragma_omp_ignored); + PP.getDiagnostics().setDiagnosticMapping(diag::warn_pragma_omp_ignored, + diag::MAP_IGNORE, + SourceLocation()); + } + PP.DiscardUntilEndOfDirective(); +} + +/// \brief Handle '#pragma omp ...' when OpenMP is enabled. +/// +void +PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &FirstTok) { + SmallVector<Token, 16> Pragma; + Token Tok; + Tok.startToken(); + Tok.setKind(tok::annot_pragma_openmp); + Tok.setLocation(FirstTok.getLocation()); + + while (Tok.isNot(tok::eod)) { + Pragma.push_back(Tok); + PP.Lex(Tok); + } + SourceLocation EodLoc = Tok.getLocation(); + Tok.startToken(); + Tok.setKind(tok::annot_pragma_openmp_end); + Tok.setLocation(EodLoc); + Pragma.push_back(Tok); + + Token *Toks = new Token[Pragma.size()]; + std::copy(Pragma.begin(), Pragma.end(), Toks); + PP.EnterTokenStream(Toks, Pragma.size(), + /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true); +} + +/// \brief Handle the microsoft \#pragma comment extension. +/// +/// The syntax is: +/// \code +/// #pragma comment(linker, "foo") +/// \endcode +/// 'linker' is one of five identifiers: compiler, exestr, lib, linker, user. +/// "foo" is a string, which is fully macro expanded, and permits string +/// concatenation, embedded escape characters etc. See MSDN for more details. +void PragmaCommentHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &Tok) { + SourceLocation CommentLoc = Tok.getLocation(); + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(CommentLoc, diag::err_pragma_comment_malformed); + return; + } + + // Read the identifier. + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(CommentLoc, diag::err_pragma_comment_malformed); + return; + } + + // Verify that this is one of the 5 whitelisted options. + // FIXME: warn that 'exestr' is deprecated. + const IdentifierInfo *II = Tok.getIdentifierInfo(); + if (!II->isStr("compiler") && !II->isStr("exestr") && !II->isStr("lib") && + !II->isStr("linker") && !II->isStr("user")) { + PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); + return; + } + + // Read the optional string if present. + PP.Lex(Tok); + std::string ArgumentString; + if (Tok.is(tok::comma) && !PP.LexStringLiteral(Tok, ArgumentString, + "pragma comment", + /*MacroExpansion=*/true)) + return; + + // FIXME: If the kind is "compiler" warn if the string is present (it is + // ignored). + // FIXME: 'lib' requires a comment string. + // FIXME: 'linker' requires a comment string, and has a specific list of + // things that are allowable. + + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); + return; + } + PP.Lex(Tok); // eat the r_paren. + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); + return; + } + + // If the pragma is lexically sound, notify any interested PPCallbacks. + if (PP.getPPCallbacks()) + PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString); +} diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h index b9a2a251fc..d9560f3181 100644 --- a/lib/Parse/ParsePragma.h +++ b/lib/Parse/ParsePragma.h @@ -98,7 +98,28 @@ public: virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); }; - + +class PragmaNoOpenMPHandler : public PragmaHandler { +public: + PragmaNoOpenMPHandler() : PragmaHandler("omp") { } + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + +class PragmaOpenMPHandler : public PragmaHandler { +public: + PragmaOpenMPHandler() : PragmaHandler("omp") { } + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + +/// PragmaCommentHandler - "\#pragma comment ...". +class PragmaCommentHandler : public PragmaHandler { +public: + PragmaCommentHandler() : PragmaHandler("comment") {} + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; } // end namespace clang diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 71a7b2c9f9..43b6965d31 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -14,13 +14,26 @@ #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" +#include "clang/AST/ASTContext.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" #include "clang/Sema/TypoCorrection.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/ADT/SmallString.h" using namespace clang; @@ -288,6 +301,14 @@ Retry: ProhibitAttributes(Attrs); HandlePragmaOpenCLExtension(); return StmtEmpty(); + + case tok::annot_pragma_captured: + return HandlePragmaCaptured(); + + case tok::annot_pragma_openmp: + SourceLocation DeclStart = Tok.getLocation(); + DeclGroupPtrTy Res = ParseOpenMPDeclarativeDirective(); + return Actions.ActOnDeclStmt(Res, DeclStart, Tok.getLocation()); } // If we reached this code, the statement must end in a semicolon. @@ -319,7 +340,7 @@ StmtResult Parser::ParseExprStatement() { SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); if (Tok.is(tok::semi)) ConsumeToken(); - return StmtError(); + return Actions.ActOnExprStmtError(); } if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() && @@ -1655,6 +1676,281 @@ StmtResult Parser::ParseReturnStatement() { return Actions.ActOnReturnStmt(ReturnLoc, R.take()); } +namespace { + class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback { + Parser &TheParser; + SourceLocation AsmLoc; + StringRef AsmString; + + /// The tokens we streamed into AsmString and handed off to MC. + ArrayRef<Token> AsmToks; + + /// The offset of each token in AsmToks within AsmString. + ArrayRef<unsigned> AsmTokOffsets; + + public: + ClangAsmParserCallback(Parser &P, SourceLocation Loc, + StringRef AsmString, + ArrayRef<Token> Toks, + ArrayRef<unsigned> Offsets) + : TheParser(P), AsmLoc(Loc), AsmString(AsmString), + AsmToks(Toks), AsmTokOffsets(Offsets) { + assert(AsmToks.size() == AsmTokOffsets.size()); + } + + void *LookupInlineAsmIdentifier(StringRef &LineBuf, + InlineAsmIdentifierInfo &Info, + bool IsUnevaluatedContext) { + // Collect the desired tokens. + SmallVector<Token, 16> LineToks; + const Token *FirstOrigToken = 0; + findTokensForString(LineBuf, LineToks, FirstOrigToken); + + unsigned NumConsumedToks; + ExprResult Result = + TheParser.ParseMSAsmIdentifier(LineToks, NumConsumedToks, &Info, + IsUnevaluatedContext); + + // If we consumed the entire line, tell MC that. + // Also do this if we consumed nothing as a way of reporting failure. + if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) { + // By not modifying LineBuf, we're implicitly consuming it all. + + // Otherwise, consume up to the original tokens. + } else { + assert(FirstOrigToken && "not using original tokens?"); + + // Since we're using original tokens, apply that offset. + assert(FirstOrigToken[NumConsumedToks].getLocation() + == LineToks[NumConsumedToks].getLocation()); + unsigned FirstIndex = FirstOrigToken - AsmToks.begin(); + unsigned LastIndex = FirstIndex + NumConsumedToks - 1; + + // The total length we've consumed is the relative offset + // of the last token we consumed plus its length. + unsigned TotalOffset = (AsmTokOffsets[LastIndex] + + AsmToks[LastIndex].getLength() + - AsmTokOffsets[FirstIndex]); + LineBuf = LineBuf.substr(0, TotalOffset); + } + + // Initialize the "decl" with the lookup result. + Info.OpDecl = static_cast<void*>(Result.take()); + return Info.OpDecl; + } + + bool LookupInlineAsmField(StringRef Base, StringRef Member, + unsigned &Offset) { + return TheParser.getActions().LookupInlineAsmField(Base, Member, + Offset, AsmLoc); + } + + static void DiagHandlerCallback(const llvm::SMDiagnostic &D, + void *Context) { + ((ClangAsmParserCallback*) Context)->handleDiagnostic(D); + } + + private: + /// Collect the appropriate tokens for the given string. + void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks, + const Token *&FirstOrigToken) const { + // For now, assert that the string we're working with is a substring + // of what we gave to MC. This lets us use the original tokens. + assert(!std::less<const char*>()(Str.begin(), AsmString.begin()) && + !std::less<const char*>()(AsmString.end(), Str.end())); + + // Try to find a token whose offset matches the first token. + unsigned FirstCharOffset = Str.begin() - AsmString.begin(); + const unsigned *FirstTokOffset + = std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), + FirstCharOffset); + + // For now, assert that the start of the string exactly + // corresponds to the start of a token. + assert(*FirstTokOffset == FirstCharOffset); + + // Use all the original tokens for this line. (We assume the + // end of the line corresponds cleanly to a token break.) + unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin(); + FirstOrigToken = &AsmToks[FirstTokIndex]; + unsigned LastCharOffset = Str.end() - AsmString.begin(); + for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) { + if (AsmTokOffsets[i] >= LastCharOffset) break; + TempToks.push_back(AsmToks[i]); + } + } + + void handleDiagnostic(const llvm::SMDiagnostic &D) { + // Compute an offset into the inline asm buffer. + // FIXME: This isn't right if .macro is involved (but hopefully, no + // real-world code does that). + const llvm::SourceMgr &LSM = *D.getSourceMgr(); + const llvm::MemoryBuffer *LBuf = + LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); + unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); + + // Figure out which token that offset points into. + const unsigned *TokOffsetPtr = + std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset); + unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin(); + unsigned TokOffset = *TokOffsetPtr; + + // If we come up with an answer which seems sane, use it; otherwise, + // just point at the __asm keyword. + // FIXME: Assert the answer is sane once we handle .macro correctly. + SourceLocation Loc = AsmLoc; + if (TokIndex < AsmToks.size()) { + const Token &Tok = AsmToks[TokIndex]; + Loc = Tok.getLocation(); + Loc = Loc.getLocWithOffset(Offset - TokOffset); + } + TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) + << D.getMessage(); + } + }; +} + +/// Parse an identifier in an MS-style inline assembly block. +/// +/// \param CastInfo - a void* so that we don't have to teach Parser.h +/// about the actual type. +ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, + unsigned &NumLineToksConsumed, + void *CastInfo, + bool IsUnevaluatedContext) { + llvm::InlineAsmIdentifierInfo &Info = + *(llvm::InlineAsmIdentifierInfo *) CastInfo; + + // Push a fake token on the end so that we don't overrun the token + // stream. We use ';' because it expression-parsing should never + // overrun it. + const tok::TokenKind EndOfStream = tok::semi; + Token EndOfStreamTok; + EndOfStreamTok.startToken(); + EndOfStreamTok.setKind(EndOfStream); + LineToks.push_back(EndOfStreamTok); + + // Also copy the current token over. + LineToks.push_back(Tok); + + PP.EnterTokenStream(LineToks.begin(), + LineToks.size(), + /*disable macros*/ true, + /*owns tokens*/ false); + + // Clear the current token and advance to the first token in LineToks. + ConsumeAnyToken(); + + // Parse an optional scope-specifier if we're in C++. + CXXScopeSpec SS; + if (getLangOpts().CPlusPlus) { + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + } + + // Require an identifier here. + SourceLocation TemplateKWLoc; + UnqualifiedId Id; + bool Invalid = ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, + /*ObjectType=*/ ParsedType(), + TemplateKWLoc, + Id); + + // If we've run into the poison token we inserted before, or there + // was a parsing error, then claim the entire line. + if (Invalid || Tok.is(EndOfStream)) { + NumLineToksConsumed = LineToks.size() - 2; + + // Otherwise, claim up to the start of the next token. + } else { + // Figure out how many tokens we are into LineToks. + unsigned LineIndex = 0; + while (LineToks[LineIndex].getLocation() != Tok.getLocation()) { + LineIndex++; + assert(LineIndex < LineToks.size() - 2); // we added two extra tokens + } + + NumLineToksConsumed = LineIndex; + } + + // Finally, restore the old parsing state by consuming all the + // tokens we staged before, implicitly killing off the + // token-lexer we pushed. + for (unsigned n = LineToks.size() - 2 - NumLineToksConsumed; n != 0; --n) { + ConsumeAnyToken(); + } + ConsumeToken(EndOfStream); + + // Leave LineToks in its original state. + LineToks.pop_back(); + LineToks.pop_back(); + + // Perform the lookup. + return Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info, + IsUnevaluatedContext); +} + +/// Turn a sequence of our tokens back into a string that we can hand +/// to the MC asm parser. +static bool buildMSAsmString(Preprocessor &PP, + SourceLocation AsmLoc, + ArrayRef<Token> AsmToks, + SmallVectorImpl<unsigned> &TokOffsets, + SmallString<512> &Asm) { + assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); + + // Is this the start of a new assembly statement? + bool isNewStatement = true; + + for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { + const Token &Tok = AsmToks[i]; + + // Start each new statement with a newline and a tab. + if (!isNewStatement && + (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) { + Asm += "\n\t"; + isNewStatement = true; + } + + // Preserve the existence of leading whitespace except at the + // start of a statement. + if (!isNewStatement && Tok.hasLeadingSpace()) + Asm += ' '; + + // Remember the offset of this token. + TokOffsets.push_back(Asm.size()); + + // Don't actually write '__asm' into the assembly stream. + if (Tok.is(tok::kw_asm)) { + // Complain about __asm at the end of the stream. + if (i + 1 == e) { + PP.Diag(AsmLoc, diag::err_asm_empty); + return true; + } + + continue; + } + + // Append the spelling of the token. + SmallString<32> SpellingBuffer; + bool SpellingInvalid = false; + Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid); + assert(!SpellingInvalid && "spelling was invalid after correct parse?"); + + // We are no longer at the start of a statement. + isNewStatement = false; + } + + // Ensure that the buffer is null-terminated. + Asm.push_back('\0'); + Asm.pop_back(); + + assert(TokOffsets.size() == AsmToks.size()); + return false; +} + /// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled, /// this routine is called to collect the tokens for an MS asm statement. /// @@ -1763,9 +2059,114 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { return StmtError(); } + // Okay, prepare to use MC to parse the assembly. + SmallVector<StringRef, 4> ConstraintRefs; + SmallVector<Expr*, 4> Exprs; + SmallVector<StringRef, 4> ClobberRefs; + + // We need an actual supported target. + llvm::Triple TheTriple = Actions.Context.getTargetInfo().getTriple(); + llvm::Triple::ArchType ArchTy = TheTriple.getArch(); + bool UnsupportedArch = (ArchTy != llvm::Triple::x86 && + ArchTy != llvm::Triple::x86_64); + if (UnsupportedArch) + Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName(); + + // If we don't support assembly, or the assembly is empty, we don't + // need to instantiate the AsmParser, etc. + if (UnsupportedArch || AsmToks.empty()) { + return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, StringRef(), + /*NumOutputs*/ 0, /*NumInputs*/ 0, + ConstraintRefs, ClobberRefs, Exprs, EndLoc); + } + + // Expand the tokens into a string buffer. + SmallString<512> AsmString; + SmallVector<unsigned, 8> TokOffsets; + if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString)) + return StmtError(); + + // Find the target and create the target specific parser. + std::string Error; + const std::string &TT = TheTriple.getTriple(); + const llvm::Target *TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error); + + OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT)); + OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); + OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); + OwningPtr<llvm::MCSubtargetInfo> + STI(TheTarget->createMCSubtargetInfo(TT, "", "")); + + llvm::SourceMgr TempSrcMgr; + llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &TempSrcMgr); + llvm::MemoryBuffer *Buffer = + llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>"); + + // Tell SrcMgr about this buffer, which is what the parser will pick up. + TempSrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); + + OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx)); + OwningPtr<llvm::MCAsmParser> + Parser(createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI)); + OwningPtr<llvm::MCTargetAsmParser> + TargetParser(TheTarget->createMCAsmParser(*STI, *Parser)); + + // Get the instruction descriptor. + const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); + llvm::MCInstPrinter *IP = + TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI); + + // Change to the Intel dialect. + Parser->setAssemblerDialect(1); + Parser->setTargetParser(*TargetParser.get()); + Parser->setParsingInlineAsm(true); + TargetParser->setParsingInlineAsm(true); + + ClangAsmParserCallback Callback(*this, AsmLoc, AsmString, + AsmToks, TokOffsets); + TargetParser->setSemaCallback(&Callback); + TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback, + &Callback); + + unsigned NumOutputs; + unsigned NumInputs; + std::string AsmStringIR; + SmallVector<std::pair<void *, bool>, 4> OpExprs; + SmallVector<std::string, 4> Constraints; + SmallVector<std::string, 4> Clobbers; + if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, + NumOutputs, NumInputs, OpExprs, Constraints, + Clobbers, MII, IP, Callback)) + return StmtError(); + + // Build the vector of clobber StringRefs. + unsigned NumClobbers = Clobbers.size(); + ClobberRefs.resize(NumClobbers); + for (unsigned i = 0; i != NumClobbers; ++i) + ClobberRefs[i] = StringRef(Clobbers[i]); + + // Recast the void pointers and build the vector of constraint StringRefs. + unsigned NumExprs = NumOutputs + NumInputs; + ConstraintRefs.resize(NumExprs); + Exprs.resize(NumExprs); + for (unsigned i = 0, e = NumExprs; i != e; ++i) { + Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first); + if (!OpExpr) + return StmtError(); + + // Need address of variable. + if (OpExprs[i].second) + OpExpr = Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr) + .take(); + + ConstraintRefs[i] = StringRef(Constraints[i]); + Exprs[i] = OpExpr; + } + // FIXME: We should be passing source locations for better diagnostics. - return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, - llvm::makeArrayRef(AsmToks), EndLoc); + return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmStringIR, + NumOutputs, NumInputs, + ConstraintRefs, ClobberRefs, Exprs, EndLoc); } /// ParseAsmStatement - Parse a GNU extended asm statement. @@ -1805,6 +2206,9 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { Diag(Loc, diag::w_asm_qualifier_ignored) << "const"; if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict"; + // FIXME: Once GCC supports _Atomic, check whether it permits it here. + if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) + Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic"; // Remember if this was a volatile asm. bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 32a78a73a8..84b7df7295 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -39,28 +39,7 @@ Parser::ParseDeclarationStartingWithTemplate(unsigned Context, AccessAttrs); } -/// \brief RAII class that manages the template parameter depth. -namespace { - class TemplateParameterDepthCounter { - unsigned &Depth; - unsigned AddedLevels; - - public: - explicit TemplateParameterDepthCounter(unsigned &Depth) - : Depth(Depth), AddedLevels(0) { } - - ~TemplateParameterDepthCounter() { - Depth -= AddedLevels; - } - void operator++() { - ++Depth; - ++AddedLevels; - } - - operator unsigned() const { return Depth; } - }; -} /// \brief Parse a template declaration or an explicit specialization. /// @@ -117,7 +96,8 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, bool isSpecialization = true; bool LastParamListWasEmpty = false; TemplateParameterLists ParamLists; - TemplateParameterDepthCounter Depth(TemplateParameterDepth); + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + do { // Consume the 'export', if any. SourceLocation ExportLoc; @@ -137,8 +117,8 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // Parse the '<' template-parameter-list '>' SourceLocation LAngleLoc, RAngleLoc; SmallVector<Decl*, 4> TemplateParams; - if (ParseTemplateParameters(Depth, TemplateParams, LAngleLoc, - RAngleLoc)) { + if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(), + TemplateParams, LAngleLoc, RAngleLoc)) { // Skip until the semi-colon or a }. SkipUntil(tok::r_brace, true, true); if (Tok.is(tok::semi)) @@ -147,14 +127,15 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, } ParamLists.push_back( - Actions.ActOnTemplateParameterList(Depth, ExportLoc, + Actions.ActOnTemplateParameterList(CurTemplateDepthTracker.getDepth(), + ExportLoc, TemplateLoc, LAngleLoc, TemplateParams.data(), TemplateParams.size(), RAngleLoc)); if (!TemplateParams.empty()) { isSpecialization = false; - ++Depth; + ++CurTemplateDepthTracker; } else { LastParamListWasEmpty = true; } @@ -214,7 +195,11 @@ Parser::ParseSingleDeclarationAfterTemplate( if (Tok.is(tok::semi)) { ProhibitAttributes(prefixAttrs); DeclEnd = ConsumeToken(); - Decl *Decl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); + Decl *Decl = Actions.ParsedFreeStandingDeclSpec( + getCurScope(), AS, DS, + TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams + : MultiTemplateParamsArg(), + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation); DS.complete(Decl); return Decl; } @@ -1164,6 +1149,9 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) { /// template-argument-list ',' template-argument bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { + // Template argument lists are constant-evaluation contexts. + EnterExpressionEvaluationContext EvalContext(Actions,Sema::ConstantEvaluated); + while (true) { ParsedTemplateArgument Arg = ParseTemplateArgument(); if (Tok.is(tok::ellipsis)) { @@ -1196,7 +1184,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { /// explicit-instantiation: /// 'extern' [opt] 'template' declaration /// -/// Note that the 'extern' is a GNU extension and C++0x feature. +/// Note that the 'extern' is a GNU extension and C++11 feature. Decl *Parser::ParseExplicitInstantiation(unsigned Context, SourceLocation ExternLoc, SourceLocation TemplateLoc, @@ -1245,53 +1233,56 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { return; // Get the FunctionDecl. - FunctionDecl *FD = 0; - if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(LMT.D)) - FD = FunTmpl->getTemplatedDecl(); - else - FD = cast<FunctionDecl>(LMT.D); + FunctionTemplateDecl *FunTmplD = dyn_cast<FunctionTemplateDecl>(LMT.D); + FunctionDecl *FunD = + FunTmplD ? FunTmplD->getTemplatedDecl() : cast<FunctionDecl>(LMT.D); + // Track template parameter depth. + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); // To restore the context after late parsing. Sema::ContextRAII GlobalSavedContext(Actions, Actions.CurContext); SmallVector<ParseScope*, 4> TemplateParamScopeStack; - DeclaratorDecl* Declarator = dyn_cast<DeclaratorDecl>(FD); - if (Declarator && Declarator->getNumTemplateParameterLists() != 0) { - TemplateParamScopeStack.push_back(new ParseScope(this, Scope::TemplateParamScope)); - Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator); - Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); - } else { - // Get the list of DeclContext to reenter. - SmallVector<DeclContext*, 4> DeclContextToReenter; - DeclContext *DD = FD->getLexicalParent(); - while (DD && !DD->isTranslationUnit()) { - DeclContextToReenter.push_back(DD); - DD = DD->getLexicalParent(); - } - // Reenter template scopes from outmost to innermost. - SmallVector<DeclContext*, 4>::reverse_iterator II = - DeclContextToReenter.rbegin(); - for (; II != DeclContextToReenter.rend(); ++II) { - if (ClassTemplatePartialSpecializationDecl* MD = - dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(*II)) { - TemplateParamScopeStack.push_back(new ParseScope(this, - Scope::TemplateParamScope)); - Actions.ActOnReenterTemplateScope(getCurScope(), MD); - } else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(*II)) { - TemplateParamScopeStack.push_back(new ParseScope(this, - Scope::TemplateParamScope, - MD->getDescribedClassTemplate() != 0 )); - Actions.ActOnReenterTemplateScope(getCurScope(), - MD->getDescribedClassTemplate()); - } - TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope)); - Actions.PushDeclContext(Actions.getCurScope(), *II); + // Get the list of DeclContexts to reenter. + SmallVector<DeclContext*, 4> DeclContextsToReenter; + DeclContext *DD = FunD->getLexicalParent(); + while (DD && !DD->isTranslationUnit()) { + DeclContextsToReenter.push_back(DD); + DD = DD->getLexicalParent(); + } + + // Reenter template scopes from outermost to innermost. + SmallVector<DeclContext*, 4>::reverse_iterator II = + DeclContextsToReenter.rbegin(); + for (; II != DeclContextsToReenter.rend(); ++II) { + if (ClassTemplatePartialSpecializationDecl *MD = + dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(*II)) { + TemplateParamScopeStack.push_back( + new ParseScope(this, Scope::TemplateParamScope)); + Actions.ActOnReenterTemplateScope(getCurScope(), MD); + ++CurTemplateDepthTracker; + } else if (CXXRecordDecl *MD = dyn_cast_or_null<CXXRecordDecl>(*II)) { + bool ManageScope = MD->getDescribedClassTemplate() != 0; + TemplateParamScopeStack.push_back( + new ParseScope(this, Scope::TemplateParamScope, ManageScope)); + Actions.ActOnReenterTemplateScope(getCurScope(), + MD->getDescribedClassTemplate()); + ++CurTemplateDepthTracker; } - TemplateParamScopeStack.push_back(new ParseScope(this, - Scope::TemplateParamScope)); - Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); + TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope)); + Actions.PushDeclContext(Actions.getCurScope(), *II); } + TemplateParamScopeStack.push_back( + new ParseScope(this, Scope::TemplateParamScope)); + + DeclaratorDecl *Declarator = dyn_cast<DeclaratorDecl>(FunD); + if (Declarator && Declarator->getNumTemplateParameterLists() != 0) { + Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator); + ++CurTemplateDepthTracker; + } + Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); + ++CurTemplateDepthTracker; assert(!LMT.Toks.empty() && "Empty body!"); @@ -1301,7 +1292,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { PP.EnterTokenStream(LMT.Toks.data(), LMT.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && "Inline method not starting with '{', ':' or 'try'"); @@ -1310,15 +1301,9 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); // Recreate the containing function DeclContext. - Sema::ContextRAII FunctionSavedContext(Actions, Actions.getContainingDC(FD)); - - if (FunctionTemplateDecl *FunctionTemplate - = dyn_cast_or_null<FunctionTemplateDecl>(LMT.D)) - Actions.ActOnStartOfFunctionDef(getCurScope(), - FunctionTemplate->getTemplatedDecl()); - if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(LMT.D)) - Actions.ActOnStartOfFunctionDef(getCurScope(), Function); + Sema::ContextRAII FunctionSavedContext(Actions, Actions.getContainingDC(FunD)); + Actions.ActOnStartOfFunctionDef(getCurScope(), FunD); if (Tok.is(tok::kw_try)) { ParseFunctionTryBlock(LMT.D, FnScope); @@ -1329,8 +1314,12 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { Actions.ActOnDefaultCtorInitializers(LMT.D); if (Tok.is(tok::l_brace)) { + assert((!FunTmplD || FunTmplD->getTemplateParameters()->getDepth() < + TemplateParameterDepth) && + "TemplateParameterDepth should be greater than the depth of " + "current template being instantiated!"); ParseFunctionStatementBody(LMT.D, FnScope); - Actions.MarkAsLateParsedTemplate(FD, false); + Actions.MarkAsLateParsedTemplate(FunD, false); } else Actions.ActOnFinishFunctionBody(LMT.D, 0); } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index b3cf983bbc..dff3b64c5b 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -184,6 +184,9 @@ Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { return TPResult::Ambiguous(); } +/// Tentatively parse an init-declarator-list in order to disambiguate it from +/// an expression. +/// /// init-declarator-list: /// init-declarator /// init-declarator-list ',' init-declarator @@ -192,14 +195,21 @@ Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { /// declarator initializer[opt] /// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt] /// -/// initializer: -/// '=' initializer-clause -/// '(' expression-list ')' +/// initializer: +/// brace-or-equal-initializer +/// '(' expression-list ')' +/// +/// brace-or-equal-initializer: +/// '=' initializer-clause +/// [C++11] braced-init-list /// -/// initializer-clause: -/// assignment-expression -/// '{' initializer-list ','[opt] '}' -/// '{' '}' +/// initializer-clause: +/// assignment-expression +/// braced-init-list +/// +/// braced-init-list: +/// '{' initializer-list ','[opt] '}' +/// '{' '}' /// Parser::TPResult Parser::TryParseInitDeclaratorList() { while (1) { @@ -218,6 +228,10 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() { ConsumeParen(); if (!SkipUntil(tok::r_paren)) return TPResult::Error(); + } else if (Tok.is(tok::l_brace)) { + // A left-brace here is sufficient to disambiguate the parse; an + // expression can never be followed directly by a braced-init-list. + return TPResult::True(); } else if (Tok.is(tok::equal) || isTokIdentifier_in()) { // MSVC and g++ won't examine the rest of declarators if '=' is // encountered; they just conclude that we have a declaration. @@ -823,11 +837,12 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw___underlying_type: - case tok::kw_thread_local: case tok::kw__Decimal32: case tok::kw__Decimal64: case tok::kw__Decimal128: case tok::kw___thread: + case tok::kw_thread_local: + case tok::kw__Thread_local: case tok::kw_typeof: case tok::kw___cdecl: case tok::kw___stdcall: @@ -879,7 +894,7 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) { /// function-specifier /// 'friend' /// 'typedef' -/// [C++0x] 'constexpr' +/// [C++11] 'constexpr' /// [GNU] attributes declaration-specifiers[opt] /// /// storage-class-specifier: @@ -889,6 +904,8 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) { /// 'mutable' /// 'auto' /// [GNU] '__thread' +/// [C++11] 'thread_local' +/// [C11] '_Thread_local' /// /// function-specifier: /// 'inline' @@ -923,8 +940,9 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) { /// 'void' /// [GNU] typeof-specifier /// [GNU] '_Complex' -/// [C++0x] 'auto' [TODO] -/// [C++0x] 'decltype' ( expression ) +/// [C++11] 'auto' +/// [C++11] 'decltype' ( expression ) +/// [C++1y] 'decltype' ( 'auto' ) /// /// type-name: /// class-name @@ -985,6 +1003,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // to types and identifiers, in order to try to recover from errors. CorrectionCandidateCallback TypoCorrection; TypoCorrection.WantRemainingKeywords = false; + TypoCorrection.WantTypeSpecifiers = Next.isNot(tok::arrow); switch (TryAnnotateName(false /* no nested name specifier */, &TypoCorrection)) { case ANK_Error: @@ -1058,6 +1077,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw_mutable: case tok::kw_auto: case tok::kw___thread: + case tok::kw_thread_local: + case tok::kw__Thread_local: // function-specifier case tok::kw_inline: case tok::kw_virtual: diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 24849edd63..455139b881 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -96,6 +96,16 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) PP.AddPragmaHandler("OPENCL", FPContractHandler.get()); } + if (getLangOpts().OpenMP) + OpenMPHandler.reset(new PragmaOpenMPHandler()); + else + OpenMPHandler.reset(new PragmaNoOpenMPHandler()); + PP.AddPragmaHandler(OpenMPHandler.get()); + + if (getLangOpts().MicrosoftExt) { + MSCommentHandler.reset(new PragmaCommentHandler()); + PP.AddPragmaHandler(MSCommentHandler.get()); + } CommentSemaHandler.reset(new ActionCommentHandler(actions)); PP.addCommentHandler(CommentSemaHandler.get()); @@ -428,6 +438,13 @@ Parser::~Parser() { OpenCLExtensionHandler.reset(); PP.RemovePragmaHandler("OPENCL", FPContractHandler.get()); } + PP.RemovePragmaHandler(OpenMPHandler.get()); + OpenMPHandler.reset(); + + if (getLangOpts().MicrosoftExt) { + PP.RemovePragmaHandler(MSCommentHandler.get()); + MSCommentHandler.reset(); + } PP.RemovePragmaHandler("STDC", FPContractHandler.get()); FPContractHandler.reset(); @@ -624,6 +641,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::annot_pragma_opencl_extension: HandlePragmaOpenCLExtension(); return DeclGroupPtrTy(); + case tok::annot_pragma_openmp: + ParseOpenMPDeclarativeDirective(); + return DeclGroupPtrTy(); case tok::semi: // Either a C++11 empty-declaration or attribute-declaration. SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(), @@ -1131,8 +1151,8 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { diag::err_invalid_storage_class_in_func_decl); DS.ClearStorageClassSpecs(); } - if (DS.isThreadSpecified()) { - Diag(DS.getThreadSpecLoc(), + if (DS.getThreadStorageClassSpec() != DeclSpec::TSCS_unspecified) { + Diag(DS.getThreadStorageClassSpecLoc(), diag::err_invalid_storage_class_in_func_decl); DS.ClearStorageClassSpecs(); } diff --git a/lib/Rewrite/Frontend/FixItRewriter.cpp b/lib/Rewrite/Frontend/FixItRewriter.cpp index a3bbdcf6eb..166c607d02 100644 --- a/lib/Rewrite/Frontend/FixItRewriter.cpp +++ b/lib/Rewrite/Frontend/FixItRewriter.cpp @@ -197,9 +197,4 @@ void FixItRewriter::Diag(SourceLocation Loc, unsigned DiagID) { Diags.setClient(this); } -DiagnosticConsumer *FixItRewriter::clone(DiagnosticsEngine &Diags) const { - return new FixItRewriter(Diags, Diags.getSourceManager(), - Rewrite.getLangOpts(), FixItOpts); -} - FixItOptions::~FixItOptions() {} diff --git a/lib/Rewrite/Frontend/InclusionRewriter.cpp b/lib/Rewrite/Frontend/InclusionRewriter.cpp index d95fb073b1..878be84224 100644 --- a/lib/Rewrite/Frontend/InclusionRewriter.cpp +++ b/lib/Rewrite/Frontend/InclusionRewriter.cpp @@ -15,7 +15,9 @@ #include "clang/Rewrite/Frontend/Rewriters.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/PreprocessorOutputOptions.h" +#include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -27,10 +29,11 @@ class InclusionRewriter : public PPCallbacks { /// Information about which #includes were actually performed, /// created by preprocessor callbacks. struct FileChange { + const Module *Mod; SourceLocation From; FileID Id; SrcMgr::CharacteristicKind FileType; - FileChange(SourceLocation From) : From(From) { + FileChange(SourceLocation From, const Module *Mod) : Mod(Mod), From(From) { } }; Preprocessor &PP; ///< Used to find inclusion directives. @@ -65,6 +68,7 @@ private: void WriteLineInfo(const char *Filename, int Line, SrcMgr::CharacteristicKind FileType, StringRef EOL, StringRef Extra = StringRef()); + void WriteImplicitModuleImport(const Module *Mod, StringRef EOL); void OutputContentUpTo(const MemoryBuffer &FromFile, unsigned &WriteFrom, unsigned WriteTo, StringRef EOL, int &lines, @@ -72,6 +76,9 @@ private: void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, const MemoryBuffer &FromFile, StringRef EOL, unsigned &NextToWrite, int &Lines); + bool HandleHasInclude(FileID FileId, Lexer &RawLex, + const DirectoryLookup *Lookup, Token &Tok, + bool &FileExists); const FileChange *FindFileChangeLocation(SourceLocation Loc) const; StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); }; @@ -117,6 +124,12 @@ void InclusionRewriter::WriteLineInfo(const char *Filename, int Line, OS << EOL; } +void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod, + StringRef EOL) { + OS << "@import " << Mod->getFullModuleName() << ";" + << " /* clang -frewrite-includes: implicit import */" << EOL; +} + /// FileChanged - Whenever the preprocessor enters or exits a #include file /// it invokes this handler. void InclusionRewriter::FileChanged(SourceLocation Loc, @@ -157,13 +170,14 @@ void InclusionRewriter::InclusionDirective(SourceLocation HashLoc, const FileEntry * /*File*/, StringRef /*SearchPath*/, StringRef /*RelativePath*/, - const Module * /*Imported*/) { + const Module *Imported) { assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion " "directive was found before the previous one was processed"); std::pair<FileChangeMap::iterator, bool> p = FileChanges.insert( - std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc))); + std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc, Imported))); assert(p.second && "Unexpected revisitation of the same include directive"); - LastInsertedFileChange = p.first; + if (!Imported) + LastInsertedFileChange = p.first; } /// Simple lookup for a SourceLocation (specifically one denoting the hash in @@ -245,6 +259,75 @@ StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, return StringRef(); } +// Expand __has_include and __has_include_next if possible. If there's no +// definitive answer return false. +bool InclusionRewriter::HandleHasInclude( + FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok, + bool &FileExists) { + // Lex the opening paren. + RawLex.LexFromRawLexer(Tok); + if (Tok.isNot(tok::l_paren)) + return false; + + RawLex.LexFromRawLexer(Tok); + + SmallString<128> FilenameBuffer; + StringRef Filename; + // Since the raw lexer doesn't give us angle_literals we have to parse them + // ourselves. + // FIXME: What to do if the file name is a macro? + if (Tok.is(tok::less)) { + RawLex.LexFromRawLexer(Tok); + + FilenameBuffer += '<'; + do { + if (Tok.is(tok::eod)) // Sanity check. + return false; + + if (Tok.is(tok::raw_identifier)) + PP.LookUpIdentifierInfo(Tok); + + // Get the string piece. + SmallVector<char, 128> TmpBuffer; + bool Invalid = false; + StringRef TmpName = PP.getSpelling(Tok, TmpBuffer, &Invalid); + if (Invalid) + return false; + + FilenameBuffer += TmpName; + + RawLex.LexFromRawLexer(Tok); + } while (Tok.isNot(tok::greater)); + + FilenameBuffer += '>'; + Filename = FilenameBuffer; + } else { + if (Tok.isNot(tok::string_literal)) + return false; + + bool Invalid = false; + Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid); + if (Invalid) + return false; + } + + // Lex the closing paren. + RawLex.LexFromRawLexer(Tok); + if (Tok.isNot(tok::r_paren)) + return false; + + // Now ask HeaderInfo if it knows about the header. + // FIXME: Subframeworks aren't handled here. Do we care? + bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename); + const DirectoryLookup *CurDir; + const FileEntry *File = PP.getHeaderSearchInfo().LookupFile( + Filename, isAngled, 0, CurDir, + PP.getSourceManager().getFileEntryForID(FileId), 0, 0, 0, false); + + FileExists = File != 0; + return true; +} + /// Use a raw lexer to analyze \p FileId, inccrementally copying parts of it /// and including content of included files recursively. bool InclusionRewriter::Process(FileID FileId, @@ -253,7 +336,7 @@ bool InclusionRewriter::Process(FileID FileId, bool Invalid; const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); if (Invalid) // invalid inclusion - return true; + return false; const char *FileName = FromFile.getBufferIdentifier(); Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts()); RawLex.SetCommentRetentionState(false); @@ -264,7 +347,7 @@ bool InclusionRewriter::Process(FileID FileId, WriteLineInfo(FileName, 1, FileType, EOL, " 1"); if (SM.getFileIDSize(FileId) == 0) - return true; + return false; // The next byte to be copied from the source file unsigned NextToWrite = 0; @@ -282,26 +365,31 @@ bool InclusionRewriter::Process(FileID FileId, RawLex.LexFromRawLexer(RawToken); if (RawToken.is(tok::raw_identifier)) PP.LookUpIdentifierInfo(RawToken); - if (RawToken.is(tok::identifier)) { + if (RawToken.is(tok::identifier) || RawToken.is(tok::kw_if)) { switch (RawToken.getIdentifierInfo()->getPPKeywordID()) { case tok::pp_include: case tok::pp_include_next: case tok::pp_import: { CommentOutDirective(RawLex, HashToken, FromFile, EOL, NextToWrite, Line); + StringRef LineInfoExtra; if (const FileChange *Change = FindFileChangeLocation( HashToken.getLocation())) { - // now include and recursively process the file - if (Process(Change->Id, Change->FileType)) + if (Change->Mod) { + WriteImplicitModuleImport(Change->Mod, EOL); + + // else now include and recursively process the file + } else if (Process(Change->Id, Change->FileType)) { // and set lineinfo back to this file, if the nested one was // actually included // `2' indicates returning to a file (after having included // another file. - WriteLineInfo(FileName, Line, FileType, EOL, " 2"); - } else - // fix up lineinfo (since commented out directive changed line - // numbers) for inclusions that were skipped due to header guards - WriteLineInfo(FileName, Line, FileType, EOL); + LineInfoExtra = " 2"; + } + } + // fix up lineinfo (since commented out directive changed line + // numbers) for inclusions that were skipped due to header guards + WriteLineInfo(FileName, Line, FileType, EOL, LineInfoExtra); break; } case tok::pp_pragma: { @@ -323,6 +411,50 @@ bool InclusionRewriter::Process(FileID FileId, } break; } + case tok::pp_if: + case tok::pp_elif: + // Rewrite special builtin macros to avoid pulling in host details. + do { + // Walk over the directive. + RawLex.LexFromRawLexer(RawToken); + if (RawToken.is(tok::raw_identifier)) + PP.LookUpIdentifierInfo(RawToken); + + if (RawToken.is(tok::identifier)) { + bool HasFile; + SourceLocation Loc = RawToken.getLocation(); + + // Rewrite __has_include(x) + if (RawToken.getIdentifierInfo()->isStr("__has_include")) { + if (!HandleHasInclude(FileId, RawLex, 0, RawToken, HasFile)) + continue; + // Rewrite __has_include_next(x) + } else if (RawToken.getIdentifierInfo()->isStr( + "__has_include_next")) { + const DirectoryLookup *Lookup = PP.GetCurDirLookup(); + if (Lookup) + ++Lookup; + + if (!HandleHasInclude(FileId, RawLex, Lookup, RawToken, + HasFile)) + continue; + } else { + continue; + } + // Replace the macro with (0) or (1), followed by the commented + // out macro for reference. + OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc), + EOL, Line); + OS << '(' << (int) HasFile << ")/*"; + OutputContentUpTo(FromFile, NextToWrite, + SM.getFileOffset(RawToken.getLocation()) + + RawToken.getLength(), + EOL, Line); + OS << "*/"; + } + } while (RawToken.isNot(tok::eod)); + + break; default: break; } diff --git a/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp index caba62b118..0e59b113c9 100644 --- a/lib/Rewrite/Frontend/RewriteModernObjC.cpp +++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp @@ -939,9 +939,8 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, // Generate the 'getter' function. ObjCPropertyDecl *PD = PID->getPropertyDecl(); ObjCIvarDecl *OID = PID->getPropertyIvarDecl(); + assert(IMD && OID && "Synthesized ivars must be attached to @implementation"); - if (!OID) - return; unsigned Attributes = PD->getPropertyAttributes(); if (mustSynthesizeSetterGetterMethod(IMD, PD, true /*getter*/)) { bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && @@ -1150,7 +1149,7 @@ void RewriteModernObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { // Lastly, comment out the @end. ReplaceText(CatDecl->getAtEndRange().getBegin(), - strlen("@end"), "/* @end */"); + strlen("@end"), "/* @end */\n"); } void RewriteModernObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { @@ -1175,7 +1174,7 @@ void RewriteModernObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { // Lastly, comment out the @end. SourceLocation LocEnd = PDecl->getAtEndRange().getBegin(); - ReplaceText(LocEnd, strlen("@end"), "/* @end */"); + ReplaceText(LocEnd, strlen("@end"), "/* @end */\n"); // Must comment out @optional/@required const char *startBuf = SM->getCharacterData(LocStart); @@ -1443,7 +1442,7 @@ void RewriteModernObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { // Lastly, comment out the @end. ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"), - "/* @end */"); + "/* @end */\n"); } } @@ -2260,6 +2259,10 @@ void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { Loc = FD->getLocation(); Type = FD->getType(); } + else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(Dcl)) { + Loc = TD->getLocation(); + Type = TD->getUnderlyingType(); + } else return; @@ -2362,7 +2365,7 @@ void RewriteModernObjC::SynthSelGetUidFunctionDecl() { SourceLocation(), SourceLocation(), SelGetUidIdent, getFuncType, 0, - SC_Extern, SC_None); + SC_Extern); } void RewriteModernObjC::RewriteFunctionDecl(FunctionDecl *FD) { @@ -2460,7 +2463,7 @@ void RewriteModernObjC::SynthSuperContructorFunctionDecl() { SourceLocation(), SourceLocation(), msgSendIdent, msgSendType, - 0, SC_Extern, SC_None); + 0, SC_Extern); } // SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); @@ -2479,7 +2482,7 @@ void RewriteModernObjC::SynthMsgSendFunctionDecl() { SourceLocation(), SourceLocation(), msgSendIdent, msgSendType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(void); @@ -2493,7 +2496,7 @@ void RewriteModernObjC::SynthMsgSendSuperFunctionDecl() { SourceLocation(), SourceLocation(), msgSendIdent, msgSendType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); @@ -2512,7 +2515,7 @@ void RewriteModernObjC::SynthMsgSendStretFunctionDecl() { SourceLocation(), SourceLocation(), msgSendIdent, msgSendType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthMsgSendSuperStretFunctionDecl - @@ -2529,7 +2532,7 @@ void RewriteModernObjC::SynthMsgSendSuperStretFunctionDecl() { SourceLocation(), msgSendIdent, msgSendType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); @@ -2548,7 +2551,7 @@ void RewriteModernObjC::SynthMsgSendFpretFunctionDecl() { SourceLocation(), SourceLocation(), msgSendIdent, msgSendType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthGetClassFunctionDecl - Class objc_getClass(const char *name); @@ -2562,7 +2565,7 @@ void RewriteModernObjC::SynthGetClassFunctionDecl() { SourceLocation(), SourceLocation(), getClassIdent, getClassType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls); @@ -2578,7 +2581,7 @@ void RewriteModernObjC::SynthGetSuperClassFunctionDecl() { SourceLocation(), getSuperClassIdent, getClassType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthGetMetaClassFunctionDecl - Class objc_getMetaClass(const char *name); @@ -2592,7 +2595,7 @@ void RewriteModernObjC::SynthGetMetaClassFunctionDecl() { SourceLocation(), SourceLocation(), getClassIdent, getClassType, - 0, SC_Extern, SC_None); + 0, SC_Extern); } Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { @@ -2625,7 +2628,7 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), SourceLocation(), &Context->Idents.get(S), - strType, 0, SC_Static, SC_None); + strType, 0, SC_Static); DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue, SourceLocation()); Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, @@ -3136,7 +3139,7 @@ static SourceLocation getFunctionSourceLocation (RewriteModernObjC &R, if (!LSD->getRBraceLoc().isValid()) return LSD->getExternLoc(); } - if (FD->getStorageClassAsWritten() != SC_None) + if (FD->getStorageClass() != SC_None) R.RewriteBlockLiteralFunctionDecl(FD); return FD->getTypeSpecStartLoc(); } @@ -3247,7 +3250,7 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla IdentifierInfo *ID = &Context->Idents.get(name); FunctionDecl *FD = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), SourceLocation(), ID, castType, 0, - SC_Extern, SC_None, false, false); + SC_Extern, false, false); DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, castType, VK_RValue, SourceLocation()); CallExpr *STCE = new (Context) CallExpr(*Context, DRE, MsgExprs, @@ -3720,7 +3723,7 @@ Stmt *RewriteModernObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { IdentifierInfo *ID = &Context->Idents.get(Name); VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), SourceLocation(), ID, getProtocolType(), 0, - SC_Extern, SC_None); + SC_Extern); DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(), VK_LValue, SourceLocation()); Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf, @@ -5400,7 +5403,7 @@ FunctionDecl *RewriteModernObjC::SynthBlockInitFunctionDecl(StringRef name) { QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); return FunctionDecl::Create(*Context, TUDecl, SourceLocation(), SourceLocation(), ID, FType, 0, SC_Extern, - SC_None, false, false); + false, false); } Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp, @@ -5501,7 +5504,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp, SourceLocation(), SourceLocation(), &Context->Idents.get(DescData.c_str()), Context->VoidPtrTy, 0, - SC_Static, SC_None); + SC_Static); UnaryOperator *DescRefExpr = new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false, Context->VoidPtrTy, @@ -5997,6 +6000,8 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) { RewriteBlockPointerDecl(TD); else if (TD->getUnderlyingType()->isFunctionPointerType()) CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); + else + RewriteObjCQualifiedInterfaceTypes(TD); } break; } @@ -7763,7 +7768,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { BaseExpr); VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), SourceLocation(), &Context->Idents.get(IvarOffsetName), - Context->UnsignedLongTy, 0, SC_Extern, SC_None); + Context->UnsignedLongTy, 0, SC_Extern); DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, Context->UnsignedLongTy, VK_LValue, SourceLocation()); diff --git a/lib/Rewrite/Frontend/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp index 108041753d..2f5cd0f6c6 100644 --- a/lib/Rewrite/Frontend/RewriteObjC.cpp +++ b/lib/Rewrite/Frontend/RewriteObjC.cpp @@ -2267,7 +2267,7 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() { SourceLocation(), SourceLocation(), SelGetUidIdent, getFuncType, 0, - SC_Extern, SC_None); + SC_Extern); } void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) { @@ -2363,7 +2363,7 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() { SourceLocation(), SourceLocation(), msgSendIdent, msgSendType, - 0, SC_Extern, SC_None); + 0, SC_Extern); } // SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); @@ -2382,7 +2382,7 @@ void RewriteObjC::SynthMsgSendFunctionDecl() { SourceLocation(), SourceLocation(), msgSendIdent, msgSendType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...); @@ -2404,7 +2404,7 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() { SourceLocation(), SourceLocation(), msgSendIdent, msgSendType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); @@ -2423,7 +2423,7 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() { SourceLocation(), SourceLocation(), msgSendIdent, msgSendType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthMsgSendSuperStretFunctionDecl - @@ -2448,7 +2448,7 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { SourceLocation(), msgSendIdent, msgSendType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); @@ -2467,7 +2467,7 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() { SourceLocation(), SourceLocation(), msgSendIdent, msgSendType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthGetClassFunctionDecl - id objc_getClass(const char *name); @@ -2481,7 +2481,7 @@ void RewriteObjC::SynthGetClassFunctionDecl() { SourceLocation(), SourceLocation(), getClassIdent, getClassType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls); @@ -2497,7 +2497,7 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() { SourceLocation(), getSuperClassIdent, getClassType, 0, - SC_Extern, SC_None); + SC_Extern); } // SynthGetMetaClassFunctionDecl - id objc_getMetaClass(const char *name); @@ -2511,7 +2511,7 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() { SourceLocation(), SourceLocation(), getClassIdent, getClassType, - 0, SC_Extern, SC_None); + 0, SC_Extern); } Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { @@ -2544,7 +2544,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), SourceLocation(), &Context->Idents.get(S), - strType, 0, SC_Static, SC_None); + strType, 0, SC_Static); DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue, SourceLocation()); Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, @@ -3112,7 +3112,7 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { IdentifierInfo *ID = &Context->Idents.get(Name); VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), SourceLocation(), ID, getProtocolType(), 0, - SC_Extern, SC_None); + SC_Extern); DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(), VK_LValue, SourceLocation()); Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf, @@ -4448,7 +4448,7 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) { QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); return FunctionDecl::Create(*Context, TUDecl, SourceLocation(), SourceLocation(), ID, FType, 0, SC_Extern, - SC_None, false, false); + false, false); } Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, @@ -4532,7 +4532,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, SourceLocation(), SourceLocation(), &Context->Idents.get(DescData.c_str()), Context->VoidPtrTy, 0, - SC_Static, SC_None); + SC_Static); UnaryOperator *DescRefExpr = new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false, Context->VoidPtrTy, diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 9993b48832..1295339aa3 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -817,6 +817,10 @@ namespace { return true; } + // We don't want to traverse local type declarations. We analyze their + // methods separately. + bool TraverseDecl(Decl *D) { return true; } + private: static const AttributedStmt *asFallThroughAttr(const Stmt *S) { @@ -1329,8 +1333,12 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { LocEndOfScope = FunEndLocation; PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << LockName); - PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here)); - Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note))); + if (LocLocked.isValid()) { + PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here)); + Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note))); + return; + } + Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); } diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index e227d4e840..9ac4c63e19 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -23,6 +23,8 @@ size_t AttributeList::allocated_size() const { if (IsAvailability) return AttributeFactory::AvailabilityAllocSize; else if (IsTypeTagForDatatype) return AttributeFactory::TypeTagForDatatypeAllocSize; + else if (IsProperty) + return AttributeFactory::PropertyAllocSize; return (sizeof(AttributeList) + NumArgs * sizeof(Expr*)); } diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 4636a097fd..e92f767134 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -38,6 +38,7 @@ add_clang_library(clangSema SemaLambda.cpp SemaLookup.cpp SemaObjCProperty.cpp + SemaOpenMP.cpp SemaOverload.cpp SemaPseudoObject.cpp SemaStmt.cpp diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 569352ecb9..3b3ab2c27b 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -24,6 +24,7 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/ErrorHandling.h" #include <cstring> using namespace clang; @@ -169,6 +170,9 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, TypeResult TrailingReturnType) { + assert(!(TypeQuals & DeclSpec::TQ_atomic) && + "function cannot have _Atomic qualifier"); + DeclaratorChunk I; I.Kind = Function; I.Loc = LocalRangeBegin; @@ -290,6 +294,11 @@ bool Declarator::isDeclarationOfFunction() const { case TST_event_t: return false; + case TST_decltype_auto: + // This must have an initializer, so can't be a function declaration, + // even if the initializer has function type. + return false; + case TST_decltype: case TST_typeofExpr: if (Expr *E = DS.getRepAsExpr()) @@ -322,7 +331,7 @@ bool Declarator::isDeclarationOfFunction() const { unsigned DeclSpec::getParsedSpecifiers() const { unsigned Res = 0; if (StorageClassSpec != SCS_unspecified || - SCS_thread_specified) + ThreadStorageClassSpec != TSCS_unspecified) Res |= PQ_StorageClassSpecifier; if (TypeQualifiers != TQ_unspecified) @@ -364,6 +373,16 @@ const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { llvm_unreachable("Unknown typespec!"); } +const char *DeclSpec::getSpecifierName(DeclSpec::TSCS S) { + switch (S) { + case DeclSpec::TSCS_unspecified: return "unspecified"; + case DeclSpec::TSCS___thread: return "__thread"; + case DeclSpec::TSCS_thread_local: return "thread_local"; + case DeclSpec::TSCS__Thread_local: return "_Thread_local"; + } + llvm_unreachable("Unknown typespec!"); +} + const char *DeclSpec::getSpecifierName(TSW W) { switch (W) { case TSW_unspecified: return "unspecified"; @@ -420,6 +439,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_typeofExpr: return "typeof"; case DeclSpec::TST_auto: return "auto"; case DeclSpec::TST_decltype: return "(decltype)"; + case DeclSpec::TST_decltype_auto: return "decltype(auto)"; case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_atomic: return "_Atomic"; @@ -442,6 +462,7 @@ const char *DeclSpec::getSpecifierName(TQ T) { case DeclSpec::TQ_const: return "const"; case DeclSpec::TQ_restrict: return "restrict"; case DeclSpec::TQ_volatile: return "volatile"; + case DeclSpec::TQ_atomic: return "_Atomic"; } llvm_unreachable("Unknown typespec!"); } @@ -479,7 +500,7 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, } if (StorageClassSpec != SCS_unspecified) { - // Maybe this is an attempt to use C++0x 'auto' outside of C++0x mode. + // Maybe this is an attempt to use C++11 'auto' outside of C++11 mode. bool isInvalid = true; if (TypeSpecType == TST_unspecified && S.getLangOpts().CPlusPlus) { if (SC == SCS_auto) @@ -506,16 +527,14 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, return false; } -bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc, +bool DeclSpec::SetStorageClassSpecThread(TSCS TSC, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { - if (SCS_thread_specified) { - PrevSpec = "__thread"; - DiagID = diag::ext_duplicate_declspec; - return true; - } - SCS_thread_specified = true; - SCS_threadLoc = Loc; + if (ThreadStorageClassSpec != TSCS_unspecified) + return BadSpecifier(TSC, (TSCS)ThreadStorageClassSpec, PrevSpec, DiagID); + + ThreadStorageClassSpec = TSC; + ThreadStorageClassSpecLoc = Loc; return false; } @@ -710,12 +729,14 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, TypeQualifiers |= T; switch (T) { - default: llvm_unreachable("Unknown type qualifier!"); - case TQ_const: TQ_constLoc = Loc; break; - case TQ_restrict: TQ_restrictLoc = Loc; break; - case TQ_volatile: TQ_volatileLoc = Loc; break; + case TQ_unspecified: break; + case TQ_const: TQ_constLoc = Loc; return false; + case TQ_restrict: TQ_restrictLoc = Loc; return false; + case TQ_volatile: TQ_volatileLoc = Loc; return false; + case TQ_atomic: TQ_atomicLoc = Loc; return false; } - return false; + + llvm_unreachable("Unknown type qualifier!"); } bool DeclSpec::setFunctionSpecInline(SourceLocation Loc) { @@ -809,15 +830,6 @@ void DeclSpec::SaveWrittenBuiltinSpecs() { } } -void DeclSpec::SaveStorageSpecifierAsWritten() { - if (SCS_extern_in_linkage_spec && StorageClassSpec == SCS_extern) - // If 'extern' is part of a linkage specification, - // then it is not a storage class "as written". - StorageClassSpecAsWritten = SCS_unspecified; - else - StorageClassSpecAsWritten = StorageClassSpec; -} - /// Finish - This does final analysis of the declspec, rejecting things like /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, @@ -825,10 +837,42 @@ void DeclSpec::SaveStorageSpecifierAsWritten() { void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { // Before possibly changing their values, save specs as written. SaveWrittenBuiltinSpecs(); - SaveStorageSpecifierAsWritten(); // Check the type specifier components first. + // If decltype(auto) is used, no other type specifiers are permitted. + if (TypeSpecType == TST_decltype_auto && + (TypeSpecWidth != TSW_unspecified || + TypeSpecComplex != TSC_unspecified || + TypeSpecSign != TSS_unspecified || + TypeAltiVecVector || TypeAltiVecPixel || TypeAltiVecBool || + TypeQualifiers)) { + const unsigned NumLocs = 8; + SourceLocation ExtraLocs[NumLocs] = { + TSWLoc, TSCLoc, TSSLoc, AltiVecLoc, + TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc + }; + FixItHint Hints[NumLocs]; + SourceLocation FirstLoc; + for (unsigned I = 0; I != NumLocs; ++I) { + if (!ExtraLocs[I].isInvalid()) { + if (FirstLoc.isInvalid() || + PP.getSourceManager().isBeforeInTranslationUnit(ExtraLocs[I], + FirstLoc)) + FirstLoc = ExtraLocs[I]; + Hints[I] = FixItHint::CreateRemoval(ExtraLocs[I]); + } + } + TypeSpecWidth = TSW_unspecified; + TypeSpecComplex = TSC_unspecified; + TypeSpecSign = TSS_unspecified; + TypeAltiVecVector = TypeAltiVecPixel = TypeAltiVecBool = false; + TypeQualifiers = 0; + Diag(D, TSTLoc, diag::err_decltype_auto_cannot_be_combined) + << Hints[0] << Hints[1] << Hints[2] << Hints[3] + << Hints[4] << Hints[5] << Hints[6] << Hints[7]; + } + // Validate and finalize AltiVec vector declspec. if (TypeAltiVecVector) { if (TypeAltiVecBool) { @@ -927,20 +971,47 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { } } + // C11 6.7.1/3, C++11 [dcl.stc]p1, GNU TLS: __thread, thread_local and + // _Thread_local can only appear with the 'static' and 'extern' storage class + // specifiers. We also allow __private_extern__ as an extension. + if (ThreadStorageClassSpec != TSCS_unspecified) { + switch (StorageClassSpec) { + case SCS_unspecified: + case SCS_extern: + case SCS_private_extern: + case SCS_static: + break; + default: + if (PP.getSourceManager().isBeforeInTranslationUnit( + getThreadStorageClassSpecLoc(), getStorageClassSpecLoc())) + Diag(D, getStorageClassSpecLoc(), + diag::err_invalid_decl_spec_combination) + << DeclSpec::getSpecifierName(getThreadStorageClassSpec()) + << SourceRange(getThreadStorageClassSpecLoc()); + else + Diag(D, getThreadStorageClassSpecLoc(), + diag::err_invalid_decl_spec_combination) + << DeclSpec::getSpecifierName(getStorageClassSpec()) + << SourceRange(getStorageClassSpecLoc()); + // Discard the thread storage class specifier to recover. + ThreadStorageClassSpec = TSCS_unspecified; + ThreadStorageClassSpecLoc = SourceLocation(); + } + } + // If no type specifier was provided and we're parsing a language where // the type specifier is not optional, but we got 'auto' as a storage // class specifier, then assume this is an attempt to use C++0x's 'auto' // type specifier. - // FIXME: Does Microsoft really support implicit int in C++? - if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().MicrosoftExt && + if (PP.getLangOpts().CPlusPlus && TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) { TypeSpecType = TST_auto; - StorageClassSpec = StorageClassSpecAsWritten = SCS_unspecified; + StorageClassSpec = SCS_unspecified; TSTLoc = TSTNameLoc = StorageClassSpecLoc; StorageClassSpecLoc = SourceLocation(); } // Diagnose if we've recovered from an ill-formed 'auto' storage class - // specifier in a pre-C++0x dialect of C++. + // specifier in a pre-C++11 dialect of C++. if (!PP.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto) Diag(D, TSTLoc, diag::ext_auto_type_specifier); if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus11 && @@ -956,16 +1027,27 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. - if (isFriendSpecified() && getStorageClassSpec()) { - DeclSpec::SCS SC = getStorageClassSpec(); - const char *SpecName = getSpecifierName(SC); + if (isFriendSpecified() && + (getStorageClassSpec() || getThreadStorageClassSpec())) { + SmallString<32> SpecName; + SourceLocation SCLoc; + FixItHint StorageHint, ThreadHint; + + if (DeclSpec::SCS SC = getStorageClassSpec()) { + SpecName = getSpecifierName(SC); + SCLoc = getStorageClassSpecLoc(); + StorageHint = FixItHint::CreateRemoval(SCLoc); + } - SourceLocation SCLoc = getStorageClassSpecLoc(); - SourceLocation SCEndLoc = SCLoc.getLocWithOffset(strlen(SpecName)); + if (DeclSpec::TSCS TSC = getThreadStorageClassSpec()) { + if (!SpecName.empty()) SpecName += " "; + SpecName += getSpecifierName(TSC); + SCLoc = getThreadStorageClassSpecLoc(); + ThreadHint = FixItHint::CreateRemoval(SCLoc); + } Diag(D, SCLoc, diag::err_friend_storage_spec) - << SpecName - << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); + << SpecName << StorageHint << ThreadHint; ClearStorageClassSpecs(); } diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp index 4d29a34a73..2f48bec123 100644 --- a/lib/Sema/ScopeInfo.cpp +++ b/lib/Sema/ScopeInfo.cpp @@ -187,3 +187,4 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) { FunctionScopeInfo::~FunctionScopeInfo() { } BlockScopeInfo::~BlockScopeInfo() { } LambdaScopeInfo::~LambdaScopeInfo() { } +CapturedRegionScopeInfo::~CapturedRegionScopeInfo() { } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 6239172a09..e718be2f8b 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -90,7 +90,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(0), TyposCorrected(0), - AnalysisWarnings(*this) + AnalysisWarnings(*this), CurScope(0), Ident_super(0) { TUScope = 0; @@ -332,6 +332,9 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { if (D->getMostRecentDecl()->isUsed()) return true; + if (D->hasExternalLinkage()) + return true; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // UnusedFileScopedDecls stores the first declaration. // The declaration may have become definition so check again. @@ -360,9 +363,6 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); } - if (D->hasExternalLinkage()) - return true; - return false; } @@ -590,12 +590,11 @@ void Sema::ActOnEndOfTranslationUnit() { } // Remove file scoped decls that turned out to be used. - UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(0, - true), - UnusedFileScopedDecls.end(), - std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), - this)), - UnusedFileScopedDecls.end()); + UnusedFileScopedDecls.erase( + std::remove_if(UnusedFileScopedDecls.begin(0, true), + UnusedFileScopedDecls.end(), + std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), this)), + UnusedFileScopedDecls.end()); if (TUKind == TU_Prefix) { // Translation unit prefixes don't need any of the checking below. @@ -616,6 +615,12 @@ void Sema::ActOnEndOfTranslationUnit() { << I->first; } + if (LangOpts.CPlusPlus11 && + Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle, + SourceLocation()) + != DiagnosticsEngine::Ignored) + CheckDelegatingCtorCycles(); + if (TUKind == TU_Module) { // If we are building a module, resolve all of the exported declarations // now. @@ -628,11 +633,12 @@ void Sema::ActOnEndOfTranslationUnit() { Module *Mod = Stack.back(); Stack.pop_back(); - // Resolve the exported declarations. + // Resolve the exported declarations and conflicts. // FIXME: Actually complain, once we figure out how to teach the - // diagnostic client to deal with complains in the module map at this + // diagnostic client to deal with complaints in the module map at this // point. ModMap.resolveExports(Mod, /*Complain=*/false); + ModMap.resolveConflicts(Mod, /*Complain=*/false); // Queue the submodules, so their exports will also be resolved. for (Module::submodule_iterator Sub = Mod->submodule_begin(), @@ -700,12 +706,6 @@ void Sema::ActOnEndOfTranslationUnit() { } - if (LangOpts.CPlusPlus11 && - Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle, - SourceLocation()) - != DiagnosticsEngine::Ignored) - CheckDelegatingCtorCycles(); - // If there were errors, disable 'unused' warnings since they will mostly be // noise. if (!Diags.hasErrorOccurred()) { @@ -727,7 +727,7 @@ void Sema::ActOnEndOfTranslationUnit() { Diag(DiagD->getLocation(), diag::warn_unneeded_member_function) << DiagD->getDeclName(); else { - if (FD->getStorageClassAsWritten() == SC_Static && + if (FD->getStorageClass() == SC_Static && !FD->isInlineSpecified() && !SourceMgr.isFromMainFile( SourceMgr.getExpansionLoc(FD->getLocation()))) @@ -750,9 +750,13 @@ void Sema::ActOnEndOfTranslationUnit() { if (DiagD->isReferenced()) { Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) << /*variable*/1 << DiagD->getDeclName(); - } else { + } else if (getSourceManager().isFromMainFile(DiagD->getLocation())) { + // If the declaration is in a header which is included into multiple + // TUs, it will declare one variable per TU, and one of the other + // variables may be used. So, only warn if the declaration is in the + // main file. Diag(DiagD->getLocation(), diag::warn_unused_variable) - << DiagD->getDeclName(); + << DiagD->getDeclName(); } } } @@ -797,7 +801,7 @@ DeclContext *Sema::getFunctionLevelDeclContext() { DeclContext *DC = CurContext; while (true) { - if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) { + if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC)) { DC = DC->getParent(); } else if (isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call && @@ -1072,7 +1076,8 @@ void Sema::ActOnComment(SourceRange Comment) { if (!LangOpts.RetainCommentsFromSystemHeaders && SourceMgr.isInSystemHeader(Comment.getBegin())) return; - RawComment RC(SourceMgr, Comment); + RawComment RC(SourceMgr, Comment, false, + LangOpts.CommentOpts.ParseAllComments); if (RC.isAlmostTrailingComment()) { SourceRange MagicMarkerRange(Comment.getBegin(), Comment.getBegin().getLocWithOffset(3)); @@ -1291,7 +1296,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, // FIXME: Try this before emitting the fixit, and suppress diagnostics // while doing so. E = ActOnCallExpr(0, E.take(), ParenInsertionLoc, - MultiExprArg(), ParenInsertionLoc.getLocWithOffset(1)); + None, ParenInsertionLoc.getLocWithOffset(1)); return true; } @@ -1302,3 +1307,24 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, E = ExprError(); return true; } + +IdentifierInfo *Sema::getSuperIdentifier() const { + if (!Ident_super) + Ident_super = &Context.Idents.get("super"); + return Ident_super; +} + +void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD, + CapturedRegionKind K) { + CapturingScopeInfo *CSI = new CapturedRegionScopeInfo(getDiagnostics(), S, CD, RD, + CD->getContextParam(), K); + CSI->ReturnType = Context.VoidTy; + FunctionScopes.push_back(CSI); +} + +CapturedRegionScopeInfo *Sema::getCurCapturedRegion() { + if (FunctionScopes.empty()) + return 0; + + return dyn_cast<CapturedRegionScopeInfo>(FunctionScopes.back()); +} diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 79a9d3c9fd..3ef1fdebaa 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -84,10 +84,10 @@ struct EffectiveContext { : Inner(DC), Dependent(DC->isDependentContext()) { - // C++ [class.access.nest]p1: + // C++11 [class.access.nest]p1: // A nested class is a member and as such has the same access // rights as any other member. - // C++ [class.access]p2: + // C++11 [class.access]p2: // A member of a class can also access all the names to which // the class has access. A local class of a member function // may access the same names that the member function itself @@ -1476,18 +1476,18 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, llvm_unreachable("falling off end"); } -void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *decl) { +void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) { // Access control for names used in the declarations of functions // and function templates should normally be evaluated in the context // of the declaration, just in case it's a friend of something. // However, this does not apply to local extern declarations. - DeclContext *DC = decl->getDeclContext(); - if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) { - if (!DC->isFunctionOrMethod()) DC = fn; - } else if (FunctionTemplateDecl *fnt = dyn_cast<FunctionTemplateDecl>(decl)) { - // Never a local declaration. - DC = fnt->getTemplatedDecl(); + DeclContext *DC = D->getDeclContext(); + if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) { + if (!DC->isFunctionOrMethod()) + DC = FN; + } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) { + DC = cast<DeclContext>(TD->getTemplatedDecl()); } EffectiveContext EC(DC); diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 85efe2d4df..01ac8f7fb6 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -78,8 +78,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, if (!SS.isSet() || SS.isInvalid()) return 0; - NestedNameSpecifier *NNS - = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + NestedNameSpecifier *NNS = SS.getScopeRep(); if (NNS->isDependent()) { // If this nested-name-specifier refers to the current // instantiation, return its DeclContext. @@ -158,9 +157,7 @@ bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) { if (!SS.isSet() || SS.isInvalid()) return false; - NestedNameSpecifier *NNS - = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - return NNS->isDependent(); + return SS.getScopeRep()->isDependent(); } // \brief Determine whether this C++ scope specifier refers to an @@ -170,9 +167,7 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) { if (!isDependentScopeSpecifier(SS)) return false; - NestedNameSpecifier *NNS - = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - return getCurrentInstantiationOf(NNS) == 0; + return getCurrentInstantiationOf(SS.getScopeRep()) == 0; } /// \brief If the given nested name specifier refers to the current @@ -769,8 +764,7 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, if (DependentTemplateName *DTN = Template.get().getAsDependentTemplateName()){ // Handle a dependent template specialization for which we cannot resolve // the template name. - assert(DTN->getQualifier() - == static_cast<NestedNameSpecifier*>(SS.getScopeRep())); + assert(DTN->getQualifier() == SS.getScopeRep()); QualType T = Context.getDependentTemplateSpecializationType(ETK_None, DTN->getQualifier(), DTN->getIdentifier(), @@ -877,8 +871,7 @@ void Sema::RestoreNestedNameSpecifierAnnotation(void *AnnotationPtr, bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); - NestedNameSpecifier *Qualifier = - static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + NestedNameSpecifier *Qualifier = SS.getScopeRep(); // There are only two places a well-formed program may qualify a // declarator: first, when defining a namespace or class member diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index 3f46cd457a..eb11a577cb 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -19,6 +19,7 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/RecordLayout.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Sema/Initialization.h" #include "llvm/ADT/SmallVector.h" @@ -332,7 +333,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, : (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range, listInitialization) : InitializationKind::CreateCast(/*type range?*/ range); - InitializationSequence sequence(S, entity, initKind, &src, 1); + InitializationSequence sequence(S, entity, initKind, src); assert(sequence.Failed() && "initialization succeeded on second try?"); switch (sequence.getFailureKind()) { @@ -682,6 +683,98 @@ void CastOperation::CheckConstCast() { << SrcExpr.get()->getType() << DestType << OpRange; } +/// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast +/// or downcast between respective pointers or references. +static void DiagnoseReinterpretUpDownCast(Sema &Self, const Expr *SrcExpr, + QualType DestType, + SourceRange OpRange) { + QualType SrcType = SrcExpr->getType(); + // When casting from pointer or reference, get pointee type; use original + // type otherwise. + const CXXRecordDecl *SrcPointeeRD = SrcType->getPointeeCXXRecordDecl(); + const CXXRecordDecl *SrcRD = + SrcPointeeRD ? SrcPointeeRD : SrcType->getAsCXXRecordDecl(); + + // Examining subobjects for records is only possible if the complete and + // valid definition is available. Also, template instantiation is not + // allowed here. + if (!SrcRD || !SrcRD->isCompleteDefinition() || SrcRD->isInvalidDecl()) + return; + + const CXXRecordDecl *DestRD = DestType->getPointeeCXXRecordDecl(); + + if (!DestRD || !DestRD->isCompleteDefinition() || DestRD->isInvalidDecl()) + return; + + enum { + ReinterpretUpcast, + ReinterpretDowncast + } ReinterpretKind; + + CXXBasePaths BasePaths; + + if (SrcRD->isDerivedFrom(DestRD, BasePaths)) + ReinterpretKind = ReinterpretUpcast; + else if (DestRD->isDerivedFrom(SrcRD, BasePaths)) + ReinterpretKind = ReinterpretDowncast; + else + return; + + bool VirtualBase = true; + bool NonZeroOffset = false; + for (CXXBasePaths::const_paths_iterator I = BasePaths.begin(), + E = BasePaths.end(); + I != E; ++I) { + const CXXBasePath &Path = *I; + CharUnits Offset = CharUnits::Zero(); + bool IsVirtual = false; + for (CXXBasePath::const_iterator IElem = Path.begin(), EElem = Path.end(); + IElem != EElem; ++IElem) { + IsVirtual = IElem->Base->isVirtual(); + if (IsVirtual) + break; + const CXXRecordDecl *BaseRD = IElem->Base->getType()->getAsCXXRecordDecl(); + assert(BaseRD && "Base type should be a valid unqualified class type"); + // Don't check if any base has invalid declaration or has no definition + // since it has no layout info. + const CXXRecordDecl *Class = IElem->Class, + *ClassDefinition = Class->getDefinition(); + if (Class->isInvalidDecl() || !ClassDefinition || + !ClassDefinition->isCompleteDefinition()) + return; + + const ASTRecordLayout &DerivedLayout = + Self.Context.getASTRecordLayout(Class); + Offset += DerivedLayout.getBaseClassOffset(BaseRD); + } + if (!IsVirtual) { + // Don't warn if any path is a non-virtually derived base at offset zero. + if (Offset.isZero()) + return; + // Offset makes sense only for non-virtual bases. + else + NonZeroOffset = true; + } + VirtualBase = VirtualBase && IsVirtual; + } + + assert((VirtualBase || NonZeroOffset) && + "Should have returned if has non-virtual base with zero offset"); + + QualType BaseType = + ReinterpretKind == ReinterpretUpcast? DestType : SrcType; + QualType DerivedType = + ReinterpretKind == ReinterpretUpcast? SrcType : DestType; + + SourceLocation BeginLoc = OpRange.getBegin(); + Self.Diag(BeginLoc, diag::warn_reinterpret_different_from_static) + << DerivedType << BaseType << !VirtualBase << ReinterpretKind + << OpRange; + Self.Diag(BeginLoc, diag::note_reinterpret_updowncast_use_static) + << ReinterpretKind + << FixItHint::CreateReplacement(BeginLoc, "static_cast"); +} + /// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is /// valid. /// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code @@ -714,8 +807,10 @@ void CastOperation::CheckReinterpretCast() { diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType, /*listInitialization=*/false); } - } else if (tcr == TC_Success && Self.getLangOpts().ObjCAutoRefCount) { - checkObjCARCConversion(Sema::CCK_OtherCast); + } else if (tcr == TC_Success) { + if (Self.getLangOpts().ObjCAutoRefCount) + checkObjCARCConversion(Sema::CCK_OtherCast); + DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange); } } @@ -1323,7 +1418,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ? InitializationKind::CreateFunctionalCast(OpRange, ListInitialization) : InitializationKind::CreateCast(OpRange); Expr *SrcExprRaw = SrcExpr.get(); - InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExprRaw, 1); + InitializationSequence InitSeq(Self, Entity, InitKind, SrcExprRaw); // At this point of CheckStaticCast, if the destination is a reference, // or the expression is an overload expression this has to work. @@ -1357,7 +1452,7 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, DestType = Self.Context.getCanonicalType(DestType); QualType SrcType = SrcExpr->getType(); if (const ReferenceType *DestTypeTmp =DestType->getAs<ReferenceType>()) { - if (DestTypeTmp->isLValueReferenceType() && !SrcExpr->isLValue()) { + if (isa<LValueReferenceType>(DestTypeTmp) && !SrcExpr->isLValue()) { // Cannot const_cast non-lvalue to lvalue reference type. But if this // is C-style, static_cast might find a way, so we simply suggest a // message and tell the parent to keep searching. @@ -1365,6 +1460,16 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_NotApplicable; } + // It's not completely clear under the standard whether we can + // const_cast bit-field gl-values. Doing so would not be + // intrinsically complicated, but for now, we say no for + // consistency with other compilers and await the word of the + // committee. + if (SrcExpr->refersToBitField()) { + msg = diag::err_bad_cxx_cast_bitfield; + return TC_NotApplicable; + } + // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2 // [...] if a pointer to T1 can be [cast] to the type pointer to T2. DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index be0480b9f1..a0998a46c6 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -586,12 +586,11 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, } bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac, - Expr **Args, unsigned NumArgs) { + ArrayRef<const Expr *> Args) { VariadicCallType CallType = Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply; - checkCall(Method, llvm::makeArrayRef<const Expr *>(Args, NumArgs), - Method->param_size(), + checkCall(Method, Args, Method->param_size(), /*IsMemberFunction=*/false, lbrac, Method->getSourceRange(), CallType); @@ -2009,7 +2008,7 @@ public: PartialDiagnostic PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, - ArrayRef<FixItHint> Fixit = ArrayRef<FixItHint>()); + ArrayRef<FixItHint> Fixit = None); protected: bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, @@ -2036,7 +2035,7 @@ protected: template <typename Range> void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, - ArrayRef<FixItHint> Fixit = ArrayRef<FixItHint>()); + ArrayRef<FixItHint> Fixit = None); void CheckPositionalAndNonpositionalArgs( const analyze_format_string::FormatSpecifier *FS); @@ -2744,6 +2743,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, return true; QualType ExprTy = E->getType(); + while (const TypeOfExprType *TET = dyn_cast<TypeOfExprType>(ExprTy)) { + ExprTy = TET->getUnderlyingExpr()->getType(); + } + if (AT.matchesType(S.Context, ExprTy)) return true; @@ -2803,7 +2806,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // casts to primitive types that are known to be large enough. bool ShouldNotPrintDirectly = false; if (S.Context.getTargetInfo().getTriple().isOSDarwin()) { - if (const TypedefType *UserTy = IntendedTy->getAs<TypedefType>()) { + // Use a 'while' to peel off layers of typedefs. + QualType TyTy = IntendedTy; + while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) { StringRef Name = UserTy->getDecl()->getName(); QualType CastTy = llvm::StringSwitch<QualType>(Name) .Case("NSInteger", S.Context.LongTy) @@ -2815,7 +2820,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, if (!CastTy.isNull()) { ShouldNotPrintDirectly = true; IntendedTy = CastTy; + break; } + TyTy = UserTy->desugar(); } } @@ -4304,7 +4311,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { IntRange::forValueOfType(C, E->getType()); } - if (FieldDecl *BitField = E->getBitField()) + if (FieldDecl *BitField = E->getSourceBitField()) return IntRange(BitField->getBitWidthValue(C), BitField->getType()->isUnsignedIntegerOrEnumerationType()); @@ -4495,9 +4502,22 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, else // op == BO_GT || op == BO_GE IsTrue = PositiveConstant; } - SmallString<16> PrettySourceValue(Value.toString(10)); + + // If this is a comparison to an enum constant, include that + // constant in the diagnostic. + const EnumConstantDecl *ED = 0; + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Constant)) + ED = dyn_cast<EnumConstantDecl>(DR->getDecl()); + + SmallString<64> PrettySourceValue; + llvm::raw_svector_ostream OS(PrettySourceValue); + if (ED) + OS << '\'' << *ED << "' (" << Value << ")"; + else + OS << Value; + S.Diag(E->getOperatorLoc(), diag::warn_out_of_range_compare) - << PrettySourceValue << OtherT << IsTrue + << OS.str() << OtherT << IsTrue << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); } @@ -4668,7 +4688,7 @@ static void AnalyzeAssignment(Sema &S, BinaryOperator *E) { // We want to recurse on the RHS as normal unless we're assigning to // a bitfield. - if (FieldDecl *Bitfield = E->getLHS()->getBitField()) { + if (FieldDecl *Bitfield = E->getLHS()->getSourceBitField()) { if (AnalyzeBitFieldAssignment(S, Bitfield, E->getRHS(), E->getOperatorLoc())) { // Recurse, ignoring any implicit conversions on the RHS. @@ -5186,10 +5206,7 @@ void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) { /// Diagnose when expression is an integer constant expression and its evaluation /// results in integer overflow void Sema::CheckForIntOverflow (Expr *E) { - if (const BinaryOperator *BExpr = dyn_cast<BinaryOperator>(E->IgnoreParens())) { - unsigned Opc = BExpr->getOpcode(); - if (Opc != BO_Add && Opc != BO_Sub && Opc != BO_Mul) - return; + if (isa<BinaryOperator>(E->IgnoreParens())) { llvm::SmallVector<PartialDiagnosticAt, 4> Diags; E->EvaluateForOverflow(Context, &Diags); } @@ -5685,12 +5702,14 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd, // notation in their sequences of declarator specifiers to specify // variable length array types. QualType PType = Param->getOriginalType(); - if (const ArrayType *AT = Context.getAsArrayType(PType)) { + while (const ArrayType *AT = Context.getAsArrayType(PType)) { if (AT->getSizeModifier() == ArrayType::Star) { // FIXME: This diagnostic should point the '[*]' if source-location // information is added for it. Diag(Param->getLocation(), diag::err_array_star_in_function_definition); + break; } + PType= AT->getElementType(); } } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 78d8518b23..fd2ce1749f 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2541,6 +2541,27 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, if (Declaration) { Result.addParentContext(Declaration->getDeclContext()); Pattern->ParentName = Result.getParentName(); + // Provide code completion comment for self.GetterName where + // GetterName is the getter method for a property with name + // different from the property name (declared via a property + // getter attribute. + const NamedDecl *ND = Declaration; + if (const ObjCMethodDecl *M = dyn_cast<ObjCMethodDecl>(ND)) + if (M->isPropertyAccessor()) + if (const ObjCPropertyDecl *PDecl = M->findPropertyDecl()) + if (PDecl->getGetterName() == M->getSelector() && + PDecl->getIdentifier() != M->getIdentifier()) { + if (const RawComment *RC = + Ctx.getRawCommentForAnyRedecl(M)) { + Result.addBriefComment(RC->getBriefText(Ctx)); + Pattern->BriefComment = Result.getBriefComment(); + } + else if (const RawComment *RC = + Ctx.getRawCommentForAnyRedecl(PDecl)) { + Result.addBriefComment(RC->getBriefText(Ctx)); + Pattern->BriefComment = Result.getBriefComment(); + } + } } return Pattern; @@ -2554,7 +2575,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, if (Kind == RK_Macro) { const MacroDirective *MD = PP.getMacroDirectiveHistory(Macro); assert(MD && "Not a macro?"); - const MacroInfo *MI = MD->getInfo(); + const MacroInfo *MI = MD->getMacroInfo(); Result.AddTypedTextChunk( Result.getAllocator().CopyString(Macro->getName())); @@ -3327,13 +3348,12 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, // be a receiver of a class message, this may be a class message send with // the initial opening bracket '[' missing. Add appropriate completions. if (AllowNonIdentifiers && !AllowNestedNameSpecifiers && + DS.getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier && DS.getTypeSpecType() == DeclSpec::TST_typename && - DS.getStorageClassSpecAsWritten() == DeclSpec::SCS_unspecified && - !DS.isThreadSpecified() && !DS.isExternInLinkageSpec() && DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified && DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && - DS.getTypeQualifiers() == 0 && - S && + !DS.isTypeAltiVecVector() && + S && (S->getFlags() & Scope::DeclScope) != 0 && (S->getFlags() & (Scope::ClassScope | Scope::TemplateParamScope | Scope::FunctionPrototypeScope | @@ -3708,6 +3728,9 @@ void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) { if (getLangOpts().C99 && !(DS.getTypeQualifiers() & DeclSpec::TQ_restrict)) Results.AddResult("restrict"); + if (getLangOpts().C11 && + !(DS.getTypeQualifiers() & DeclSpec::TQ_atomic)) + Results.AddResult("_Atomic"); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), @@ -5315,7 +5338,7 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, } else { // "super" may be the name of a type or variable. Figure out which // it is. - IdentifierInfo *Super = &Context.Idents.get("super"); + IdentifierInfo *Super = getSuperIdentifier(); NamedDecl *ND = LookupSingleName(S, Super, SuperLoc, LookupOrdinaryName); if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) { @@ -5448,7 +5471,7 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.second; MethList && MethList->Method; - MethList = MethList->Next) { + MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) continue; @@ -5621,7 +5644,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.first; MethList && MethList->Method; - MethList = MethList->Next) { + MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) continue; @@ -7062,7 +7085,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, for (ObjCMethodList *MethList = IsInstanceMethod ? &M->second.first : &M->second.second; MethList && MethList->Method; - MethList = MethList->Next) { + MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) continue; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 252f94dc22..e0e8bd646b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -129,7 +129,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { /// /// If name lookup results in an ambiguity, this routine will complain /// and then return NULL. -ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, +ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS, bool isClassName, bool HasTrailingDot, ParsedType ObjectTypePtr, @@ -676,9 +676,9 @@ Corrected: (isa<TypeDecl>(UnderlyingFirstDecl) || isa<ObjCInterfaceDecl>(UnderlyingFirstDecl) || isa<ObjCCompatibleAliasDecl>(UnderlyingFirstDecl))) { - UnqualifiedDiag = diag::err_unknown_typename_suggest; - QualifiedDiag = diag::err_unknown_nested_typename_suggest; - } + UnqualifiedDiag = diag::err_unknown_typename_suggest; + QualifiedDiag = diag::err_unknown_nested_typename_suggest; + } if (SS.isEmpty()) Diag(NameLoc, UnqualifiedDiag) @@ -1174,6 +1174,31 @@ static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) { return false; } +// We need this to handle +// +// typedef struct { +// void *foo() { return 0; } +// } A; +// +// When we see foo we don't know if after the typedef we will get 'A' or '*A' +// for example. If 'A', foo will have external linkage. If we have '*A', +// foo will have no linkage. Since we can't know untill we get to the end +// of the typedef, this function finds out if D might have non external linkage. +// Callers should verify at the end of the TU if it D has external linkage or +// not. +bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) { + const DeclContext *DC = D->getDeclContext(); + while (!DC->isTranslationUnit()) { + if (const RecordDecl *RD = dyn_cast<RecordDecl>(DC)){ + if (!RD->hasNameForLinkage()) + return true; + } + DC = DC->getParent(); + } + + return !D->hasExternalLinkage(); +} + bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { assert(D); @@ -1194,7 +1219,10 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { return false; } else { // 'static inline' functions are used in headers; don't warn. - if (FD->getStorageClass() == SC_Static && + // Make sure we get the storage class from the canonical declaration, + // since otherwise we will get spurious warnings on specialized + // static template functions. + if (FD->getCanonicalDecl()->getStorageClass() == SC_Static && FD->isInlineSpecified()) return false; } @@ -1223,10 +1251,7 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { } // Only warn for unused decls internal to the translation unit. - if (D->hasExternalLinkage()) - return false; - - return true; + return mightHaveNonExternalLinkage(D); } void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { @@ -1367,7 +1392,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (!D->getDeclName()) continue; // Diagnose unused variables in this scope. - if (!S->hasErrorOccurred()) + if (!S->hasUnrecoverableErrorOccurred()) DiagnoseUnusedDecl(D); // If this was a forward reference to a label, verify it was defined. @@ -1535,7 +1560,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, Context.getTranslationUnitDecl(), Loc, Loc, II, R, /*TInfo=*/0, SC_Extern, - SC_None, false, + false, /*hasPrototype=*/true); New->setImplicit(); @@ -1548,7 +1573,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, ParmVarDecl::Create(Context, New, SourceLocation(), SourceLocation(), 0, FT->getArgType(i), /*TInfo=*/0, - SC_None, SC_None, 0); + SC_None, 0); parm->setScopeInfo(0, i); Params.push_back(parm); } @@ -1583,9 +1608,6 @@ static void filterNonConflictingPreviousDecls(ASTContext &context, if (previous.empty()) return; - // If this declaration has external - bool hasExternalLinkage = decl->hasExternalLinkage(); - LookupResult::Filter filter = previous.makeFilter(); while (filter.hasNext()) { NamedDecl *old = filter.next(); @@ -1594,8 +1616,7 @@ static void filterNonConflictingPreviousDecls(ASTContext &context, if (!old->isHidden()) continue; - // If either has no-external linkage, ignore the old declaration. - if (!hasExternalLinkage || old->getLinkage() != ExternalLinkage) + if (old->getLinkage() != ExternalLinkage) filter.erase(); } @@ -2225,11 +2246,9 @@ static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) { return false; LanguageLinkage OldLinkage = Old->getLanguageLinkage(); - if (OldLinkage == CXXLanguageLinkage && - New->getDeclContext()->isExternCContext()) + if (OldLinkage == CXXLanguageLinkage && New->isInExternCContext()) return true; - if (OldLinkage == CLanguageLinkage && - New->getDeclContext()->isExternCXXContext()) + if (OldLinkage == CLanguageLinkage && New->isInExternCXXContext()) return true; return false; } @@ -2255,6 +2274,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { Old = dyn_cast<FunctionDecl>(OldD); if (!Old) { if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(OldD)) { + if (New->getFriendObjectKind()) { + Diag(New->getLocation(), diag::err_using_decl_friend); + Diag(Shadow->getTargetDecl()->getLocation(), + diag::note_using_decl_target); + Diag(Shadow->getUsingDecl()->getLocation(), + diag::note_using_decl) << 0; + return true; + } + Diag(New->getLocation(), diag::err_using_decl_conflict_reverse); Diag(Shadow->getTargetDecl()->getLocation(), diag::note_using_decl_target); @@ -2284,9 +2312,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { // Don't complain about this if we're in GNU89 mode and the old function // is an extern inline function. + // Don't complain about specializations. They are not supposed to have + // storage classes. if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) && New->getStorageClass() == SC_Static && - Old->getStorageClass() != SC_Static && + isExternalLinkage(Old->getLinkage()) && + !New->getTemplateSpecializationInfo() && !canRedefineFunction(Old, getLangOpts())) { if (getLangOpts().MicrosoftExt) { Diag(New->getLocation(), diag::warn_static_non_static) << New; @@ -2408,12 +2439,22 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { // Certain function declarations cannot be overloaded: // -- Function declarations that differ only in the return type // cannot be overloaded. - QualType OldReturnType = OldType->getResultType(); - QualType NewReturnType = cast<FunctionType>(NewQType)->getResultType(); + + // Go back to the type source info to compare the declared return types, + // per C++1y [dcl.type.auto]p??: + // Redeclarations or specializations of a function or function template + // with a declared return type that uses a placeholder type shall also + // use that placeholder, not a deduced type. + QualType OldDeclaredReturnType = (Old->getTypeSourceInfo() + ? Old->getTypeSourceInfo()->getType()->castAs<FunctionType>() + : OldType)->getResultType(); + QualType NewDeclaredReturnType = (New->getTypeSourceInfo() + ? New->getTypeSourceInfo()->getType()->castAs<FunctionType>() + : NewType)->getResultType(); QualType ResQT; - if (OldReturnType != NewReturnType) { - if (NewReturnType->isObjCObjectPointerType() - && OldReturnType->isObjCObjectPointerType()) + if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType)) { + if (NewDeclaredReturnType->isObjCObjectPointerType() && + OldDeclaredReturnType->isObjCObjectPointerType()) ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType); if (ResQT.isNull()) { if (New->isCXXClassMember() && New->isOutOfLine()) @@ -2428,8 +2469,21 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { NewQType = ResQT; } - const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); - CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); + QualType OldReturnType = OldType->getResultType(); + QualType NewReturnType = cast<FunctionType>(NewQType)->getResultType(); + if (OldReturnType != NewReturnType) { + // If this function has a deduced return type and has already been + // defined, copy the deduced value from the old declaration. + AutoType *OldAT = Old->getResultType()->getContainedAutoType(); + if (OldAT && OldAT->isDeduced()) { + New->setType(SubstAutoType(New->getType(), OldAT->getDeducedType())); + NewQType = Context.getCanonicalType( + SubstAutoType(NewQType, OldAT->getDeducedType())); + } + } + + const CXXMethodDecl *OldMethod = dyn_cast<CXXMethodDecl>(Old); + CXXMethodDecl *NewMethod = dyn_cast<CXXMethodDecl>(New); if (OldMethod && NewMethod) { // Preserve triviality. NewMethod->setTrivial(OldMethod->isTrivial()); @@ -2578,7 +2632,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { SourceLocation(), SourceLocation(), 0, *ParamType, /*TInfo=*/0, - SC_None, SC_None, + SC_None, 0); Param->setScopeInfo(0, Params.size()); Param->setImplicit(); @@ -2654,21 +2708,31 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { // Fall through to diagnose conflicting types. } - // A function that has already been declared has been redeclared or defined - // with a different type- show appropriate diagnostic - if (unsigned BuiltinID = Old->getBuiltinID()) { - // The user has declared a builtin function with an incompatible - // signature. + // A function that has already been declared has been redeclared or + // defined with a different type; show an appropriate diagnostic. + + // If the previous declaration was an implicitly-generated builtin + // declaration, then at the very least we should use a specialized note. + unsigned BuiltinID; + if (Old->isImplicit() && (BuiltinID = Old->getBuiltinID())) { + // If it's actually a library-defined builtin function like 'malloc' + // or 'printf', just warn about the incompatible redeclaration. if (Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) { - // The function the user is redeclaring is a library-defined - // function like 'malloc' or 'printf'. Warn about the - // redeclaration, then pretend that we don't know about this - // library built-in. Diag(New->getLocation(), diag::warn_redecl_library_builtin) << New; Diag(Old->getLocation(), diag::note_previous_builtin_declaration) << Old << Old->getType(); - New->getIdentifier()->setBuiltinID(Builtin::NotBuiltin); - Old->setInvalidDecl(); + + // If this is a global redeclaration, just forget hereafter + // about the "builtin-ness" of the function. + // + // Doing this for local extern declarations is problematic. If + // the builtin declaration remains visible, a second invalid + // local declaration will produce a hard error; if it doesn't + // remain visible, a single bogus local redeclaration (which is + // actually only a warning) could break all the downstream code. + if (!New->getDeclContext()->isFunctionOrMethod()) + New->getIdentifier()->setBuiltinID(Builtin::NotBuiltin); + return false; } @@ -2694,11 +2758,6 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, // Merge the attributes mergeDeclAttributes(New, Old); - // Merge the storage class. - if (Old->getStorageClass() != SC_Extern && - Old->getStorageClass() != SC_None) - New->setStorageClass(Old->getStorageClass()); - // Merge "pure" flag. if (Old->isPure()) New->setPure(); @@ -2731,7 +2790,10 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, ObjCMethodDecl *oldMethod) { // Merge the attributes, including deprecated/unavailable - mergeDeclAttributes(newMethod, oldMethod, AMK_Override); + AvailabilityMergeKind MergeKind = + isa<ObjCImplDecl>(newMethod->getDeclContext()) ? AMK_Redeclaration + : AMK_Override; + mergeDeclAttributes(newMethod, oldMethod, MergeKind); // Merge attributes from the parameters. ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin(), @@ -2751,14 +2813,13 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, /// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back /// to here in AddInitializerToDecl. We can't check them before the initializer /// is attached. -void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) { +void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldWasHidden) { if (New->isInvalidDecl() || Old->isInvalidDecl()) return; QualType MergedT; if (getLangOpts().CPlusPlus) { - AutoType *AT = New->getType()->getContainedAutoType(); - if (AT && !AT->isDeduced()) { + if (New->getType()->isUndeducedType()) { // We don't know what the new type is until the initializer is attached. return; } else if (Context.hasSameType(New->getType(), Old->getType())) { @@ -2798,7 +2859,11 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) { Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } - New->setType(MergedT); + + // Don't actually update the type on the new declaration if the old + // declaration was a extern declaration in a different scope. + if (!OldWasHidden) + New->setType(MergedT); } /// MergeVarDecl - We just parsed a variable 'New' which has the same name @@ -2809,7 +2874,8 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) { /// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative /// definitions here, since the initializer hasn't been attached. /// -void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { +void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous, + bool PreviousWasHidden) { // If the new decl is already invalid, don't do any other checking. if (New->isInvalidDecl()) return; @@ -2825,6 +2891,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } + if (!shouldLinkPossiblyHiddenDecl(Old, New)) + return; + // C++ [class.mem]p1: // A member shall not be declared twice in the member-specification [...] // @@ -2849,13 +2918,14 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { } // Merge the types. - MergeVarDeclTypes(New, Old); + MergeVarDeclTypes(New, Old, PreviousWasHidden); if (New->isInvalidDecl()) return; - // C99 6.2.2p4: Check if we have a static decl followed by a non-static. + // [dcl.stc]p8: Check if we have a non-static decl followed by a static. if (New->getStorageClass() == SC_Static && - (Old->getStorageClass() == SC_None || Old->hasExternalStorage())) { + !New->isStaticDataMember() && + isExternalLinkage(Old->getLinkage())) { Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); @@ -2871,8 +2941,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { // identifier has external linkage. if (New->hasExternalStorage() && Old->hasLinkage()) /* Okay */; - else if (New->getStorageClass() != SC_Static && - Old->getStorageClass() == SC_Static) { + else if (New->getCanonicalDecl()->getStorageClass() != SC_Static && + !New->isStaticDataMember() && + Old->getCanonicalDecl()->getStorageClass() == SC_Static) { Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); @@ -2885,8 +2956,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } - if (Old->hasExternalStorage() && - !New->hasLinkage() && New->isLocalVarDecl()) { + if (Old->hasLinkage() && New->isLocalVarDecl() && + !New->hasExternalStorage()) { Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); @@ -2905,12 +2976,22 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } - if (New->isThreadSpecified() && !Old->isThreadSpecified()) { - Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); - } else if (!New->isThreadSpecified() && Old->isThreadSpecified()) { - Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); + if (New->getTLSKind() != Old->getTLSKind()) { + if (!Old->getTLSKind()) { + Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_declaration); + } else if (!New->getTLSKind()) { + Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_declaration); + } else { + // Do not allow redeclaration to change the variable between requiring + // static and dynamic initialization. + // FIXME: GCC allows this, but uses the TLS keyword on the first + // declaration to determine the kind. Do we need to be compatible here? + Diag(New->getLocation(), diag::err_thread_thread_different_kind) + << New->getDeclName() << (New->getTLSKind() == VarDecl::TLS_Dynamic); + Diag(Old->getLocation(), diag::note_previous_declaration); + } } // C++ doesn't have tentative definitions, so go right ahead and check here. @@ -2932,17 +3013,6 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return; } - // c99 6.2.2 P4. - // For an identifier declared with the storage-class specifier extern in a - // scope in which a prior declaration of that identifier is visible, if - // the prior declaration specifies internal or external linkage, the linkage - // of the identifier at the later declaration is the same as the linkage - // specified at the prior declaration. - // FIXME. revisit this code. - if (New->hasExternalStorage() && - Old->getLinkage() == InternalLinkage) - New->setStorageClass(Old->getStorageClass()); - // Merge "used" flag. if (Old->isUsed(false)) New->setUsed(); @@ -2962,11 +3032,12 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with -/// no declarator (e.g. "struct foo;") is parsed. It also accopts template +/// no declarator (e.g. "struct foo;") is parsed. It also accepts template /// parameters to cope with template friend declarations. Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, - MultiTemplateParamsArg TemplateParams) { + MultiTemplateParamsArg TemplateParams, + bool IsExplicitInstantiation) { Decl *TagD = 0; TagDecl *Tag = 0; if (DS.getTypeSpecType() == DeclSpec::TST_class || @@ -3019,6 +3090,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, return TagD; } + DiagnoseFunctionSpecifiers(DS); + if (DS.isFriendSpecified()) { // If we're dealing with a decl but not a TagDecl, assume that // whatever routines created it handled the friendship aspect. @@ -3027,10 +3100,28 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, return ActOnFriendTypeDecl(S, DS, TemplateParams); } - // Track whether we warned about the fact that there aren't any - // declarators. - bool emittedWarning = false; - + CXXScopeSpec &SS = DS.getTypeSpecScope(); + bool IsExplicitSpecialization = + !TemplateParams.empty() && TemplateParams.back()->size() == 0; + if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() && + !IsExplicitInstantiation && !IsExplicitSpecialization) { + // Per C++ [dcl.type.elab]p1, a class declaration cannot have a + // nested-name-specifier unless it is an explicit instantiation + // or an explicit specialization. + // Per C++ [dcl.enum]p1, an opaque-enum-declaration can't either. + Diag(SS.getBeginLoc(), diag::err_standalone_class_nested_name_specifier) + << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 : + DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 : + DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 : + DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4) + << SS.getRange(); + return 0; + } + + // Track whether this decl-specifier declares anything. + bool DeclaresAnything = true; + + // Handle anonymous struct definitions. if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { if (!Record->getDeclName() && Record->isCompleteDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { @@ -3038,13 +3129,11 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Record->getDeclContext()->isRecord()) return BuildAnonymousStructOrUnion(S, DS, AS, Record); - Diag(DS.getLocStart(), diag::ext_no_declarators) - << DS.getSourceRange(); - emittedWarning = true; + DeclaresAnything = false; } } - // Check for Microsoft C extension: anonymous struct. + // Check for Microsoft C extension: anonymous struct member. if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus && CurContext->isRecord() && DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) { @@ -3061,70 +3150,83 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, return BuildMicrosoftCAnonymousStruct(S, DS, Record); } } - - if (getLangOpts().CPlusPlus && + + // Skip all the checks below if we have a type error. + if (DS.getTypeSpecType() == DeclSpec::TST_error || + (TagD && TagD->isInvalidDecl())) + return TagD; + + if (getLangOpts().CPlusPlus && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) if (EnumDecl *Enum = dyn_cast_or_null<EnumDecl>(Tag)) if (Enum->enumerator_begin() == Enum->enumerator_end() && - !Enum->getIdentifier() && !Enum->isInvalidDecl()) { - Diag(Enum->getLocation(), diag::ext_no_declarators) - << DS.getSourceRange(); - emittedWarning = true; - } + !Enum->getIdentifier() && !Enum->isInvalidDecl()) + DeclaresAnything = false; - // Skip all the checks below if we have a type error. - if (DS.getTypeSpecType() == DeclSpec::TST_error) return TagD; - if (!DS.isMissingDeclaratorOk()) { - // Warn about typedefs of enums without names, since this is an - // extension in both Microsoft and GNU. - if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef && - Tag && isa<EnumDecl>(Tag)) { + // Customize diagnostic for a typedef missing a name. + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) Diag(DS.getLocStart(), diag::ext_typedef_without_a_name) << DS.getSourceRange(); - return Tag; - } - - Diag(DS.getLocStart(), diag::ext_no_declarators) - << DS.getSourceRange(); - emittedWarning = true; + else + DeclaresAnything = false; } - // We're going to complain about a bunch of spurious specifiers; - // only do this if we're declaring a tag, because otherwise we - // should be getting diag::ext_no_declarators. - if (emittedWarning || (TagD && TagD->isInvalidDecl())) + if (DS.isModulePrivateSpecified() && + Tag && Tag->getDeclContext()->isFunctionOrMethod()) + Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class) + << Tag->getTagKind() + << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc()); + + ActOnDocumentableDecl(TagD); + + // C 6.7/2: + // A declaration [...] shall declare at least a declarator [...], a tag, + // or the members of an enumeration. + // C++ [dcl.dcl]p3: + // [If there are no declarators], and except for the declaration of an + // unnamed bit-field, the decl-specifier-seq shall introduce one or more + // names into the program, or shall redeclare a name introduced by a + // previous declaration. + if (!DeclaresAnything) { + // In C, we allow this as a (popular) extension / bug. Don't bother + // producing further diagnostics for redundant qualifiers after this. + Diag(DS.getLocStart(), diag::ext_no_declarators) << DS.getSourceRange(); return TagD; + } + + // C++ [dcl.stc]p1: + // If a storage-class-specifier appears in a decl-specifier-seq, [...] the + // init-declarator-list of the declaration shall not be empty. + // C++ [dcl.fct.spec]p1: + // If a cv-qualifier appears in a decl-specifier-seq, the + // init-declarator-list of the declaration shall not be empty. + // + // Spurious qualifiers here appear to be valid in C. + unsigned DiagID = diag::warn_standalone_specifier; + if (getLangOpts().CPlusPlus) + DiagID = diag::ext_standalone_specifier; // Note that a linkage-specification sets a storage class, but // 'extern "C" struct foo;' is actually valid and not theoretically // useless. - if (DeclSpec::SCS scs = DS.getStorageClassSpec()) - if (!DS.isExternInLinkageSpec()) - Diag(DS.getStorageClassSpecLoc(), diag::warn_standalone_specifier) - << DeclSpec::getSpecifierName(scs); - - if (DS.isThreadSpecified()) - Diag(DS.getThreadSpecLoc(), diag::warn_standalone_specifier) << "__thread"; + if (DeclSpec::SCS SCS = DS.getStorageClassSpec()) + if (!DS.isExternInLinkageSpec() && SCS != DeclSpec::SCS_typedef) + Diag(DS.getStorageClassSpecLoc(), DiagID) + << DeclSpec::getSpecifierName(SCS); + + if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec()) + Diag(DS.getThreadStorageClassSpecLoc(), DiagID) + << DeclSpec::getSpecifierName(TSCS); if (DS.getTypeQualifiers()) { if (DS.getTypeQualifiers() & DeclSpec::TQ_const) - Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "const"; + Diag(DS.getConstSpecLoc(), DiagID) << "const"; if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) - Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "volatile"; + Diag(DS.getConstSpecLoc(), DiagID) << "volatile"; // Restrict is covered above. + if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) + Diag(DS.getAtomicSpecLoc(), DiagID) << "_Atomic"; } - if (DS.isInlineSpecified()) - Diag(DS.getInlineSpecLoc(), diag::warn_standalone_specifier) << "inline"; - if (DS.isVirtualSpecified()) - Diag(DS.getVirtualSpecLoc(), diag::warn_standalone_specifier) << "virtual"; - if (DS.isExplicitSpecified()) - Diag(DS.getExplicitSpecLoc(), diag::warn_standalone_specifier) <<"explicit"; - - if (DS.isModulePrivateSpecified() && - Tag && Tag->getDeclContext()->isFunctionOrMethod()) - Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class) - << Tag->getTagKind() - << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc()); // Warn about ignored type attributes, for example: // __attribute__((aligned)) struct A; @@ -3149,8 +3251,6 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } } - ActOnDocumentableDecl(TagD); - return TagD; } @@ -3270,10 +3370,16 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, /// a VarDecl::StorageClass. Any error reporting is up to the caller: /// illegal input values are mapped to SC_None. static StorageClass -StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec) { +StorageClassSpecToVarDeclStorageClass(const DeclSpec &DS) { + DeclSpec::SCS StorageClassSpec = DS.getStorageClassSpec(); + assert(StorageClassSpec != DeclSpec::SCS_typedef && + "Parser allowed 'typedef' as storage class VarDecl."); switch (StorageClassSpec) { case DeclSpec::SCS_unspecified: return SC_None; - case DeclSpec::SCS_extern: return SC_Extern; + case DeclSpec::SCS_extern: + if (DS.isExternInLinkageSpec()) + return SC_None; + return SC_Extern; case DeclSpec::SCS_static: return SC_Static; case DeclSpec::SCS_auto: return SC_Auto; case DeclSpec::SCS_register: return SC_Register; @@ -3285,25 +3391,6 @@ StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec) { llvm_unreachable("unknown storage class specifier"); } -/// StorageClassSpecToFunctionDeclStorageClass - Maps a DeclSpec::SCS to -/// a StorageClass. Any error reporting is up to the caller: -/// illegal input values are mapped to SC_None. -static StorageClass -StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec) { - switch (StorageClassSpec) { - case DeclSpec::SCS_unspecified: return SC_None; - case DeclSpec::SCS_extern: return SC_Extern; - case DeclSpec::SCS_static: return SC_Static; - case DeclSpec::SCS_private_extern: return SC_PrivateExtern; - // Illegal SCSs map to None: error reporting is up to the caller. - case DeclSpec::SCS_auto: // Fall through. - case DeclSpec::SCS_mutable: // Fall through. - case DeclSpec::SCS_register: // Fall through. - case DeclSpec::SCS_typedef: return SC_None; - } - llvm_unreachable("unknown storage class specifier"); -} - /// BuildAnonymousStructOrUnion - Handle the declaration of an /// anonymous structure or union. Anonymous unions are a C++ feature /// (C++ [class.union]) and a C11 feature; anonymous structures @@ -3362,18 +3449,23 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, if (DS.getTypeQualifiers()) { if (DS.getTypeQualifiers() & DeclSpec::TQ_const) Diag(DS.getConstSpecLoc(), diag::ext_anonymous_struct_union_qualified) - << Record->isUnion() << 0 + << Record->isUnion() << "const" << FixItHint::CreateRemoval(DS.getConstSpecLoc()); if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) - Diag(DS.getVolatileSpecLoc(), + Diag(DS.getVolatileSpecLoc(), diag::ext_anonymous_struct_union_qualified) - << Record->isUnion() << 1 + << Record->isUnion() << "volatile" << FixItHint::CreateRemoval(DS.getVolatileSpecLoc()); if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) - Diag(DS.getRestrictSpecLoc(), + Diag(DS.getRestrictSpecLoc(), diag::ext_anonymous_struct_union_qualified) - << Record->isUnion() << 2 + << Record->isUnion() << "restrict" << FixItHint::CreateRemoval(DS.getRestrictSpecLoc()); + if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) + Diag(DS.getAtomicSpecLoc(), + diag::ext_anonymous_struct_union_qualified) + << Record->isUnion() << "_Atomic" + << FixItHint::CreateRemoval(DS.getAtomicSpecLoc()); DS.ClearTypeQualifiers(); } @@ -3485,9 +3577,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, FieldCollector->Add(cast<FieldDecl>(Anon)); } else { DeclSpec::SCS SCSpec = DS.getStorageClassSpec(); - assert(SCSpec != DeclSpec::SCS_typedef && - "Parser allowed 'typedef' as storage class VarDecl."); - VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec); + VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(DS); if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here @@ -3495,15 +3585,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Invalid = true; SC = SC_None; } - SCSpec = DS.getStorageClassSpecAsWritten(); - VarDecl::StorageClass SCAsWritten - = StorageClassSpecToVarDeclStorageClass(SCSpec); Anon = VarDecl::Create(Context, Owner, DS.getLocStart(), Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), - TInfo, SC, SCAsWritten); + TInfo, SC); // Default-initialize the implicit variable. This initialization will be // trivial in almost all cases, except if a union member has an in-class @@ -4278,34 +4365,6 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, "Decl is not a locally-scoped decl!"); // Note that we have a locally-scoped external with this name. LocallyScopedExternCDecls[ND->getDeclName()] = ND; - - if (!Previous.isSingleResult()) - return; - - NamedDecl *PrevDecl = Previous.getFoundDecl(); - - // If there was a previous declaration of this entity, it may be in - // our identifier chain. Update the identifier chain with the new - // declaration. - if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) { - // The previous declaration was found on the identifer resolver - // chain, so remove it from its scope. - - if (S->isDeclScope(PrevDecl)) { - // Special case for redeclarations in the SAME scope. - // Because this declaration is going to be added to the identifier chain - // later, we should temporarily take it OFF the chain. - IdResolver.RemoveDecl(ND); - - } else { - // Find the scope for the original declaration. - while (S && !S->isDeclScope(PrevDecl)) - S = S->getParent(); - } - - if (S) - S->RemoveDecl(PrevDecl); - } } llvm::DenseMap<DeclarationName, NamedDecl *>::iterator @@ -4327,23 +4386,23 @@ Sema::findLocallyScopedExternCDecl(DeclarationName Name) { /// \brief Diagnose function specifiers on a declaration of an identifier that /// does not identify a function. -void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { +void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) { // FIXME: We should probably indicate the identifier in question to avoid // confusion for constructs like "inline int a(), b;" - if (D.getDeclSpec().isInlineSpecified()) - Diag(D.getDeclSpec().getInlineSpecLoc(), + if (DS.isInlineSpecified()) + Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function); - if (D.getDeclSpec().isVirtualSpecified()) - Diag(D.getDeclSpec().getVirtualSpecLoc(), + if (DS.isVirtualSpecified()) + Diag(DS.getVirtualSpecLoc(), diag::err_virtual_non_function); - if (D.getDeclSpec().isExplicitSpecified()) - Diag(D.getDeclSpec().getExplicitSpecLoc(), + if (DS.isExplicitSpecified()) + Diag(DS.getExplicitSpecLoc(), diag::err_explicit_non_function); - if (D.getDeclSpec().isNoreturnSpecified()) - Diag(D.getDeclSpec().getNoreturnSpecLoc(), + if (DS.isNoreturnSpecified()) + Diag(DS.getNoreturnSpecLoc(), diag::err_noreturn_non_function); } @@ -4360,10 +4419,8 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, Previous.clear(); } - DiagnoseFunctionSpecifiers(D); + DiagnoseFunctionSpecifiers(D.getDeclSpec()); - if (D.getDeclSpec().isThreadSpecified()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); if (D.getDeclSpec().isConstexprSpecified()) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) << 1; @@ -4557,7 +4614,7 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) { if (VarDecl *var = dyn_cast<VarDecl>(decl)) { // Thread-local variables cannot have lifetime. if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone && - var->isThreadSpecified()) { + var->getTLSKind()) { Diag(var->getLocation(), diag::err_arc_thread_ownership) << var->getType(); return true; @@ -4583,6 +4640,58 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { } } +/// Given that we are within the definition of the given function, +/// will that definition behave like C99's 'inline', where the +/// definition is discarded except for optimization purposes? +static bool isFunctionDefinitionDiscarded(Sema &S, FunctionDecl *FD) { + // Try to avoid calling GetGVALinkageForFunction. + + // All cases of this require the 'inline' keyword. + if (!FD->isInlined()) return false; + + // This is only possible in C++ with the gnu_inline attribute. + if (S.getLangOpts().CPlusPlus && !FD->hasAttr<GNUInlineAttr>()) + return false; + + // Okay, go ahead and call the relatively-more-expensive function. + +#ifndef NDEBUG + // AST quite reasonably asserts that it's working on a function + // definition. We don't really have a way to tell it that we're + // currently defining the function, so just lie to it in +Asserts + // builds. This is an awful hack. + FD->setLazyBody(1); +#endif + + bool isC99Inline = (S.Context.GetGVALinkageForFunction(FD) == GVA_C99Inline); + +#ifndef NDEBUG + FD->setLazyBody(0); +#endif + + return isC99Inline; +} + +static bool shouldConsiderLinkage(const VarDecl *VD) { + const DeclContext *DC = VD->getDeclContext()->getRedeclContext(); + if (DC->isFunctionOrMethod()) + return VD->hasExternalStorage(); + if (DC->isFileContext()) + return true; + if (DC->isRecord()) + return false; + llvm_unreachable("Unexpected context"); +} + +static bool shouldConsiderLinkage(const FunctionDecl *FD) { + const DeclContext *DC = FD->getDeclContext()->getRedeclContext(); + if (DC->isFileContext() || DC->isFunctionOrMethod()) + return true; + if (DC->isRecord()) + return false; + llvm_unreachable("Unexpected context"); +} + NamedDecl* Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, @@ -4591,12 +4700,10 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, DeclarationName Name = GetNameForDeclarator(D).getName(); DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); - assert(SCSpec != DeclSpec::SCS_typedef && - "Parser allowed 'typedef' as storage class VarDecl."); - VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec); + VarDecl::StorageClass SC = + StorageClassSpecToVarDeclStorageClass(D.getDeclSpec()); - if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16) - { + if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16) { // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and // half array type (unless the cl_khr_fp16 extension is enabled). if (Context.getBaseElementType(R)->isHalfType()) { @@ -4612,9 +4719,16 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.setInvalidType(); SC = SC_None; } - SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); - VarDecl::StorageClass SCAsWritten - = StorageClassSpecToVarDeclStorageClass(SCSpec); + + // C++11 [dcl.stc]p4: + // When thread_local is applied to a variable of block scope the + // storage-class-specifier static is implied if it does not appear + // explicitly. + // Core issue: 'static' is not implied if the variable is declared 'extern'. + if (SCSpec == DeclSpec::SCS_unspecified && + D.getDeclSpec().getThreadStorageClassSpec() == + DeclSpec::TSCS_thread_local && DC->isFunctionOrMethod()) + SC = SC_Static; IdentifierInfo *II = Name.getAsIdentifierInfo(); if (!II) { @@ -4623,7 +4737,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, return 0; } - DiagnoseFunctionSpecifiers(D); + DiagnoseFunctionSpecifiers(D.getDeclSpec()); if (!DC->isRecord() && S->getFnParent() == 0) { // C99 6.9p2: The storage-class specifiers auto and register shall not @@ -4645,7 +4759,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // OpenCL __local address space. if (R.getAddressSpace() == LangAS::opencl_local) { SC = SC_OpenCLWorkGroupLocal; - SCAsWritten = SC_OpenCLWorkGroupLocal; } // OpenCL v1.2 s6.9.b p4: @@ -4678,7 +4791,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (!getLangOpts().CPlusPlus) { NewVD = VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), II, - R, TInfo, SC, SCAsWritten); + R, TInfo, SC); if (D.isInvalidType()) NewVD->setInvalidDecl(); @@ -4689,8 +4802,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); - } else if (SC == SC_None) - SC = SC_Static; + } } if (SC == SC_Static && CurContext->isRecord()) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) { @@ -4748,12 +4860,11 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewVD = VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), II, - R, TInfo, SC, SCAsWritten); + R, TInfo, SC); // If this decl has an auto type in need of deduction, make a note of the // Decl so we can diagnose uses of it in its own initializer. - if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && - R->getContainedAutoType()) + if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType()) ParsingInitForAutoVars.insert(NewVD); if (D.isInvalidType() || Invalid) @@ -4775,13 +4886,35 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // lexical context will be different from the semantic context. NewVD->setLexicalDeclContext(CurContext); - if (D.getDeclSpec().isThreadSpecified()) { + if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) { if (NewVD->hasLocalStorage()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global); + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_thread_non_global) + << DeclSpec::getSpecifierName(TSCS); else if (!Context.getTargetInfo().isTLSSupported()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_unsupported); + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_thread_unsupported); else - NewVD->setThreadSpecified(true); + NewVD->setTSCSpec(TSCS); + } + + // C99 6.7.4p3 + // An inline definition of a function with external linkage shall + // not contain a definition of a modifiable object with static or + // thread storage duration... + // We only apply this when the function is required to be defined + // elsewhere, i.e. when the function is not 'extern inline'. Note + // that a local variable with thread storage duration still has to + // be marked 'static'. Also note that it's possible to get these + // semantics in C++ using __attribute__((gnu_inline)). + if (SC == SC_Static && S->getFnParent() != 0 && + !NewVD->getType().isConstQualified()) { + FunctionDecl *CurFD = getCurFunctionDecl(); + if (CurFD && isFunctionDefinitionDiscarded(*this, CurFD)) { + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::warn_static_local_in_extern_inline); + MaybeSuggestAddingStaticToDecl(CurFD); + } } if (D.getDeclSpec().isModulePrivateSpecified()) { @@ -4811,7 +4944,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, (NewVD->hasAttr<CUDASharedAttr>() || NewVD->hasAttr<CUDAConstantAttr>())) { NewVD->setStorageClass(SC_Static); - NewVD->setStorageClassAsWritten(SC_Static); } } @@ -4861,7 +4993,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new // declaration has linkage). - FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(), + FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewVD), isExplicitSpecialization); if (!getLangOpts().CPlusPlus) { @@ -5004,30 +5136,42 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) { template<typename T> static bool mayConflictWithNonVisibleExternC(const T *ND) { - return ND->isExternC() || ND->getDeclContext()->isTranslationUnit(); + const DeclContext *DC = ND->getDeclContext(); + if (DC->getRedeclContext()->isTranslationUnit()) + return true; + + // We know that is the first decl we see, other than function local + // extern C ones. If this is C++ and the decl is not in a extern C context + // it cannot have C language linkage. Avoid calling isExternC in that case. + // We need to this because of code like + // + // namespace { struct bar {}; } + // auto foo = bar(); + // + // This code runs before the init of foo is set, and therefore before + // the type of foo is known. Not knowing the type we cannot know its linkage + // unless it is in an extern C block. + if (!ND->isInExternCContext()) { + const ASTContext &Context = ND->getASTContext(); + if (Context.getLangOpts().CPlusPlus) + return false; + } + + return ND->isExternC(); } -/// \brief Perform semantic checking on a newly-created variable -/// declaration. -/// -/// This routine performs all of the type-checking required for a -/// variable declaration once it has been built. It is used both to -/// check variables after they have been parsed and their declarators -/// have been translated into a declaration, and to check variables -/// that have been instantiated from a template. -/// -/// Sets NewVD->isInvalidDecl() if an error was encountered. -/// -/// Returns true if the variable declaration is a redeclaration. -bool Sema::CheckVariableDeclaration(VarDecl *NewVD, - LookupResult &Previous) { +void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { // If the decl is already known invalid, don't check it. if (NewVD->isInvalidDecl()) - return false; + return; TypeSourceInfo *TInfo = NewVD->getTypeSourceInfo(); QualType T = TInfo->getType(); + // Defer checking an 'auto' type until its initializer is attached. + if (T->isUndeducedType()) + return; + if (T->isObjCObjectType()) { Diag(NewVD->getLocation(), diag::err_statically_allocated_object) << FixItHint::CreateInsertion(NewVD->getLocation(), "*"); @@ -5042,16 +5186,26 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, if (NewVD->hasLocalStorage() && T.getAddressSpace() != 0) { Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl); NewVD->setInvalidDecl(); - return false; + return; } + // OpenCL v1.2 s6.5 - All program scope variables must be declared in the + // __constant address space. + if (getLangOpts().OpenCL && NewVD->isFileVarDecl() + && T.getAddressSpace() != LangAS::opencl_constant + && !T->isSamplerT()){ + Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space); + NewVD->setInvalidDecl(); + return; + } + // OpenCL v1.2 s6.8 -- The static qualifier is valid only in program // scope. if ((getLangOpts().OpenCLVersion >= 120) && NewVD->isStaticLocal()) { Diag(NewVD->getLocation(), diag::err_static_function_scope); NewVD->setInvalidDecl(); - return false; + return; } if (NewVD->hasLocalStorage() && T.isObjCGCWeak() @@ -5092,7 +5246,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage) << SizeRange; NewVD->setInvalidDecl(); - return false; + return; } if (FixedTInfo == 0) { @@ -5101,7 +5255,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, else Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage); NewVD->setInvalidDecl(); - return false; + return; } Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); @@ -5109,46 +5263,94 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, NewVD->setTypeSourceInfo(FixedTInfo); } - if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) { - // Since we did not find anything by this name, look for a non-visible - // extern "C" declaration with the same name. - llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos - = findLocallyScopedExternCDecl(NewVD->getDeclName()); - if (Pos != LocallyScopedExternCDecls.end()) - Previous.addDecl(Pos->second); - } - - // Filter out any non-conflicting previous declarations. - filterNonConflictingPreviousDecls(Context, NewVD, Previous); - - if (T->isVoidType() && !NewVD->hasExternalStorage()) { + if (T->isVoidType() && NewVD->isThisDeclarationADefinition()) { Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type) << T; NewVD->setInvalidDecl(); - return false; + return; } if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) { Diag(NewVD->getLocation(), diag::err_block_on_nonlocal); NewVD->setInvalidDecl(); - return false; + return; } if (isVM && NewVD->hasAttr<BlocksAttr>()) { Diag(NewVD->getLocation(), diag::err_block_on_vm); NewVD->setInvalidDecl(); - return false; + return; } if (NewVD->isConstexpr() && !T->isDependentType() && RequireLiteralType(NewVD->getLocation(), T, diag::err_constexpr_var_non_literal)) { + // Can't perform this check until the type is deduced. NewVD->setInvalidDecl(); + return; + } +} + +/// \brief Perform semantic checking on a newly-created variable +/// declaration. +/// +/// This routine performs all of the type-checking required for a +/// variable declaration once it has been built. It is used both to +/// check variables after they have been parsed and their declarators +/// have been translated into a declaration, and to check variables +/// that have been instantiated from a template. +/// +/// Sets NewVD->isInvalidDecl() if an error was encountered. +/// +/// Returns true if the variable declaration is a redeclaration. +bool Sema::CheckVariableDeclaration(VarDecl *NewVD, + LookupResult &Previous) { + CheckVariableDeclarationType(NewVD); + + // If the decl is already known invalid, don't check it. + if (NewVD->isInvalidDecl()) return false; + + // If we did not find anything by this name, look for a non-visible + // extern "C" declaration with the same name. + // + // Clang has a lot of problems with extern local declarations. + // The actual standards text here is: + // + // C++11 [basic.link]p6: + // The name of a function declared in block scope and the name + // of a variable declared by a block scope extern declaration + // have linkage. If there is a visible declaration of an entity + // with linkage having the same name and type, ignoring entities + // declared outside the innermost enclosing namespace scope, the + // block scope declaration declares that same entity and + // receives the linkage of the previous declaration. + // + // C11 6.2.7p4: + // For an identifier with internal or external linkage declared + // in a scope in which a prior declaration of that identifier is + // visible, if the prior declaration specifies internal or + // external linkage, the type of the identifier at the later + // declaration becomes the composite type. + // + // The most important point here is that we're not allowed to + // update our understanding of the type according to declarations + // not in scope. + bool PreviousWasHidden = false; + if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) { + llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos + = findLocallyScopedExternCDecl(NewVD->getDeclName()); + if (Pos != LocallyScopedExternCDecls.end()) { + Previous.addDecl(Pos->second); + PreviousWasHidden = true; + } } + // Filter out any non-conflicting previous declarations. + filterNonConflictingPreviousDecls(Context, NewVD, Previous); + if (!Previous.empty()) { - MergeVarDecl(NewVD, Previous); + MergeVarDecl(NewVD, Previous, PreviousWasHidden); return true; } return false; @@ -5473,7 +5675,10 @@ static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef, D.setInvalidType(); break; case DeclSpec::SCS_unspecified: break; - case DeclSpec::SCS_extern: return SC_Extern; + case DeclSpec::SCS_extern: + if (D.getDeclSpec().isExternInLinkageSpec()) + return SC_None; + return SC_Extern; case DeclSpec::SCS_static: { if (SemaRef.CurContext->getRedeclContext()->isFunctionOrMethod()) { // C99 6.7.1p5: @@ -5504,9 +5709,6 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, FunctionDecl *NewFD = 0; bool isInline = D.getDeclSpec().isInlineSpecified(); - DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); - FunctionDecl::StorageClass SCAsWritten - = StorageClassSpecToFunctionDeclStorageClass(SCSpec); if (!SemaRef.getLangOpts().CPlusPlus) { // Determine whether the function was written with a @@ -5520,8 +5722,8 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getLocStart(), NameInfo, R, - TInfo, SC, SCAsWritten, isInline, - HasPrototype); + TInfo, SC, isInline, + HasPrototype, false); if (D.isInvalidType()) NewFD->setInvalidDecl(); @@ -5588,7 +5790,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, return FunctionDecl::Create(SemaRef.Context, DC, D.getLocStart(), D.getIdentifierLoc(), Name, R, TInfo, - SC, SCAsWritten, isInline, + SC, isInline, /*hasPrototype=*/true, isConstexpr); } @@ -5619,36 +5821,21 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, return 0; } - bool isStatic = SC == SC_Static; - - // [class.free]p1: - // Any allocation function for a class T is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_New || - Name.getCXXOverloadedOperator() == OO_Array_New) - isStatic = true; - - // [class.free]p6 Any deallocation function for a class X is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_Delete || - Name.getCXXOverloadedOperator() == OO_Array_Delete) - isStatic = true; - - IsVirtualOkay = !isStatic; - // This is a C++ method declaration. - return CXXMethodDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC), - D.getLocStart(), NameInfo, R, - TInfo, isStatic, SCAsWritten, isInline, - isConstexpr, SourceLocation()); - + CXXMethodDecl *Ret = CXXMethodDecl::Create(SemaRef.Context, + cast<CXXRecordDecl>(DC), + D.getLocStart(), NameInfo, R, + TInfo, SC, isInline, + isConstexpr, SourceLocation()); + IsVirtualOkay = !Ret->isStatic(); + return Ret; } else { // Determine whether the function was written with a // prototype. This true when: // - we're in C++ (where every function has a prototype), return FunctionDecl::Create(SemaRef.Context, DC, D.getLocStart(), - NameInfo, R, TInfo, SC, SCAsWritten, isInline, + NameInfo, R, TInfo, SC, isInline, true/*HasPrototype*/, isConstexpr); } } @@ -5683,8 +5870,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, DeclarationName Name = NameInfo.getName(); FunctionDecl::StorageClass SC = getFunctionStorageClass(*this, D); - if (D.getDeclSpec().isThreadSpecified()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_invalid_thread) + << DeclSpec::getSpecifierName(TSCS); // Do not allow returning a objc interface by-value. if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) { @@ -5877,6 +6066,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Okay: Add virtual to the method. NewFD->setVirtualAsWritten(true); } + + if (getLangOpts().CPlusPlus1y && + NewFD->getResultType()->isUndeducedType()) + Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual); } // C++ [dcl.fct.spec]p3: @@ -6002,7 +6195,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // Filter out previous declarations that don't match the scope. - FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), + FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewFD), isExplicitSpecialization || isFunctionTemplateSpecialization); @@ -6214,7 +6407,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // A storage-class-specifier shall not be specified in an explicit // specialization (14.7.3) if (SC != SC_None) { - if (SC != NewFD->getStorageClass()) + if (SC != NewFD->getTemplateSpecializationInfo()->getTemplate()->getTemplatedDecl()->getStorageClass()) Diag(NewFD->getLocation(), diag::err_explicit_specialization_inconsistent_storage_class) << SC @@ -6381,15 +6574,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, EPI.Variadic = true; EPI.ExtInfo = FT->getExtInfo(); - QualType R = Context.getFunctionType(FT->getResultType(), - ArrayRef<QualType>(), - EPI); + QualType R = Context.getFunctionType(FT->getResultType(), None, EPI); NewFD->setType(R); } // If there's a #pragma GCC visibility in scope, and this isn't a class // member, set the visibility of this function. - if (NewFD->hasExternalLinkage() && !DC->isRecord()) + if (!DC->isRecord() && NewFD->hasExternalLinkage()) AddPushedVisibilityAttribute(NewFD); // If there's a #pragma clang arc_cf_code_audited in scope, consider @@ -6527,8 +6718,11 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // there's no more work to do here; we'll just add the new // function to the scope. if (!AllowOverloadingOfFunction(Previous, Context)) { - Redeclaration = true; - OldDecl = Previous.getFoundDecl(); + NamedDecl *Candidate = Previous.getFoundDecl(); + if (shouldLinkPossiblyHiddenDecl(Candidate, NewFD)) { + Redeclaration = true; + OldDecl = Candidate; + } } else { switch (CheckOverload(S, NewFD, Previous, OldDecl, /*NewIsUsingDecl*/ false)) { @@ -6570,9 +6764,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // // This needs to be delayed until we know whether this is an out-of-line // definition of a static member function. + // + // This rule is not present in C++1y, so we produce a backwards + // compatibility warning whenever it happens in C++11. CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD); - if (MD && MD->isConstexpr() && !MD->isStatic() && - !isa<CXXConstructorDecl>(MD) && + if (!getLangOpts().CPlusPlus1y && MD && MD->isConstexpr() && + !MD->isStatic() && !isa<CXXConstructorDecl>(MD) && (MD->getTypeQualifiers() & Qualifiers::Const) == 0) { CXXMethodDecl *OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl); if (FunctionTemplateDecl *OldTD = @@ -6587,6 +6784,18 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, ArrayRef<QualType>(FPT->arg_type_begin(), FPT->getNumArgs()), EPI)); + + // Warn that we did this, if we're not performing template instantiation. + // In that case, we'll have warned already when the template was defined. + if (ActiveTemplateInstantiations.empty()) { + SourceLocation AddConstLoc; + if (FunctionTypeLoc FTL = MD->getTypeSourceInfo()->getTypeLoc() + .IgnoreParens().getAs<FunctionTypeLoc>()) + AddConstLoc = PP.getLocForEndOfToken(FTL.getRParenLoc()); + + Diag(MD->getLocation(), diag::warn_cxx1y_compat_constexpr_not_const) + << FixItHint::CreateInsertion(AddConstLoc, " const"); + } } } @@ -6730,7 +6939,8 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // If this function is declared as being extern "C", then check to see if // the function returns a UDT (class, struct, or union type) that is not C // compatible, and if it does, warn the user. - if (NewFD->isExternC()) { + // But, issue any diagnostic on the first declaration only. + if (NewFD->isExternC() && Previous.empty()) { QualType R = NewFD->getResultType(); if (R->isIncompleteType() && !R->isVoidType()) Diag(NewFD->getLocation(), diag::warn_return_value_udt_incomplete) @@ -7006,6 +7216,14 @@ namespace { Visit(Base); } + void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + if (E->getNumArgs() > 0) + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->getArg(0))) + HandleDeclRefExpr(DRE); + + Inherited::VisitCXXOperatorCallExpr(E); + } + void VisitUnaryOperator(UnaryOperator *E) { // For POD record types, addresses of its own members are well-defined. if (E->getOpcode() == UO_AddrOf && isRecordType && @@ -7015,7 +7233,7 @@ namespace { return; } Inherited::VisitUnaryOperator(E); - } + } void VisitObjCMessageExpr(ObjCMessageExpr *E) { return; } @@ -7099,10 +7317,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. - AutoType *Auto = 0; - if (TypeMayContainAuto && - (Auto = VDecl->getType()->getContainedAutoType()) && - !Auto->isDeduced()) { + if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) { Expr *DeduceInit = Init; // Initializer could be a C++ direct-initializer. Deduction only works if it // contains exactly one expression. @@ -7140,19 +7355,18 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, Init = Result.take(); DefaultedToAuto = true; } - - TypeSourceInfo *DeducedType = 0; + + QualType DeducedType; if (DeduceAutoType(VDecl->getTypeSourceInfo(), DeduceInit, DeducedType) == DAR_Failed) DiagnoseAutoDeductionFailure(VDecl, DeduceInit); - if (!DeducedType) { + if (DeducedType.isNull()) { RealDecl->setInvalidDecl(); return; } - VDecl->setTypeSourceInfo(DeducedType); - VDecl->setType(DeducedType->getType()); - VDecl->ClearLinkageCache(); - + VDecl->setType(DeducedType); + assert(VDecl->isLinkageValid()); + // In ARC, infer lifetime. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl)) VDecl->setInvalidDecl(); @@ -7162,8 +7376,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // We only want to warn outside of template instantiations, though: // inside a template, the 'id' could have come from a parameter. if (ActiveTemplateInstantiations.empty() && !DefaultedToAuto && - DeducedType->getType()->isObjCIdType()) { - SourceLocation Loc = DeducedType->getTypeLoc().getBeginLoc(); + DeducedType->isObjCIdType()) { + SourceLocation Loc = + VDecl->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); Diag(Loc, diag::warn_auto_var_is_id) << VDecl->getDeclName() << DeduceInit->getSourceRange(); } @@ -7171,7 +7386,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // If this is a redeclaration, check that the type we just deduced matches // the previously declared type. if (VarDecl *Old = VDecl->getPreviousDecl()) - MergeVarDeclTypes(VDecl, Old); + MergeVarDeclTypes(VDecl, Old, /*OldWasHidden*/ false); + + // Check the deduced type is valid for a variable declaration. + CheckVariableDeclarationType(VDecl); + if (VDecl->isInvalidDecl()) + return; } if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) { @@ -7277,15 +7497,13 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, : InitializationKind::CreateCopy(VDecl->getLocation(), Init->getLocStart()); - Expr **Args = &Init; - unsigned NumArgs = 1; - if (CXXDirectInit) { - Args = CXXDirectInit->getExprs(); - NumArgs = CXXDirectInit->getNumExprs(); - } - InitializationSequence InitSeq(*this, Entity, Kind, Args, NumArgs); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(Args, NumArgs), &DclT); + MultiExprArg Args = Init; + if (CXXDirectInit) + Args = MultiExprArg(CXXDirectInit->getExprs(), + CXXDirectInit->getNumExprs()); + + InitializationSequence InitSeq(*this, Entity, Kind, Args); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; @@ -7446,7 +7664,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, } // Suggest adding 'constexpr' in C++11 for literal types. - } else if (getLangOpts().CPlusPlus11 && DclT->isLiteralType()) { + } else if (getLangOpts().CPlusPlus11 && DclT->isLiteralType(Context)) { Diag(VDecl->getLocation(), diag::err_in_class_initializer_literal_type) << DclT << Init->getSourceRange() << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr "); @@ -7458,14 +7676,28 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, VDecl->setInvalidDecl(); } } else if (VDecl->isFileVarDecl()) { - if (VDecl->getStorageClassAsWritten() == SC_Extern && + if (VDecl->getStorageClass() == SC_Extern && (!getLangOpts().CPlusPlus || - !Context.getBaseElementType(VDecl->getType()).isConstQualified())) + !(Context.getBaseElementType(VDecl->getType()).isConstQualified() || + VDecl->isExternC()))) Diag(VDecl->getLocation(), diag::warn_extern_init); // C99 6.7.8p4. All file scoped initializers need to be constant. if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) CheckForConstantInitializer(Init, DclT); + else if (VDecl->getTLSKind() == VarDecl::TLS_Static && + !VDecl->isInvalidDecl() && !DclT->isDependentType() && + !Init->isValueDependent() && !VDecl->isConstexpr() && + !Init->isConstantInitializer( + Context, VDecl->getType()->isReferenceType())) { + // GNU C++98 edits for __thread, [basic.start.init]p4: + // An object of thread storage duration shall not require dynamic + // initialization. + // FIXME: Need strict checking here. + Diag(VDecl->getLocation(), diag::err_thread_dynamic_init); + if (getLangOpts().CPlusPlus11) + Diag(VDecl->getLocation(), diag::note_use_thread_local); + } } // We will represent direct-initialization similarly to copy-initialization: @@ -7720,9 +7952,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); InitializationKind Kind = InitializationKind::CreateDefault(Var->getLocation()); - - InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); - ExprResult Init = InitSeq.Perform(*this, Entity, Kind, MultiExprArg()); + + InitializationSequence InitSeq(*this, Entity, Kind, None); + ExprResult Init = InitSeq.Perform(*this, Entity, Kind, None); if (Init.isInvalid()) Var->setInvalidDecl(); else if (Init.get()) { @@ -7747,7 +7979,7 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) { // for-range-declaration cannot be given a storage class specifier. int Error = -1; - switch (VD->getStorageClassAsWritten()) { + switch (VD->getStorageClass()) { case SC_None: break; case SC_Extern: @@ -7811,6 +8043,16 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var; } + if (var->getTLSKind() == VarDecl::TLS_Static && + var->getType().isDestructedType()) { + // GNU C++98 edits for __thread, [basic.start.term]p3: + // The type of an object with thread storage duration shall not + // have a non-trivial destructor. + Diag(var->getLocation(), diag::err_thread_nontrivial_dtor); + if (getLangOpts().CPlusPlus11) + Diag(var->getLocation(), diag::note_use_thread_local); + } + // All the following checks are C++ only. if (!getLangOpts().CPlusPlus) return; @@ -7825,6 +8067,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // Regardless, we don't want to ignore array nesting when // constructing this copy. if (type->isStructureOrClassType()) { + EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated); SourceLocation poi = var->getLocation(); Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi); ExprResult result @@ -7896,7 +8139,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { const DeclContext *DC = VD->getDeclContext(); // If there's a #pragma GCC visibility in scope, and this isn't a class // member, set the visibility of this variable. - if (VD->hasExternalLinkage() && !DC->isRecord()) + if (!DC->isRecord() && VD->hasExternalLinkage()) AddPushedVisibilityAttribute(VD); if (VD->isFileVarDecl()) @@ -7955,7 +8198,7 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, getASTContext().addUnnamedTag(Tag); return BuildDeclaratorGroup(Decls.data(), Decls.size(), - DS.getTypeSpecType() == DeclSpec::TST_auto); + DS.containsPlaceholderType()); } /// BuildDeclaratorGroup - convert a list of declarations into a declaration @@ -7980,8 +8223,8 @@ Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls, // Don't reissue diagnostics when instantiating a template. if (AT && D->isInvalidDecl()) break; - if (AT && AT->isDeduced()) { - QualType U = AT->getDeducedType(); + QualType U = AT ? AT->getDeducedType() : QualType(); + if (!U.isNull()) { CanQualType UCanon = Context.getCanonicalType(U); if (Deduced.isNull()) { Deduced = U; @@ -7990,6 +8233,7 @@ Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls, } else if (DeducedCanon != UCanon) { Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_auto_different_deductions) + << (AT->isDecltypeAuto() ? 1 : 0) << Deduced << DeducedDecl->getDeclName() << U << D->getDeclName() << DeducedDecl->getInit()->getSourceRange() @@ -8060,27 +8304,25 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. // C++03 [dcl.stc]p2 also permits 'auto'. VarDecl::StorageClass StorageClass = SC_None; - VarDecl::StorageClass StorageClassAsWritten = SC_None; if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { StorageClass = SC_Register; - StorageClassAsWritten = SC_Register; } else if (getLangOpts().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_auto) { StorageClass = SC_Auto; - StorageClassAsWritten = SC_Auto; } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { Diag(DS.getStorageClassSpecLoc(), diag::err_invalid_storage_class_in_func_decl); D.getMutableDeclSpec().ClearStorageClassSpecs(); } - if (D.getDeclSpec().isThreadSpecified()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); - if (D.getDeclSpec().isConstexprSpecified()) - Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) + if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec()) + Diag(DS.getThreadStorageClassSpecLoc(), diag::err_invalid_thread) + << DeclSpec::getSpecifierName(TSCS); + if (DS.isConstexprSpecified()) + Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr) << 0; - DiagnoseFunctionSpecifiers(D); + DiagnoseFunctionSpecifiers(DS); TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType parmDeclType = TInfo->getType(); @@ -8140,7 +8382,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { D.getLocStart(), D.getIdentifierLoc(), II, parmDeclType, TInfo, - StorageClass, StorageClassAsWritten); + StorageClass); if (D.isInvalidType()) New->setInvalidDecl(); @@ -8179,7 +8421,7 @@ ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC, location for the unnamed parameters, embedding the parameter's type? */ ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, Loc, 0, T, Context.getTrivialTypeSourceInfo(T, Loc), - SC_None, SC_None, 0); + SC_None, 0); Param->setImplicit(); return Param; } @@ -8232,8 +8474,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, SourceLocation NameLoc, IdentifierInfo *Name, QualType T, TypeSourceInfo *TSInfo, - VarDecl::StorageClass StorageClass, - VarDecl::StorageClass StorageClassAsWritten) { + VarDecl::StorageClass StorageClass) { // In ARC, infer a lifetime qualifier for appropriate parameter types. if (getLangOpts().ObjCAutoRefCount && T.getObjCLifetime() == Qualifiers::OCL_None && @@ -8260,8 +8501,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name, Context.getAdjustedParameterType(T), TSInfo, - StorageClass, StorageClassAsWritten, - 0); + StorageClass, 0); // Parameters can not be abstract class types. // For record types, this is done by the AbstractClassUsageDiagnoser once @@ -8641,6 +8881,21 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD) { FD->setBody(Body); + if (getLangOpts().CPlusPlus1y && !FD->isInvalidDecl() && + !FD->isDependentContext()) { + if (FD->getResultType()->isUndeducedType()) { + // If the function has a deduced result type but contains no 'return' + // statements, the result type as written must be exactly 'auto', and + // the deduced result type is 'void'. + if (!FD->getResultType()->getAs<AutoType>()) { + Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto) + << FD->getResultType(); + FD->setInvalidDecl(); + } + Context.adjustDeducedFunctionResultType(FD, Context.VoidTy); + } + } + // The only way to be included in UndefinedButUsed is if there is an // ODR use before the definition. Avoid the expensive map lookup if this // is the first declaration. @@ -9248,6 +9503,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, TUK == TUK_Friend, isExplicitSpecialization, Invalid)) { + if (Kind == TTK_Enum) { + Diag(KWLoc, diag::err_enum_template); + return 0; + } + if (TemplateParams->size() > 0) { // This is a declaration or definition of a class template (which may // be a member of another template). @@ -9376,6 +9636,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // shouldn't be diagnosing. LookupName(Previous, S); + // When declaring or defining a tag, ignore ambiguities introduced + // by types using'ed into this scope. if (Previous.isAmbiguous() && (TUK == TUK_Definition || TUK == TUK_Declaration)) { LookupResult::Filter F = Previous.makeFilter(); @@ -9386,6 +9648,27 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } F.done(); } + + // C++11 [namespace.memdef]p3: + // If the name in a friend declaration is neither qualified nor + // a template-id and the declaration is a function or an + // elaborated-type-specifier, the lookup to determine whether + // the entity has been previously declared shall not consider + // any scopes outside the innermost enclosing namespace. + // + // Does it matter that this should be by scope instead of by + // semantic context? + if (!Previous.empty() && TUK == TUK_Friend) { + DeclContext *EnclosingNS = SearchDC->getEnclosingNamespaceContext(); + LookupResult::Filter F = Previous.makeFilter(); + while (F.hasNext()) { + NamedDecl *ND = F.next(); + DeclContext *DC = ND->getDeclContext()->getRedeclContext(); + if (DC->isFileContext() && !EnclosingNS->Encloses(ND->getDeclContext())) + F.erase(); + } + F.done(); + } // Note: there used to be some attempt at recovery here. if (Previous.isAmbiguous()) @@ -9743,7 +10026,8 @@ CreateNewDecl: // If this is an undefined enum, warn. if (TUK != TUK_Definition && !Invalid) { TagDecl *Def; - if (getLangOpts().CPlusPlus11 && cast<EnumDecl>(New)->isFixed()) { + if ((getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) && + cast<EnumDecl>(New)->isFixed()) { // C++0x: 7.2p2: opaque-enum-declaration. // Conflicts are diagnosed above. Do nothing. } @@ -10171,10 +10455,12 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, D.setInvalidType(); } - DiagnoseFunctionSpecifiers(D); + DiagnoseFunctionSpecifiers(D.getDeclSpec()); - if (D.getDeclSpec().isThreadSpecified()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_invalid_thread) + << DeclSpec::getSpecifierName(TSCS); // Check to see if this name was declared as a member previously NamedDecl *PrevDecl = 0; @@ -10382,8 +10668,8 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // FIXME: We need to pass in the attributes given an AST // representation, not a parser representation. if (D) { - // FIXME: What to pass instead of TUScope? - ProcessDeclAttributes(TUScope, NewFD, *D); + // FIXME: The current scope is almost... but not entirely... correct here. + ProcessDeclAttributes(getCurScope(), NewFD, *D); if (NewFD->hasAttrs()) CheckAlignasUnderalignment(NewFD); @@ -10587,8 +10873,8 @@ Decl *Sema::ActOnIvar(Scope *S, } /// ActOnLastBitfield - This routine handles synthesized bitfields rules for -/// class and class extensions. For every class @interface and class -/// extension @interface, if the last ivar is a bitfield of any type, +/// class and class extensions. For every class \@interface and class +/// extension \@interface, if the last ivar is a bitfield of any type, /// then add an implicit `char :0` ivar to the end of that interface. void Sema::ActOnLastBitfield(SourceLocation DeclLoc, SmallVectorImpl<Decl *> &AllIvarDecls) { @@ -11322,8 +11608,8 @@ struct DenseMapInfoDupKey { // Emits a warning when an element is implicitly set a value that // a previous element has already been set to. -static void CheckForDuplicateEnumValues(Sema &S, Decl **Elements, - unsigned NumElements, EnumDecl *Enum, +static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements, + EnumDecl *Enum, QualType EnumType) { if (S.Diags.getDiagnosticLevel(diag::warn_duplicate_enum_values, Enum->getLocation()) == @@ -11349,8 +11635,8 @@ static void CheckForDuplicateEnumValues(Sema &S, Decl **Elements, // Populate the EnumMap with all values represented by enum constants without // an initialier. - for (unsigned i = 0; i < NumElements; ++i) { - EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]); + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { + EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]); // Null EnumConstantDecl means a previous diagnostic has been emitted for // this constant. Skip this enum since it may be ill-formed. @@ -11370,7 +11656,7 @@ static void CheckForDuplicateEnumValues(Sema &S, Decl **Elements, } // Create vectors for any values that has duplicates. - for (unsigned i = 0; i < NumElements; ++i) { + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]); if (!ValidDuplicateEnum(ECD, Enum)) continue; @@ -11434,7 +11720,7 @@ static void CheckForDuplicateEnumValues(Sema &S, Decl **Elements, void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, SourceLocation RBraceLoc, Decl *EnumDeclX, - Decl **Elements, unsigned NumElements, + ArrayRef<Decl *> Elements, Scope *S, AttributeList *Attr) { EnumDecl *Enum = cast<EnumDecl>(EnumDeclX); QualType EnumType = Context.getTypeDeclType(Enum); @@ -11443,7 +11729,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ProcessDeclAttributeList(S, Enum, Attr); if (Enum->isDependentType()) { - for (unsigned i = 0; i != NumElements; ++i) { + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]); if (!ECD) continue; @@ -11470,7 +11756,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // Keep track of whether all elements have type int. bool AllElementsInt = true; - for (unsigned i = 0; i != NumElements; ++i) { + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]); if (!ECD) continue; // Already issued a diagnostic. @@ -11587,7 +11873,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // Loop over all of the enumerator constants, changing their types to match // the type of the enum if needed. - for (unsigned i = 0; i != NumElements; ++i) { + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]); if (!ECD) continue; // Already issued a diagnostic. @@ -11655,7 +11941,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, if (InFunctionDeclarator) DeclsInPrototypeScope.push_back(Enum); - CheckForDuplicateEnumValues(*this, Elements, NumElements, Enum, EnumType); + CheckForDuplicateEnumValues(*this, Elements, Enum, EnumType); // Now that the enum type is defined, ensure it's not been underaligned. if (Enum->hasAttrs()) @@ -11712,7 +11998,8 @@ void Sema::createImplicitModuleImport(SourceLocation Loc, Module *Mod) { Consumer.HandleImplicitImportDecl(ImportD); // Make the module visible. - PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc); + PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc, + /*Complain=*/false); } void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index c9ccf80191..7b3345a332 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -284,7 +284,7 @@ static bool mayBeSharedVariable(const Decl *D) { if (isa<FieldDecl>(D)) return true; if (const VarDecl *vd = dyn_cast<VarDecl>(D)) - return (vd->hasGlobalStorage() && !(vd->isThreadSpecified())); + return vd->hasGlobalStorage() && !vd->getTLSKind(); return false; } @@ -709,7 +709,7 @@ static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, // Check that all arguments are lockable objects. checkAttrArgsAreLockableObjs(S, D, Attr, Args); - if (Args.size() == 0) + if (Args.empty()) return false; return true; @@ -858,7 +858,7 @@ static bool checkLocksRequiredCommon(Sema &S, Decl *D, // check that all arguments are lockable objects checkAttrArgsAreLockableObjs(S, D, Attr, Args); - if (Args.size() == 0) + if (Args.empty()) return false; return true; @@ -1656,7 +1656,7 @@ static void handleTLSModelAttr(Sema &S, Decl *D, return; } - if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->isThreadSpecified()) { + if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->getTLSKind()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) << Attr.getName() << ExpectedTLSVar; return; @@ -2246,8 +2246,11 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, MergedObsoleted == Obsoleted) return NULL; + // Only create a new attribute if !Override, but we want to do + // the checking. if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced, - MergedDeprecated, MergedObsoleted)) { + MergedDeprecated, MergedObsoleted) && + !Override) { return ::new (Context) AvailabilityAttr(Range, Context, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable, Message, @@ -2799,6 +2802,15 @@ static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) { ParmType, Attr.getLoc())); } +static void handleEndianAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!dyn_cast<VarDecl>(D)) + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << "endian" + << 9; + StringRef EndianType = Attr.getParameterName()->getName(); + if (EndianType != "host" && EndianType != "device") + S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_endian) << EndianType; +} + SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name, unsigned AttrSpellingListIndex) { @@ -3988,6 +4000,22 @@ static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){ D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getRange(), S.Context)); } +static void handleOpenCLImageAccessAttr(Sema &S, Decl *D, const AttributeList &Attr){ + assert(!Attr.isInvalid()); + + Expr *E = Attr.getArg(0); + llvm::APSInt ArgNum(32); + if (E->isTypeDependent() || E->isValueDependent() || + !E->isIntegerConstantExpr(ArgNum, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << Attr.getName()->getName() << E->getSourceRange(); + return; + } + + D->addAttr(::new (S.Context) OpenCLImageAccessAttr( + Attr.getRange(), S.Context, ArgNum.getZExtValue())); +} + bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, const FunctionDecl *FD) { if (attr.isInvalid()) @@ -4678,7 +4706,6 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_IBOutletCollection: handleIBOutletCollection(S, D, Attr); break; case AttributeList::AT_AddressSpace: - case AttributeList::AT_OpenCLImageAccess: case AttributeList::AT_ObjCGC: case AttributeList::AT_VectorSize: case AttributeList::AT_NeonVectorType: @@ -4783,6 +4810,10 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_VecTypeHint: handleVecTypeHint(S, D, Attr); break; + case AttributeList::AT_Endian: + handleEndianAttr(S, D, Attr); + break; + case AttributeList::AT_InitPriority: handleInitPriorityAttr(S, D, Attr); break; @@ -4853,8 +4884,12 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_OpenCLKernel: handleOpenCLKernelAttr(S, D, Attr); break; + case AttributeList::AT_OpenCLImageAccess: + handleOpenCLImageAccessAttr(S, D, Attr); + break; // Microsoft attributes: + case AttributeList::AT_MsProperty: break; case AttributeList::AT_MsStruct: handleMsStructAttr(S, D, Attr); break; @@ -5061,8 +5096,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, NewFD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(), Loc, Loc, DeclarationName(II), FD->getType(), FD->getTypeSourceInfo(), - SC_None, SC_None, - false/*isInlineSpecified*/, + SC_None, false/*isInlineSpecified*/, FD->hasPrototype(), false/*isConstexprSpecified*/); NewD = NewFD; @@ -5087,8 +5121,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), VD->getInnerLocStart(), VD->getLocation(), II, VD->getType(), VD->getTypeSourceInfo(), - VD->getStorageClass(), - VD->getStorageClassAsWritten()); + VD->getStorageClass()); if (VD->getQualifier()) { VarDecl *NewVD = cast<VarDecl>(NewD); NewVD->setQualifierInfo(VD->getQualifierLoc()); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index f66509d177..e6a131a076 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -65,6 +65,7 @@ namespace { bool VisitDeclRefExpr(DeclRefExpr *DRE); bool VisitCXXThisExpr(CXXThisExpr *ThisE); bool VisitLambdaExpr(LambdaExpr *Lambda); + bool VisitPseudoObjectExpr(PseudoObjectExpr *POE); }; /// VisitExpr - Visit all of the children of this expression. @@ -115,6 +116,23 @@ namespace { << ThisE->getSourceRange(); } + bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *POE) { + bool Invalid = false; + for (PseudoObjectExpr::semantics_iterator + i = POE->semantics_begin(), e = POE->semantics_end(); i != e; ++i) { + Expr *E = *i; + + // Look through bindings. + if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) { + E = OVE->getSourceExpr(); + assert(E && "pseudo-object binding without source expression?"); + } + + Invalid |= Visit(E); + } + return Invalid; + } + bool CheckDefaultArgumentVisitor::VisitLambdaExpr(LambdaExpr *Lambda) { // C++11 [expr.lambda.prim]p13: // A lambda-expression appearing in a default argument shall not @@ -127,8 +145,9 @@ namespace { } } -void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, - CXXMethodDecl *Method) { +void +Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, + const CXXMethodDecl *Method) { // If we have an MSAny spec already, don't bother. if (!Method || ComputedEST == EST_MSAny) return; @@ -246,7 +265,7 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, Param); InitializationKind Kind = InitializationKind::CreateCopy(Param->getLocation(), EqualLoc); - InitializationSequence InitSeq(*this, Entity, Kind, &Arg, 1); + InitializationSequence InitSeq(*this, Entity, Kind, Arg); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Arg); if (Result.isInvalid()) return true; @@ -614,25 +633,11 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { unsigned NumParams = FD->getNumParams(); unsigned p; - bool IsLambda = FD->getOverloadedOperator() == OO_Call && - isa<CXXMethodDecl>(FD) && - cast<CXXMethodDecl>(FD)->getParent()->isLambda(); - // Find first parameter with a default argument for (p = 0; p < NumParams; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); - if (Param->hasDefaultArg()) { - // C++11 [expr.prim.lambda]p5: - // [...] Default arguments (8.3.6) shall not be specified in the - // parameter-declaration-clause of a lambda-declarator. - // - // FIXME: Core issue 974 strikes this sentence, we only provide an - // extension warning. - if (IsLambda) - Diag(Param->getLocation(), diag::ext_lambda_default_arguments) - << Param->getDefaultArgRange(); + if (Param->hasDefaultArg()) break; - } } // C++ [dcl.fct.default]p4: @@ -770,12 +775,13 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { } /// Check the given declaration statement is legal within a constexpr function -/// body. C++0x [dcl.constexpr]p3,p4. +/// body. C++11 [dcl.constexpr]p3,p4, and C++1y [dcl.constexpr]p3. /// -/// \return true if the body is OK, false if we have diagnosed a problem. +/// \return true if the body is OK (maybe only as an extension), false if we +/// have diagnosed a problem. static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, - DeclStmt *DS) { - // C++0x [dcl.constexpr]p3 and p4: + DeclStmt *DS, SourceLocation &Cxx1yLoc) { + // C++11 [dcl.constexpr]p3 and p4: // The definition of a constexpr function(p3) or constructor(p4) [...] shall // contain only for (DeclStmt::decl_iterator DclIt = DS->decl_begin(), @@ -786,6 +792,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, case Decl::UsingShadow: case Decl::UsingDirective: case Decl::UnresolvedUsingTypename: + case Decl::UnresolvedUsingValue: // - static_assert-declarations // - using-declarations, // - using-directives, @@ -809,20 +816,63 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, case Decl::Enum: case Decl::CXXRecord: - // As an extension, we allow the declaration (but not the definition) of - // classes and enumerations in all declarations, not just in typedef and - // alias declarations. - if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition()) { - SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_type_definition) + // C++1y allows types to be defined, not just declared. + if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition()) + SemaRef.Diag(DS->getLocStart(), + SemaRef.getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_constexpr_type_definition + : diag::ext_constexpr_type_definition) << isa<CXXConstructorDecl>(Dcl); - return false; - } continue; - case Decl::Var: - SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_var_declaration) + case Decl::EnumConstant: + case Decl::IndirectField: + case Decl::ParmVar: + // These can only appear with other declarations which are banned in + // C++11 and permitted in C++1y, so ignore them. + continue; + + case Decl::Var: { + // C++1y [dcl.constexpr]p3 allows anything except: + // a definition of a variable of non-literal type or of static or + // thread storage duration or for which no initialization is performed. + VarDecl *VD = cast<VarDecl>(*DclIt); + if (VD->isThisDeclarationADefinition()) { + if (VD->isStaticLocal()) { + SemaRef.Diag(VD->getLocation(), + diag::err_constexpr_local_var_static) + << isa<CXXConstructorDecl>(Dcl) + << (VD->getTLSKind() == VarDecl::TLS_Dynamic); + return false; + } + if (!VD->getType()->isDependentType() && + SemaRef.RequireLiteralType( + VD->getLocation(), VD->getType(), + diag::err_constexpr_local_var_non_literal_type, + isa<CXXConstructorDecl>(Dcl))) + return false; + if (!VD->hasInit()) { + SemaRef.Diag(VD->getLocation(), + diag::err_constexpr_local_var_no_init) + << isa<CXXConstructorDecl>(Dcl); + return false; + } + } + SemaRef.Diag(VD->getLocation(), + SemaRef.getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_constexpr_local_var + : diag::ext_constexpr_local_var) << isa<CXXConstructorDecl>(Dcl); - return false; + continue; + } + + case Decl::NamespaceAlias: + case Decl::Function: + // These are disallowed in C++11 and permitted in C++1y. Allow them + // everywhere as an extension. + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = DS->getLocStart(); + continue; default: SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_body_invalid_stmt) @@ -871,6 +921,124 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef, } } +/// Check the provided statement is allowed in a constexpr function +/// definition. +static bool +CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, + llvm::SmallVectorImpl<SourceLocation> &ReturnStmts, + SourceLocation &Cxx1yLoc) { + // - its function-body shall be [...] a compound-statement that contains only + switch (S->getStmtClass()) { + case Stmt::NullStmtClass: + // - null statements, + return true; + + case Stmt::DeclStmtClass: + // - static_assert-declarations + // - using-declarations, + // - using-directives, + // - typedef declarations and alias-declarations that do not define + // classes or enumerations, + if (!CheckConstexprDeclStmt(SemaRef, Dcl, cast<DeclStmt>(S), Cxx1yLoc)) + return false; + return true; + + case Stmt::ReturnStmtClass: + // - and exactly one return statement; + if (isa<CXXConstructorDecl>(Dcl)) { + // C++1y allows return statements in constexpr constructors. + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + return true; + } + + ReturnStmts.push_back(S->getLocStart()); + return true; + + case Stmt::CompoundStmtClass: { + // C++1y allows compound-statements. + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + + CompoundStmt *CompStmt = cast<CompoundStmt>(S); + for (CompoundStmt::body_iterator BodyIt = CompStmt->body_begin(), + BodyEnd = CompStmt->body_end(); BodyIt != BodyEnd; ++BodyIt) { + if (!CheckConstexprFunctionStmt(SemaRef, Dcl, *BodyIt, ReturnStmts, + Cxx1yLoc)) + return false; + } + return true; + } + + case Stmt::AttributedStmtClass: + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + return true; + + case Stmt::IfStmtClass: { + // C++1y allows if-statements. + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + + IfStmt *If = cast<IfStmt>(S); + if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts, + Cxx1yLoc)) + return false; + if (If->getElse() && + !CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts, + Cxx1yLoc)) + return false; + return true; + } + + case Stmt::WhileStmtClass: + case Stmt::DoStmtClass: + case Stmt::ForStmtClass: + case Stmt::CXXForRangeStmtClass: + case Stmt::ContinueStmtClass: + // C++1y allows all of these. We don't allow them as extensions in C++11, + // because they don't make sense without variable mutation. + if (!SemaRef.getLangOpts().CPlusPlus1y) + break; + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + for (Stmt::child_range Children = S->children(); Children; ++Children) + if (*Children && + !CheckConstexprFunctionStmt(SemaRef, Dcl, *Children, ReturnStmts, + Cxx1yLoc)) + return false; + return true; + + case Stmt::SwitchStmtClass: + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + case Stmt::BreakStmtClass: + // C++1y allows switch-statements, and since they don't need variable + // mutation, we can reasonably allow them in C++11 as an extension. + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + for (Stmt::child_range Children = S->children(); Children; ++Children) + if (*Children && + !CheckConstexprFunctionStmt(SemaRef, Dcl, *Children, ReturnStmts, + Cxx1yLoc)) + return false; + return true; + + default: + if (!isa<Expr>(S)) + break; + + // C++1y allows expression-statements. + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + return true; + } + + SemaRef.Diag(S->getLocStart(), diag::err_constexpr_body_invalid_stmt) + << isa<CXXConstructorDecl>(Dcl); + return false; +} + /// Check the body for the given constexpr function declaration only contains /// the permitted types of statement. C++11 [dcl.constexpr]p3,p4. /// @@ -891,43 +1059,24 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { return false; } + SmallVector<SourceLocation, 4> ReturnStmts; + // - its function-body shall be [...] a compound-statement that contains only + // [... list of cases ...] CompoundStmt *CompBody = cast<CompoundStmt>(Body); - - SmallVector<SourceLocation, 4> ReturnStmts; + SourceLocation Cxx1yLoc; for (CompoundStmt::body_iterator BodyIt = CompBody->body_begin(), BodyEnd = CompBody->body_end(); BodyIt != BodyEnd; ++BodyIt) { - switch ((*BodyIt)->getStmtClass()) { - case Stmt::NullStmtClass: - // - null statements, - continue; - - case Stmt::DeclStmtClass: - // - static_assert-declarations - // - using-declarations, - // - using-directives, - // - typedef declarations and alias-declarations that do not define - // classes or enumerations, - if (!CheckConstexprDeclStmt(*this, Dcl, cast<DeclStmt>(*BodyIt))) - return false; - continue; - - case Stmt::ReturnStmtClass: - // - and exactly one return statement; - if (isa<CXXConstructorDecl>(Dcl)) - break; - - ReturnStmts.push_back((*BodyIt)->getLocStart()); - continue; - - default: - break; - } + if (!CheckConstexprFunctionStmt(*this, Dcl, *BodyIt, ReturnStmts, Cxx1yLoc)) + return false; + } - Diag((*BodyIt)->getLocStart(), diag::err_constexpr_body_invalid_stmt) + if (Cxx1yLoc.isValid()) + Diag(Cxx1yLoc, + getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_constexpr_body_invalid_stmt + : diag::ext_constexpr_body_invalid_stmt) << isa<CXXConstructorDecl>(Dcl); - return false; - } if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Dcl)) { @@ -983,14 +1132,23 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { } } else { if (ReturnStmts.empty()) { - Diag(Dcl->getLocation(), diag::err_constexpr_body_no_return); - return false; + // C++1y doesn't require constexpr functions to contain a 'return' + // statement. We still do, unless the return type is void, because + // otherwise if there's no return statement, the function cannot + // be used in a core constant expression. + bool OK = getLangOpts().CPlusPlus1y && Dcl->getResultType()->isVoidType(); + Diag(Dcl->getLocation(), + OK ? diag::warn_cxx11_compat_constexpr_body_no_return + : diag::err_constexpr_body_no_return); + return OK; } if (ReturnStmts.size() > 1) { - Diag(ReturnStmts.back(), diag::err_constexpr_body_multiple_return); + Diag(ReturnStmts.back(), + getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_constexpr_body_multiple_return + : diag::ext_constexpr_body_multiple_return); for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I) Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return); - return false; } } @@ -1311,29 +1469,25 @@ void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases, (CXXBaseSpecifier**)(Bases), NumBases); } -static CXXRecordDecl *GetClassForType(QualType T) { - if (const RecordType *RT = T->getAs<RecordType>()) - return cast<CXXRecordDecl>(RT->getDecl()); - else if (const InjectedClassNameType *ICT = T->getAs<InjectedClassNameType>()) - return ICT->getDecl(); - else - return 0; -} - /// \brief Determine whether the type \p Derived is a C++ class that is /// derived from the type \p Base. bool Sema::IsDerivedFrom(QualType Derived, QualType Base) { if (!getLangOpts().CPlusPlus) return false; - CXXRecordDecl *DerivedRD = GetClassForType(Derived); + CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl(); if (!DerivedRD) return false; - CXXRecordDecl *BaseRD = GetClassForType(Base); + CXXRecordDecl *BaseRD = Base->getAsCXXRecordDecl(); if (!BaseRD) return false; - + + // If either the base or the derived type is invalid, don't try to + // check whether one is derived from the other. + if (BaseRD->isInvalidDecl() || DerivedRD->isInvalidDecl()) + return false; + // FIXME: instantiate DerivedRD if necessary. We need a PoI for this. return DerivedRD->hasDefinition() && DerivedRD->isDerivedFrom(BaseRD); } @@ -1344,11 +1498,11 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) { if (!getLangOpts().CPlusPlus) return false; - CXXRecordDecl *DerivedRD = GetClassForType(Derived); + CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl(); if (!DerivedRD) return false; - CXXRecordDecl *BaseRD = GetClassForType(Base); + CXXRecordDecl *BaseRD = Base->getAsCXXRecordDecl(); if (!BaseRD) return false; @@ -1588,6 +1742,13 @@ static bool InitializationHasSideEffects(const FieldDecl &FD) { return false; } +static AttributeList *getMSPropertyAttr(AttributeList *list) { + for (AttributeList* it = list; it != 0; it = it->getNext()) + if (it->isDeclspecPropertyAttribute()) + return it; + return 0; +} + /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the /// bitfield width if there is one, 'InitExpr' specifies the initializer if @@ -1664,30 +1825,24 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // data members and cannot be applied to names declared const or static, // and cannot be applied to reference members. switch (DS.getStorageClassSpec()) { - case DeclSpec::SCS_unspecified: - case DeclSpec::SCS_typedef: - case DeclSpec::SCS_static: - // FALL THROUGH. - break; - case DeclSpec::SCS_mutable: - if (isFunc) { - if (DS.getStorageClassSpecLoc().isValid()) - Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_function); - else - Diag(DS.getThreadSpecLoc(), diag::err_mutable_function); + case DeclSpec::SCS_unspecified: + case DeclSpec::SCS_typedef: + case DeclSpec::SCS_static: + break; + case DeclSpec::SCS_mutable: + if (isFunc) { + Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_function); - // FIXME: It would be nicer if the keyword was ignored only for this - // declarator. Otherwise we could get follow-up errors. - D.getMutableDeclSpec().ClearStorageClassSpecs(); - } - break; - default: - if (DS.getStorageClassSpecLoc().isValid()) - Diag(DS.getStorageClassSpecLoc(), - diag::err_storageclass_invalid_for_member); - else - Diag(DS.getThreadSpecLoc(), diag::err_storageclass_invalid_for_member); + // FIXME: It would be nicer if the keyword was ignored only for this + // declarator. Otherwise we could get follow-up errors. D.getMutableDeclSpec().ClearStorageClassSpecs(); + } + break; + default: + Diag(DS.getStorageClassSpecLoc(), + diag::err_storageclass_invalid_for_member); + D.getMutableDeclSpec().ClearStorageClassSpecs(); + break; } bool isInstField = ((DS.getStorageClassSpec() == DeclSpec::SCS_unspecified || @@ -1773,8 +1928,16 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, SS.clear(); } - Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, - InitStyle, AS); + AttributeList *MSPropertyAttr = + getMSPropertyAttr(D.getDeclSpec().getAttributes().getList()); + if (MSPropertyAttr) { + Member = HandleMSProperty(S, cast<CXXRecordDecl>(CurContext), Loc, D, + BitWidth, InitStyle, AS, MSPropertyAttr); + isInstField = false; + } else { + Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, + BitWidth, InitStyle, AS); + } assert(Member && "HandleField never returns null"); } else { assert(InitStyle == ICIS_NoInit || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static); @@ -1994,14 +2157,12 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc, Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list) << /*at end of ctor*/1 << InitExpr->getSourceRange(); } - Expr **Inits = &InitExpr; - unsigned NumInits = 1; InitializedEntity Entity = InitializedEntity::InitializeMember(FD); InitializationKind Kind = FD->getInClassInitStyle() == ICIS_ListInit ? InitializationKind::CreateDirectList(InitExpr->getLocStart()) : InitializationKind::CreateCopy(InitExpr->getLocStart(), InitLoc); - InitializationSequence Seq(*this, Entity, Kind, Inits, NumInits); - Init = Seq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); + InitializationSequence Seq(*this, Entity, Kind, InitExpr); + Init = Seq.Perform(*this, Entity, Kind, InitExpr); if (Init.isInvalid()) { FD->setInvalidDecl(); return; @@ -2364,23 +2525,19 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, // foo(foo) // where foo is not also a parameter to the constructor. // TODO: implement -Wuninitialized and fold this into that framework. - Expr **Args; - unsigned NumArgs; + MultiExprArg Args; if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { - Args = ParenList->getExprs(); - NumArgs = ParenList->getNumExprs(); + Args = MultiExprArg(ParenList->getExprs(), ParenList->getNumExprs()); } else if (InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) { - Args = InitList->getInits(); - NumArgs = InitList->getNumInits(); + Args = MultiExprArg(InitList->getInits(), InitList->getNumInits()); } else { // Template instantiation doesn't reconstruct ParenListExprs for us. - Args = &Init; - NumArgs = 1; + Args = Init; } if (getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit, IdLoc) != DiagnosticsEngine::Ignored) - for (unsigned i = 0; i < NumArgs; ++i) + for (unsigned i = 0, e = Args.size(); i != e; ++i) // FIXME: Warn about the case when other fields are used before being // initialized. For example, let this field be the i'th field. When // initializing the i'th field, throw a warning if any of the >= i'th @@ -2401,8 +2558,7 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, bool InitList = false; if (isa<InitListExpr>(Init)) { InitList = true; - Args = &Init; - NumArgs = 1; + Args = Init; if (isStdInitializerList(Member->getType(), 0)) { Diag(IdLoc, diag::warn_dangling_std_initializer_list) @@ -2419,10 +2575,8 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, : InitializationKind::CreateDirect(IdLoc, InitRange.getBegin(), InitRange.getEnd()); - InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); - ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, - MultiExprArg(Args, NumArgs), - 0); + InitializationSequence InitSeq(*this, MemberEntity, Kind, Args); + ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, Args, 0); if (MemberInit.isInvalid()) return true; @@ -2458,12 +2612,10 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, Diag(NameLoc, diag::warn_cxx98_compat_delegating_ctor); bool InitList = true; - Expr **Args = &Init; - unsigned NumArgs = 1; + MultiExprArg Args = Init; if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { InitList = false; - Args = ParenList->getExprs(); - NumArgs = ParenList->getNumExprs(); + Args = MultiExprArg(ParenList->getExprs(), ParenList->getNumExprs()); } SourceRange InitRange = Init->getSourceRange(); @@ -2474,10 +2626,9 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, InitList ? InitializationKind::CreateDirectList(NameLoc) : InitializationKind::CreateDirect(NameLoc, InitRange.getBegin(), InitRange.getEnd()); - InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs); + InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args); ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind, - MultiExprArg(Args, NumArgs), - 0); + Args, 0); if (DelegationInit.isInvalid()) return true; @@ -2597,12 +2748,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // Initialize the base. bool InitList = true; - Expr **Args = &Init; - unsigned NumArgs = 1; + MultiExprArg Args = Init; if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { InitList = false; - Args = ParenList->getExprs(); - NumArgs = ParenList->getNumExprs(); + Args = MultiExprArg(ParenList->getExprs(), ParenList->getNumExprs()); } InitializedEntity BaseEntity = @@ -2611,9 +2760,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, InitList ? InitializationKind::CreateDirectList(BaseLoc) : InitializationKind::CreateDirect(BaseLoc, InitRange.getBegin(), InitRange.getEnd()); - InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs); - ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, - MultiExprArg(Args, NumArgs), 0); + InitializationSequence InitSeq(*this, BaseEntity, Kind, Args); + ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, Args, 0); if (BaseInit.isInvalid()) return true; @@ -2642,9 +2790,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, } // Create a static_cast\<T&&>(expr). -static Expr *CastForMoving(Sema &SemaRef, Expr *E) { - QualType ExprType = E->getType(); - QualType TargetType = SemaRef.Context.getRValueReferenceType(ExprType); +static Expr *CastForMoving(Sema &SemaRef, Expr *E, QualType T = QualType()) { + if (T.isNull()) T = E->getType(); + QualType TargetType = SemaRef.BuildReferenceType( + T, /*SpelledAsLValue*/false, SourceLocation(), DeclarationName()); SourceLocation ExprLoc = E->getLocStart(); TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo( TargetType, ExprLoc); @@ -2659,7 +2808,8 @@ static Expr *CastForMoving(Sema &SemaRef, Expr *E) { enum ImplicitInitializerKind { IIK_Default, IIK_Copy, - IIK_Move + IIK_Move, + IIK_Inherit }; static bool @@ -2675,11 +2825,39 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, ExprResult BaseInit; switch (ImplicitInitKind) { + case IIK_Inherit: { + const CXXRecordDecl *Inherited = + Constructor->getInheritedConstructor()->getParent(); + const CXXRecordDecl *Base = BaseSpec->getType()->getAsCXXRecordDecl(); + if (Base && Inherited->getCanonicalDecl() == Base->getCanonicalDecl()) { + // C++11 [class.inhctor]p8: + // Each expression in the expression-list is of the form + // static_cast<T&&>(p), where p is the name of the corresponding + // constructor parameter and T is the declared type of p. + SmallVector<Expr*, 16> Args; + for (unsigned I = 0, E = Constructor->getNumParams(); I != E; ++I) { + ParmVarDecl *PD = Constructor->getParamDecl(I); + ExprResult ArgExpr = + SemaRef.BuildDeclRefExpr(PD, PD->getType().getNonReferenceType(), + VK_LValue, SourceLocation()); + if (ArgExpr.isInvalid()) + return true; + Args.push_back(CastForMoving(SemaRef, ArgExpr.take(), PD->getType())); + } + + InitializationKind InitKind = InitializationKind::CreateDirect( + Constructor->getLocation(), SourceLocation(), SourceLocation()); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, Args); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, Args); + break; + } + } + // Fall through. case IIK_Default: { InitializationKind InitKind = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); - BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, MultiExprArg()); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, None); break; } @@ -2716,10 +2894,8 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationKind InitKind = InitializationKind::CreateDirect(Constructor->getLocation(), SourceLocation(), SourceLocation()); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, - &CopyCtorArg, 1); - BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, - MultiExprArg(&CopyCtorArg, 1)); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, CopyCtorArg); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, CopyCtorArg); break; } } @@ -2825,7 +3001,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc, Loc, IterationVarName, SizeType, SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc), - SC_None, SC_None); + SC_None); IndexVariables.push_back(IterationVar); // Create a reference to the iteration variable. @@ -2870,8 +3046,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation()); Expr *CtorArgE = CtorArg.takeAs<Expr>(); - InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, - &CtorArgE, 1); + InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, CtorArgE); ExprResult MemberInit = InitSeq.Perform(SemaRef, Entities.back(), InitKind, @@ -2897,7 +3072,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, return false; } - assert(ImplicitInitKind == IIK_Default && "Unhandled implicit init kind!"); + assert((ImplicitInitKind == IIK_Default || ImplicitInitKind == IIK_Inherit) && + "Unhandled implicit init kind!"); QualType FieldBaseElementType = SemaRef.Context.getBaseElementType(Field->getType()); @@ -2908,10 +3084,10 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, : InitializedEntity::InitializeMember(Field); InitializationKind InitKind = InitializationKind::CreateDefault(Loc); - - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); - ExprResult MemberInit = - InitSeq.Perform(SemaRef, InitEntity, InitKind, MultiExprArg()); + + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None); + ExprResult MemberInit = + InitSeq.Perform(SemaRef, InitEntity, InitKind, None); MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) @@ -2988,6 +3164,8 @@ struct BaseAndFieldInfo { IIK = IIK_Copy; else if (Generated && Ctor->isMoveConstructor()) IIK = IIK_Move; + else if (Ctor->getInheritedConstructor()) + IIK = IIK_Inherit; else IIK = IIK_Default; } @@ -2999,6 +3177,7 @@ struct BaseAndFieldInfo { return true; case IIK_Default: + case IIK_Inherit: return false; } @@ -3009,7 +3188,7 @@ struct BaseAndFieldInfo { AllToInit.push_back(Init); // Check whether this initializer makes the field "used". - if (Init->getInit() && Init->getInit()->HasSideEffects(S.Context)) + if (Init->getInit()->HasSideEffects(S.Context)) S.UnusedPrivateFields.remove(Init->getAnyMember()); return false; @@ -3058,16 +3237,18 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, // has a brace-or-equal-initializer, the entity is initialized as specified // in [dcl.init]. if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) { + Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, + Info.Ctor->getLocation(), Field); CXXCtorInitializer *Init; if (Indirect) Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, SourceLocation(), - SourceLocation(), 0, + SourceLocation(), DIE, SourceLocation()); else Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, SourceLocation(), - SourceLocation(), 0, + SourceLocation(), DIE, SourceLocation()); return Info.addFieldInitializer(Init); } @@ -3226,7 +3407,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, // If we're not generating the implicit copy/move constructor, then we'll // handle anonymous struct/union fields based on their individual // indirect fields. - if (F->isAnonymousStructOrUnion() && Info.IIK == IIK_Default) + if (F->isAnonymousStructOrUnion() && !Info.isImplicitCopyOrMove()) continue; if (CollectFieldInitializer(*this, Info, F)) @@ -3235,7 +3416,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, } // Beyond this point, we only consider default initialization. - if (Info.IIK != IIK_Default) + if (Info.isImplicitCopyOrMove()) continue; if (IndirectFieldDecl *F = dyn_cast<IndirectFieldDecl>(*Mem)) { @@ -3401,7 +3582,7 @@ bool CheckRedundantInit(Sema &S, return false; } - if (FieldDecl *Field = Init->getMember()) + if (FieldDecl *Field = Init->getAnyMember()) S.Diag(Init->getSourceLocation(), diag::err_multiple_mem_initialization) << Field->getDeclName() @@ -4062,14 +4243,14 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } - // Declare inherited constructors. We do this eagerly here because: - // - The standard requires an eager diagnostic for conflicting inherited + // Declare inheriting constructors. We do this eagerly here because: + // - The standard requires an eager diagnostic for conflicting inheriting // constructors from different classes. // - The lazy declaration of the other implicit constructors is so as to not // waste space and performance on classes that are not meant to be // instantiated (e.g. meta-functions). This doesn't apply to classes that - // have inherited constructors. - DeclareInheritedConstructors(Record); + // have inheriting constructors. + DeclareInheritingConstructors(Record); } /// Is the special member function which would be selected to perform the @@ -4185,7 +4366,9 @@ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) { case Sema::CXXInvalid: break; } - llvm_unreachable("only special members have implicit exception specs"); + assert(cast<CXXConstructorDecl>(MD)->getInheritedConstructor() && + "only special members have implicit exception specs"); + return S.ComputeInheritingCtorExceptionSpec(cast<CXXConstructorDecl>(MD)); } static void @@ -4193,12 +4376,8 @@ updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT, const Sema::ImplicitExceptionSpecification &ExceptSpec) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); ExceptSpec.getEPI(EPI); - const FunctionProtoType *NewFPT = cast<FunctionProtoType>( - S.Context.getFunctionType(FPT->getResultType(), - ArrayRef<QualType>(FPT->arg_type_begin(), - FPT->getNumArgs()), - EPI)); - FD->setType(QualType(NewFPT, 0)); + FD->setType(S.Context.getFunctionType(FPT->getResultType(), + FPT->getArgTypes(), EPI)); } void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) { @@ -4342,9 +4521,15 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { if (Type->hasExceptionSpec()) { // Delay the check if this is the first declaration of the special member, // since we may not have parsed some necessary in-class initializers yet. - if (First) + if (First) { + // If the exception specification needs to be instantiated, do so now, + // before we clobber it with an EST_Unevaluated specification below. + if (Type->getExceptionSpecType() == EST_Uninstantiated) { + InstantiateExceptionSpec(MD->getLocStart(), MD); + Type = MD->getType()->getAs<FunctionProtoType>(); + } DelayedDefaultedMemberExceptionSpecs.push_back(std::make_pair(MD, Type)); - else + } else CheckExplicitlyDefaultedMemberExceptionSpec(MD, Type); } @@ -4367,7 +4552,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { if (ShouldDeleteSpecialMember(MD, CSM)) { if (First) { - MD->setDeletedAsWritten(); + SetDeclDeleted(MD, MD->getLocation()); } else { // C++11 [dcl.fct.def.default]p4: // [For a] user-provided explicitly-defaulted function [...] if such a @@ -4391,7 +4576,7 @@ void Sema::CheckExplicitlyDefaultedMemberExceptionSpec( FunctionProtoType::ExtProtoInfo EPI; computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI); const FunctionProtoType *ImplicitType = cast<FunctionProtoType>( - Context.getFunctionType(Context.VoidTy, ArrayRef<QualType>(), EPI)); + Context.getFunctionType(Context.VoidTy, None, EPI)); // Ensure that it matches. CheckEquivalentExceptionSpec( @@ -5373,8 +5558,10 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { for (unsigned i = 0, e = Data.OverloadedMethods.size(); i != e; ++i) { CXXMethodDecl *overloadedMD = Data.OverloadedMethods[i]; - Diag(overloadedMD->getLocation(), + PartialDiagnostic PD = PDiag( diag::note_hidden_overloaded_virtual_declared_here) << overloadedMD; + HandleFunctionTypeMismatch(PD, MD->getType(), overloadedMD->getType()); + Diag(overloadedMD->getLocation(), PD); } } } @@ -5644,10 +5831,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, EPI.TypeQuals = 0; EPI.RefQualifier = RQ_None; - return Context.getFunctionType(Context.VoidTy, - ArrayRef<QualType>(Proto->arg_type_begin(), - Proto->getNumArgs()), - EPI); + return Context.getFunctionType(Context.VoidTy, Proto->getArgTypes(), EPI); } /// CheckConstructor - Checks a fully-formed constructor for @@ -5827,7 +6011,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, EPI.Variadic = false; EPI.TypeQuals = 0; EPI.RefQualifier = RQ_None; - return Context.getFunctionType(Context.VoidTy, ArrayRef<QualType>(), EPI); + return Context.getFunctionType(Context.VoidTy, None, EPI); } /// CheckConversionDeclarator - Called by ActOnDeclarator to check the @@ -5908,8 +6092,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // of the errors above fired) and with the conversion type as the // return type. if (D.isInvalidType()) - R = Context.getFunctionType(ConvType, ArrayRef<QualType>(), - Proto->getExtProtoInfo()); + R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo()); // C++0x explicit conversion operators. if (D.getDeclSpec().isExplicitSpecified()) @@ -6519,9 +6702,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, // C++11 inheriting constructors. Diag(Name.getLocStart(), getLangOpts().CPlusPlus11 ? - // FIXME: Produce warn_cxx98_compat_using_decl_constructor - // instead once inheriting constructors work. - diag::err_using_decl_constructor_unsupported : + diag::warn_cxx98_compat_using_decl_constructor : diag::err_using_decl_constructor) << SS.getRange(); @@ -6545,7 +6726,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, if (!TargetName) return 0; - // Warn about using declarations. + // Warn about access declarations. // TODO: store that the declaration was written without 'using' and // talk about access decls instead of using decls in the // diagnostics. @@ -7471,6 +7652,77 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, return ExceptSpec; } +Sema::ImplicitExceptionSpecification +Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) { + CXXRecordDecl *ClassDecl = CD->getParent(); + + // C++ [except.spec]p14: + // An inheriting constructor [...] shall have an exception-specification. [...] + ImplicitExceptionSpecification ExceptSpec(*this); + if (ClassDecl->isInvalidDecl()) + return ExceptSpec; + + // Inherited constructor. + const CXXConstructorDecl *InheritedCD = CD->getInheritedConstructor(); + const CXXRecordDecl *InheritedDecl = InheritedCD->getParent(); + // FIXME: Copying or moving the parameters could add extra exceptions to the + // set, as could the default arguments for the inherited constructor. This + // will be addressed when we implement the resolution of core issue 1351. + ExceptSpec.CalledDecl(CD->getLocStart(), InheritedCD); + + // Direct base-class constructors. + for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), + BEnd = ClassDecl->bases_end(); + B != BEnd; ++B) { + if (B->isVirtual()) // Handled below. + continue; + + if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); + if (BaseClassDecl == InheritedDecl) + continue; + CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); + if (Constructor) + ExceptSpec.CalledDecl(B->getLocStart(), Constructor); + } + } + + // Virtual base-class constructors. + for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(), + BEnd = ClassDecl->vbases_end(); + B != BEnd; ++B) { + if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); + if (BaseClassDecl == InheritedDecl) + continue; + CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); + if (Constructor) + ExceptSpec.CalledDecl(B->getLocStart(), Constructor); + } + } + + // Field constructors. + for (RecordDecl::field_iterator F = ClassDecl->field_begin(), + FEnd = ClassDecl->field_end(); + F != FEnd; ++F) { + if (F->hasInClassInitializer()) { + if (Expr *E = F->getInClassInitializer()) + ExceptSpec.CalledExpr(E); + else if (!F->isInvalidDecl()) + Diag(CD->getLocation(), + diag::err_in_class_initializer_references_def_ctor) << CD; + } else if (const RecordType *RecordTy + = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { + CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); + CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl); + if (Constructor) + ExceptSpec.CalledDecl(F->getLocation(), Constructor); + } + } + + return ExceptSpec; +} + namespace { /// RAII object to register a special member as being currently declared. struct DeclaringSpecialMember { @@ -7539,16 +7791,14 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( FunctionProtoType::ExtProtoInfo EPI; EPI.ExceptionSpecType = EST_Unevaluated; EPI.ExceptionSpecDecl = DefaultCon; - DefaultCon->setType(Context.getFunctionType(Context.VoidTy, - ArrayRef<QualType>(), - EPI)); + DefaultCon->setType(Context.getFunctionType(Context.VoidTy, None, EPI)); // We don't need to use SpecialMemberIsTrivial here; triviality for default // constructors is easy to compute. DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor()); if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor)) - DefaultCon->setDeletedAsWritten(); + SetDeclDeleted(DefaultCon, ClassLoc); // Note that we have declared this constructor. ++ASTContext::NumImplicitDefaultConstructorsDeclared; @@ -7597,186 +7847,339 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { CheckDelayedExplicitlyDefaultedMemberExceptionSpecs(); } -void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { - // We start with an initial pass over the base classes to collect those that - // inherit constructors from. If there are none, we can forgo all further - // processing. - typedef SmallVector<const RecordType *, 4> BasesVector; - BasesVector BasesToInheritFrom; - for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(), - BaseE = ClassDecl->bases_end(); - BaseIt != BaseE; ++BaseIt) { - if (BaseIt->getInheritConstructors()) { - QualType Base = BaseIt->getType(); - if (Base->isDependentType()) { - // If we inherit constructors from anything that is dependent, just - // abort processing altogether. We'll get another chance for the - // instantiations. - return; +namespace { +/// Information on inheriting constructors to declare. +class InheritingConstructorInfo { +public: + InheritingConstructorInfo(Sema &SemaRef, CXXRecordDecl *Derived) + : SemaRef(SemaRef), Derived(Derived) { + // Mark the constructors that we already have in the derived class. + // + // C++11 [class.inhctor]p3: [...] a constructor is implicitly declared [...] + // unless there is a user-declared constructor with the same signature in + // the class where the using-declaration appears. + visitAll(Derived, &InheritingConstructorInfo::noteDeclaredInDerived); + } + + void inheritAll(CXXRecordDecl *RD) { + visitAll(RD, &InheritingConstructorInfo::inherit); + } + +private: + /// Information about an inheriting constructor. + struct InheritingConstructor { + InheritingConstructor() + : DeclaredInDerived(false), BaseCtor(0), DerivedCtor(0) {} + + /// If \c true, a constructor with this signature is already declared + /// in the derived class. + bool DeclaredInDerived; + + /// The constructor which is inherited. + const CXXConstructorDecl *BaseCtor; + + /// The derived constructor we declared. + CXXConstructorDecl *DerivedCtor; + }; + + /// Inheriting constructors with a given canonical type. There can be at + /// most one such non-template constructor, and any number of templated + /// constructors. + struct InheritingConstructorsForType { + InheritingConstructor NonTemplate; + llvm::SmallVector< + std::pair<TemplateParameterList*, InheritingConstructor>, 4> Templates; + + InheritingConstructor &getEntry(Sema &S, const CXXConstructorDecl *Ctor) { + if (FunctionTemplateDecl *FTD = Ctor->getDescribedFunctionTemplate()) { + TemplateParameterList *ParamList = FTD->getTemplateParameters(); + for (unsigned I = 0, N = Templates.size(); I != N; ++I) + if (S.TemplateParameterListsAreEqual(ParamList, Templates[I].first, + false, S.TPL_TemplateMatch)) + return Templates[I].second; + Templates.push_back(std::make_pair(ParamList, InheritingConstructor())); + return Templates.back().second; } - BasesToInheritFrom.push_back(Base->castAs<RecordType>()); + + return NonTemplate; + } + }; + + /// Get or create the inheriting constructor record for a constructor. + InheritingConstructor &getEntry(const CXXConstructorDecl *Ctor, + QualType CtorType) { + return Map[CtorType.getCanonicalType()->castAs<FunctionProtoType>()] + .getEntry(SemaRef, Ctor); + } + + typedef void (InheritingConstructorInfo::*VisitFn)(const CXXConstructorDecl*); + + /// Process all constructors for a class. + void visitAll(const CXXRecordDecl *RD, VisitFn Callback) { + for (CXXRecordDecl::ctor_iterator CtorIt = RD->ctor_begin(), + CtorE = RD->ctor_end(); + CtorIt != CtorE; ++CtorIt) + (this->*Callback)(*CtorIt); + for (CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl> + I(RD->decls_begin()), E(RD->decls_end()); + I != E; ++I) { + const FunctionDecl *FD = (*I)->getTemplatedDecl(); + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) + (this->*Callback)(CD); } } - if (BasesToInheritFrom.empty()) - return; - // Now collect the constructors that we already have in the current class. - // Those take precedence over inherited constructors. - // C++0x [class.inhctor]p3: [...] a constructor is implicitly declared [...] - // unless there is a user-declared constructor with the same signature in - // the class where the using-declaration appears. - llvm::SmallSet<const Type *, 8> ExistingConstructors; - for (CXXRecordDecl::ctor_iterator CtorIt = ClassDecl->ctor_begin(), - CtorE = ClassDecl->ctor_end(); - CtorIt != CtorE; ++CtorIt) { - ExistingConstructors.insert( - Context.getCanonicalType(CtorIt->getType()).getTypePtr()); - } - - DeclarationName CreatedCtorName = - Context.DeclarationNames.getCXXConstructorName( - ClassDecl->getTypeForDecl()->getCanonicalTypeUnqualified()); - - // Now comes the true work. - // First, we keep a map from constructor types to the base that introduced - // them. Needed for finding conflicting constructors. We also keep the - // actually inserted declarations in there, for pretty diagnostics. - typedef std::pair<CanQualType, CXXConstructorDecl *> ConstructorInfo; - typedef llvm::DenseMap<const Type *, ConstructorInfo> ConstructorToSourceMap; - ConstructorToSourceMap InheritedConstructors; - for (BasesVector::iterator BaseIt = BasesToInheritFrom.begin(), - BaseE = BasesToInheritFrom.end(); - BaseIt != BaseE; ++BaseIt) { - const RecordType *Base = *BaseIt; - CanQualType CanonicalBase = Base->getCanonicalTypeUnqualified(); - CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(Base->getDecl()); - for (CXXRecordDecl::ctor_iterator CtorIt = BaseDecl->ctor_begin(), - CtorE = BaseDecl->ctor_end(); - CtorIt != CtorE; ++CtorIt) { - // Find the using declaration for inheriting this base's constructors. - // FIXME: Don't perform name lookup just to obtain a source location! - DeclarationName Name = - Context.DeclarationNames.getCXXConstructorName(CanonicalBase); - LookupResult Result(*this, Name, SourceLocation(), LookupUsingDeclName); - LookupQualifiedName(Result, CurContext); - UsingDecl *UD = Result.getAsSingle<UsingDecl>(); - SourceLocation UsingLoc = UD ? UD->getLocation() : - ClassDecl->getLocation(); - - // C++0x [class.inhctor]p1: The candidate set of inherited constructors - // from the class X named in the using-declaration consists of actual - // constructors and notional constructors that result from the - // transformation of defaulted parameters as follows: - // - all non-template default constructors of X, and - // - for each non-template constructor of X that has at least one - // parameter with a default argument, the set of constructors that - // results from omitting any ellipsis parameter specification and - // successively omitting parameters with a default argument from the - // end of the parameter-type-list. - CXXConstructorDecl *BaseCtor = *CtorIt; - bool CanBeCopyOrMove = BaseCtor->isCopyOrMoveConstructor(); - const FunctionProtoType *BaseCtorType = - BaseCtor->getType()->getAs<FunctionProtoType>(); - - for (unsigned params = BaseCtor->getMinRequiredArguments(), - maxParams = BaseCtor->getNumParams(); - params <= maxParams; ++params) { - // Skip default constructors. They're never inherited. - if (params == 0) - continue; - // Skip copy and move constructors for the same reason. - if (CanBeCopyOrMove && params == 1) - continue; + /// Note that a constructor (or constructor template) was declared in Derived. + void noteDeclaredInDerived(const CXXConstructorDecl *Ctor) { + getEntry(Ctor, Ctor->getType()).DeclaredInDerived = true; + } - // Build up a function type for this particular constructor. - // FIXME: The working paper does not consider that the exception spec - // for the inheriting constructor might be larger than that of the - // source. This code doesn't yet, either. When it does, this code will - // need to be delayed until after exception specifications and in-class - // member initializers are attached. - const Type *NewCtorType; - if (params == maxParams) - NewCtorType = BaseCtorType; - else { - SmallVector<QualType, 16> Args; - for (unsigned i = 0; i < params; ++i) { - Args.push_back(BaseCtorType->getArgType(i)); - } - FunctionProtoType::ExtProtoInfo ExtInfo = - BaseCtorType->getExtProtoInfo(); - ExtInfo.Variadic = false; - NewCtorType = Context.getFunctionType(BaseCtorType->getResultType(), - Args, ExtInfo) - .getTypePtr(); - } - const Type *CanonicalNewCtorType = - Context.getCanonicalType(NewCtorType); + /// Inherit a single constructor. + void inherit(const CXXConstructorDecl *Ctor) { + const FunctionProtoType *CtorType = + Ctor->getType()->castAs<FunctionProtoType>(); + ArrayRef<QualType> ArgTypes(CtorType->getArgTypes()); + FunctionProtoType::ExtProtoInfo EPI = CtorType->getExtProtoInfo(); - // Now that we have the type, first check if the class already has a - // constructor with this signature. - if (ExistingConstructors.count(CanonicalNewCtorType)) - continue; + SourceLocation UsingLoc = getUsingLoc(Ctor->getParent()); - // Then we check if we have already declared an inherited constructor - // with this signature. - std::pair<ConstructorToSourceMap::iterator, bool> result = - InheritedConstructors.insert(std::make_pair( - CanonicalNewCtorType, - std::make_pair(CanonicalBase, (CXXConstructorDecl*)0))); - if (!result.second) { - // Already in the map. If it came from a different class, that's an - // error. Not if it's from the same. - CanQualType PreviousBase = result.first->second.first; - if (CanonicalBase != PreviousBase) { - const CXXConstructorDecl *PrevCtor = result.first->second.second; - const CXXConstructorDecl *PrevBaseCtor = - PrevCtor->getInheritedConstructor(); - assert(PrevBaseCtor && "Conflicting constructor was not inherited"); - - Diag(UsingLoc, diag::err_using_decl_constructor_conflict); - Diag(BaseCtor->getLocation(), - diag::note_using_decl_constructor_conflict_current_ctor); - Diag(PrevBaseCtor->getLocation(), - diag::note_using_decl_constructor_conflict_previous_ctor); - Diag(PrevCtor->getLocation(), - diag::note_using_decl_constructor_conflict_previous_using); - } - continue; - } + // Core issue (no number yet): the ellipsis is always discarded. + if (EPI.Variadic) { + SemaRef.Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis); + SemaRef.Diag(Ctor->getLocation(), + diag::note_using_decl_constructor_ellipsis); + EPI.Variadic = false; + } - // OK, we're there, now add the constructor. - // C++0x [class.inhctor]p8: [...] that would be performed by a - // user-written inline constructor [...] - DeclarationNameInfo DNI(CreatedCtorName, UsingLoc); - CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create( - Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0), - /*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true, - /*ImplicitlyDeclared=*/true, - // FIXME: Due to a defect in the standard, we treat inherited - // constructors as constexpr even if that makes them ill-formed. - /*Constexpr=*/BaseCtor->isConstexpr()); - NewCtor->setAccess(BaseCtor->getAccess()); - - // Build up the parameter decls and add them. - SmallVector<ParmVarDecl *, 16> ParamDecls; - for (unsigned i = 0; i < params; ++i) { - ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor, - UsingLoc, UsingLoc, - /*IdentifierInfo=*/0, - BaseCtorType->getArgType(i), - /*TInfo=*/0, SC_None, - SC_None, /*DefaultArg=*/0)); - } - NewCtor->setParams(ParamDecls); - NewCtor->setInheritedConstructor(BaseCtor); + // Declare a constructor for each number of parameters. + // + // C++11 [class.inhctor]p1: + // The candidate set of inherited constructors from the class X named in + // the using-declaration consists of [... modulo defects ...] for each + // constructor or constructor template of X, the set of constructors or + // constructor templates that results from omitting any ellipsis parameter + // specification and successively omitting parameters with a default + // argument from the end of the parameter-type-list + unsigned MinParams = minParamsToInherit(Ctor); + unsigned Params = Ctor->getNumParams(); + if (Params >= MinParams) { + do + declareCtor(UsingLoc, Ctor, + SemaRef.Context.getFunctionType( + Ctor->getResultType(), ArgTypes.slice(0, Params), EPI)); + while (Params > MinParams && + Ctor->getParamDecl(--Params)->hasDefaultArg()); + } + } + + /// Find the using-declaration which specified that we should inherit the + /// constructors of \p Base. + SourceLocation getUsingLoc(const CXXRecordDecl *Base) { + // No fancy lookup required; just look for the base constructor name + // directly within the derived class. + ASTContext &Context = SemaRef.Context; + DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Context.getRecordType(Base))); + DeclContext::lookup_const_result Decls = Derived->lookup(Name); + return Decls.empty() ? Derived->getLocation() : Decls[0]->getLocation(); + } + + unsigned minParamsToInherit(const CXXConstructorDecl *Ctor) { + // C++11 [class.inhctor]p3: + // [F]or each constructor template in the candidate set of inherited + // constructors, a constructor template is implicitly declared + if (Ctor->getDescribedFunctionTemplate()) + return 0; - ClassDecl->addDecl(NewCtor); - result.first->second.second = NewCtor; + // For each non-template constructor in the candidate set of inherited + // constructors other than a constructor having no parameters or a + // copy/move constructor having a single parameter, a constructor is + // implicitly declared [...] + if (Ctor->getNumParams() == 0) + return 1; + if (Ctor->isCopyOrMoveConstructor()) + return 2; + + // Per discussion on core reflector, never inherit a constructor which + // would become a default, copy, or move constructor of Derived either. + const ParmVarDecl *PD = Ctor->getParamDecl(0); + const ReferenceType *RT = PD->getType()->getAs<ReferenceType>(); + return (RT && RT->getPointeeCXXRecordDecl() == Derived) ? 2 : 1; + } + + /// Declare a single inheriting constructor, inheriting the specified + /// constructor, with the given type. + void declareCtor(SourceLocation UsingLoc, const CXXConstructorDecl *BaseCtor, + QualType DerivedType) { + InheritingConstructor &Entry = getEntry(BaseCtor, DerivedType); + + // C++11 [class.inhctor]p3: + // ... a constructor is implicitly declared with the same constructor + // characteristics unless there is a user-declared constructor with + // the same signature in the class where the using-declaration appears + if (Entry.DeclaredInDerived) + return; + + // C++11 [class.inhctor]p7: + // If two using-declarations declare inheriting constructors with the + // same signature, the program is ill-formed + if (Entry.DerivedCtor) { + if (BaseCtor->getParent() != Entry.BaseCtor->getParent()) { + // Only diagnose this once per constructor. + if (Entry.DerivedCtor->isInvalidDecl()) + return; + Entry.DerivedCtor->setInvalidDecl(); + + SemaRef.Diag(UsingLoc, diag::err_using_decl_constructor_conflict); + SemaRef.Diag(BaseCtor->getLocation(), + diag::note_using_decl_constructor_conflict_current_ctor); + SemaRef.Diag(Entry.BaseCtor->getLocation(), + diag::note_using_decl_constructor_conflict_previous_ctor); + SemaRef.Diag(Entry.DerivedCtor->getLocation(), + diag::note_using_decl_constructor_conflict_previous_using); + } else { + // Core issue (no number): if the same inheriting constructor is + // produced by multiple base class constructors from the same base + // class, the inheriting constructor is defined as deleted. + SemaRef.SetDeclDeleted(Entry.DerivedCtor, UsingLoc); } + + return; } + + ASTContext &Context = SemaRef.Context; + DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Context.getRecordType(Derived))); + DeclarationNameInfo NameInfo(Name, UsingLoc); + + TemplateParameterList *TemplateParams = 0; + if (const FunctionTemplateDecl *FTD = + BaseCtor->getDescribedFunctionTemplate()) { + TemplateParams = FTD->getTemplateParameters(); + // We're reusing template parameters from a different DeclContext. This + // is questionable at best, but works out because the template depth in + // both places is guaranteed to be 0. + // FIXME: Rebuild the template parameters in the new context, and + // transform the function type to refer to them. + } + + // Build type source info pointing at the using-declaration. This is + // required by template instantiation. + TypeSourceInfo *TInfo = + Context.getTrivialTypeSourceInfo(DerivedType, UsingLoc); + FunctionProtoTypeLoc ProtoLoc = + TInfo->getTypeLoc().IgnoreParens().castAs<FunctionProtoTypeLoc>(); + + CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create( + Context, Derived, UsingLoc, NameInfo, DerivedType, + TInfo, BaseCtor->isExplicit(), /*Inline=*/true, + /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr()); + + // Build an unevaluated exception specification for this constructor. + const FunctionProtoType *FPT = DerivedType->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = DerivedCtor; + DerivedCtor->setType(Context.getFunctionType(FPT->getResultType(), + FPT->getArgTypes(), EPI)); + + // Build the parameter declarations. + SmallVector<ParmVarDecl *, 16> ParamDecls; + for (unsigned I = 0, N = FPT->getNumArgs(); I != N; ++I) { + TypeSourceInfo *TInfo = + Context.getTrivialTypeSourceInfo(FPT->getArgType(I), UsingLoc); + ParmVarDecl *PD = ParmVarDecl::Create( + Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/0, + FPT->getArgType(I), TInfo, SC_None, /*DefaultArg=*/0); + PD->setScopeInfo(0, I); + PD->setImplicit(); + ParamDecls.push_back(PD); + ProtoLoc.setArg(I, PD); + } + + // Set up the new constructor. + DerivedCtor->setAccess(BaseCtor->getAccess()); + DerivedCtor->setParams(ParamDecls); + DerivedCtor->setInheritedConstructor(BaseCtor); + if (BaseCtor->isDeleted()) + SemaRef.SetDeclDeleted(DerivedCtor, UsingLoc); + + // If this is a constructor template, build the template declaration. + if (TemplateParams) { + FunctionTemplateDecl *DerivedTemplate = + FunctionTemplateDecl::Create(SemaRef.Context, Derived, UsingLoc, Name, + TemplateParams, DerivedCtor); + DerivedTemplate->setAccess(BaseCtor->getAccess()); + DerivedCtor->setDescribedFunctionTemplate(DerivedTemplate); + Derived->addDecl(DerivedTemplate); + } else { + Derived->addDecl(DerivedCtor); + } + + Entry.BaseCtor = BaseCtor; + Entry.DerivedCtor = DerivedCtor; } + + Sema &SemaRef; + CXXRecordDecl *Derived; + typedef llvm::DenseMap<const Type *, InheritingConstructorsForType> MapType; + MapType Map; +}; } +void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) { + // Defer declaring the inheriting constructors until the class is + // instantiated. + if (ClassDecl->isDependentContext()) + return; + + // Find base classes from which we might inherit constructors. + SmallVector<CXXRecordDecl*, 4> InheritedBases; + for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(), + BaseE = ClassDecl->bases_end(); + BaseIt != BaseE; ++BaseIt) + if (BaseIt->getInheritConstructors()) + InheritedBases.push_back(BaseIt->getType()->getAsCXXRecordDecl()); + + // Go no further if we're not inheriting any constructors. + if (InheritedBases.empty()) + return; + + // Declare the inherited constructors. + InheritingConstructorInfo ICI(*this, ClassDecl); + for (unsigned I = 0, N = InheritedBases.size(); I != N; ++I) + ICI.inheritAll(InheritedBases[I]); +} + +void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor) { + CXXRecordDecl *ClassDecl = Constructor->getParent(); + assert(Constructor->getInheritedConstructor() && + !Constructor->doesThisDeclarationHaveABody() && + !Constructor->isDeleted()); + + SynthesizedFunctionScope Scope(*this, Constructor); + DiagnosticErrorTrap Trap(Diags); + if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) || + Trap.hasErrorOccurred()) { + Diag(CurrentLocation, diag::note_inhctor_synthesized_at) + << Context.getTagDeclType(ClassDecl); + Constructor->setInvalidDecl(); + return; + } + + SourceLocation Loc = Constructor->getLocation(); + Constructor->setBody(new (Context) CompoundStmt(Loc)); + + Constructor->setUsed(); + MarkVTableUsed(CurrentLocation, ClassDecl); + + if (ASTMutationListener *L = getASTMutationListener()) { + L->CompletedImplicitDefinition(Constructor); + } +} + + Sema::ImplicitExceptionSpecification Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) { CXXRecordDecl *ClassDecl = MD->getParent(); @@ -7852,9 +8255,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { FunctionProtoType::ExtProtoInfo EPI; EPI.ExceptionSpecType = EST_Unevaluated; EPI.ExceptionSpecDecl = Destructor; - Destructor->setType(Context.getFunctionType(Context.VoidTy, - ArrayRef<QualType>(), - EPI)); + Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI)); AddOverriddenMethods(ClassDecl, Destructor); @@ -7863,7 +8264,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); if (ShouldDeleteSpecialMember(Destructor, CXXDestructor)) - Destructor->setDeletedAsWritten(); + SetDeclDeleted(Destructor, ClassLoc); // Note that we have declared this destructor. ++ASTContext::NumImplicitDestructorsDeclared; @@ -7958,9 +8359,7 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo(); EPI.ExceptionSpecType = EST_Unevaluated; EPI.ExceptionSpecDecl = Destructor; - Destructor->setType(Context.getFunctionType(Context.VoidTy, - ArrayRef<QualType>(), - EPI)); + Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI)); // FIXME: If the destructor has a body that could throw, and the newly created // spec doesn't allow exceptions, we should emit a warning, because this @@ -8184,7 +8583,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T, VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType, S.Context.getTrivialTypeSourceInfo(SizeType, Loc), - SC_None, SC_None); + SC_None); // Initialize the iteration variable to zero. llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0); @@ -8348,8 +8747,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { DeclarationNameInfo NameInfo(Name, ClassLoc); CXXMethodDecl *CopyAssignment = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(), - /*TInfo=*/0, /*isStatic=*/false, - /*StorageClassAsWritten=*/SC_None, + /*TInfo=*/0, + /*StorageClass=*/SC_None, /*isInline=*/true, /*isConstexpr=*/false, SourceLocation()); CopyAssignment->setAccess(AS_public); @@ -8366,7 +8765,6 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, ClassLoc, ClassLoc, /*Id=*/0, ArgType, /*TInfo=*/0, - SC_None, SC_None, 0); CopyAssignment->setParams(FromParam); @@ -8383,7 +8781,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // there is no user-declared move assignment operator, a copy assignment // operator is implicitly declared as defaulted. if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) - CopyAssignment->setDeletedAsWritten(); + SetDeclDeleted(CopyAssignment, ClassLoc); // Note that we have added this copy-assignment operator. ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; @@ -8797,8 +9195,8 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { DeclarationNameInfo NameInfo(Name, ClassLoc); CXXMethodDecl *MoveAssignment = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(), - /*TInfo=*/0, /*isStatic=*/false, - /*StorageClassAsWritten=*/SC_None, + /*TInfo=*/0, + /*StorageClass=*/SC_None, /*isInline=*/true, /*isConstexpr=*/false, SourceLocation()); @@ -8816,7 +9214,6 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment, ClassLoc, ClassLoc, /*Id=*/0, ArgType, /*TInfo=*/0, - SC_None, SC_None, 0); MoveAssignment->setParams(FromParam); @@ -9171,7 +9568,6 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ClassLoc, ClassLoc, /*IdentifierInfo=*/0, ArgType, /*TInfo=*/0, - SC_None, SC_None, 0); CopyConstructor->setParams(FromParam); @@ -9186,7 +9582,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // user-declared move assignment operator, a copy constructor is implicitly // declared as defaulted. if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) - CopyConstructor->setDeletedAsWritten(); + SetDeclDeleted(CopyConstructor, ClassLoc); // Note that we have declared this constructor. ++ASTContext::NumImplicitCopyConstructorsDeclared; @@ -9358,7 +9754,6 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( ClassLoc, ClassLoc, /*IdentifierInfo=*/0, ArgType, /*TInfo=*/0, - SC_None, SC_None, 0); MoveConstructor->setParams(FromParam); @@ -10087,7 +10482,8 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, // FIXME: Add all the various semantics of linkage specifications LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, - ExternLoc, LangLoc, Language); + ExternLoc, LangLoc, Language, + LBraceLoc.isValid()); CurContext->addDecl(D); PushDeclContext(S, D); return D; @@ -10190,7 +10586,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, } VarDecl *ExDecl = VarDecl::Create(Context, CurContext, StartLoc, Loc, Name, - ExDeclType, TInfo, SC_None, SC_None); + ExDeclType, TInfo, SC_None); ExDecl->setExceptionVariable(true); // In ARC, infer 'retaining' for variables of retainable type. @@ -10199,6 +10595,9 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, if (!Invalid && !ExDeclType->isDependentType()) { if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) { + // Insulate this from anything else we might currently be parsing. + EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated); + // C++ [except.handle]p16: // The object declared in an exception-declaration or, if the // exception-declaration does not specify a name, a temporary (12.2) is @@ -10217,9 +10616,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, Expr *opaqueValue = new (Context) OpaqueValueExpr(Loc, initType, VK_LValue, OK_Ordinary); - InitializationSequence sequence(*this, entity, initKind, &opaqueValue, 1); - ExprResult result = sequence.Perform(*this, entity, initKind, - MultiExprArg(&opaqueValue, 1)); + InitializationSequence sequence(*this, entity, initKind, opaqueValue); + ExprResult result = sequence.Perform(*this, entity, initKind, opaqueValue); if (result.isInvalid()) Invalid = true; else { @@ -10708,42 +11106,41 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, // Find the appropriate context according to the above. DC = CurContext; + + // Skip class contexts. If someone can cite chapter and verse + // for this behavior, that would be nice --- it's what GCC and + // EDG do, and it seems like a reasonable intent, but the spec + // really only says that checks for unqualified existing + // declarations should stop at the nearest enclosing namespace, + // not that they should only consider the nearest enclosing + // namespace. + while (DC->isRecord()) + DC = DC->getParent(); + + DeclContext *LookupDC = DC; + while (LookupDC->isTransparentContext()) + LookupDC = LookupDC->getParent(); + while (true) { - // Skip class contexts. If someone can cite chapter and verse - // for this behavior, that would be nice --- it's what GCC and - // EDG do, and it seems like a reasonable intent, but the spec - // really only says that checks for unqualified existing - // declarations should stop at the nearest enclosing namespace, - // not that they should only consider the nearest enclosing - // namespace. - while (DC->isRecord() || DC->isTransparentContext()) - DC = DC->getParent(); - - LookupQualifiedName(Previous, DC); + LookupQualifiedName(Previous, LookupDC); // TODO: decide what we think about using declarations. - if (isLocal || !Previous.empty()) + if (isLocal) break; + if (!Previous.empty()) { + DC = LookupDC; + break; + } + if (isTemplateId) { - if (isa<TranslationUnitDecl>(DC)) break; + if (isa<TranslationUnitDecl>(LookupDC)) break; } else { - if (DC->isFileContext()) break; + if (LookupDC->isFileContext()) break; } - DC = DC->getParent(); + LookupDC = LookupDC->getParent(); } - // C++ [class.friend]p1: A friend of a class is a function or - // class that is not a member of the class . . . - // C++11 changes this for both friend types and functions. - // Most C++ 98 compilers do seem to give an error here, so - // we do, too. - if (!Previous.empty() && DC->Equals(CurContext)) - Diag(DS.getFriendSpecLoc(), - getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_friend_is_member : - diag::err_friend_is_member); - DCScope = getScopeForDeclContext(S, DC); // C++ [class.friend]p6: @@ -10900,6 +11297,7 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { Diag(DelLoc, diag::err_deleted_non_function); return; } + if (const FunctionDecl *Prev = Fn->getPreviousDecl()) { // Don't consider the implicit declaration we generate for explicit // specializations. FIXME: Do not generate these implicit declarations. @@ -10910,7 +11308,29 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { } // If the declaration wasn't the first, we delete the function anyway for // recovery. + Fn = Fn->getCanonicalDecl(); } + + if (Fn->isDeleted()) + return; + + // See if we're deleting a function which is already known to override a + // non-deleted virtual function. + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) { + bool IssuedDiagnostic = false; + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); + I != E; ++I) { + if (!(*MD->begin_overridden_methods())->isDeleted()) { + if (!IssuedDiagnostic) { + Diag(DelLoc, diag::err_deleted_override) << MD->getDeclName(); + IssuedDiagnostic = true; + } + Diag((*I)->getLocation(), diag::note_overridden_virtual_function); + } + } + } + Fn->setDeletedAsWritten(); } @@ -10941,6 +11361,9 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { // on it. Pattern->isDefined(Primary); + // If the method was defaulted on its first declaration, we will have + // already performed the checking in CheckCompletedCXXClass. Such a + // declaration doesn't trigger an implicit definition. if (Primary == Primary->getCanonicalDecl()) return; @@ -11268,8 +11691,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, // Ignore any vtable uses in unevaluated operands or for classes that do // not have a vtable. if (!Class->isDynamicClass() || Class->isDependentContext() || - CurContext->isDependentContext() || - ExprEvalContexts.back().Context == Unevaluated) + CurContext->isDependentContext() || isUnevaluatedContext()) return; // Try to insert this class into the map. @@ -11457,10 +11879,10 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); InitializationKind InitKind = InitializationKind::CreateDefault(ObjCImplementation->getLocation()); - - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - ExprResult MemberInit = - InitSeq.Perform(*this, InitEntity, InitKind, MultiExprArg()); + + InitializationSequence InitSeq(*this, InitEntity, InitKind, None); + ExprResult MemberInit = + InitSeq.Perform(*this, InitEntity, InitKind, None); MemberInit = MaybeCreateExprWithCleanups(MemberInit); // Note, MemberInit could actually come back empty if no initialization // is required (e.g., because it would call a trivial default constructor) @@ -11816,3 +12238,94 @@ bool Sema::CheckCUDATarget(CUDAFunctionTarget CallerTarget, return false; } + +/// HandleMSProperty - Analyze a __delcspec(property) field of a C++ class. +/// +MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, + SourceLocation DeclStart, + Declarator &D, Expr *BitWidth, + InClassInitStyle InitStyle, + AccessSpecifier AS, + AttributeList *MSPropertyAttr) { + IdentifierInfo *II = D.getIdentifier(); + if (!II) { + Diag(DeclStart, diag::err_anonymous_property); + return NULL; + } + SourceLocation Loc = D.getIdentifierLoc(); + + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + QualType T = TInfo->getType(); + if (getLangOpts().CPlusPlus) { + CheckExtraCXXDefaultArguments(D); + + if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, + UPPC_DataMemberType)) { + D.setInvalidType(); + T = Context.IntTy; + TInfo = Context.getTrivialTypeSourceInfo(T, Loc); + } + } + + DiagnoseFunctionSpecifiers(D.getDeclSpec()); + + if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_invalid_thread) + << DeclSpec::getSpecifierName(TSCS); + + // Check to see if this name was declared as a member previously + NamedDecl *PrevDecl = 0; + LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); + LookupName(Previous, S); + switch (Previous.getResultKind()) { + case LookupResult::Found: + case LookupResult::FoundUnresolvedValue: + PrevDecl = Previous.getAsSingle<NamedDecl>(); + break; + + case LookupResult::FoundOverloaded: + PrevDecl = Previous.getRepresentativeDecl(); + break; + + case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::Ambiguous: + break; + } + + if (PrevDecl && PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + + if (PrevDecl && !isDeclInScope(PrevDecl, Record, S)) + PrevDecl = 0; + + SourceLocation TSSL = D.getLocStart(); + MSPropertyDecl *NewPD; + const AttributeList::PropertyData &Data = MSPropertyAttr->getPropertyData(); + NewPD = new (Context) MSPropertyDecl(Record, Loc, + II, T, TInfo, TSSL, + Data.GetterId, Data.SetterId); + ProcessDeclAttributes(TUScope, NewPD, D); + NewPD->setAccess(AS); + + if (NewPD->isInvalidDecl()) + Record->setInvalidDecl(); + + if (D.getDeclSpec().isModulePrivateSpecified()) + NewPD->setModulePrivate(); + + if (NewPD->isInvalidDecl() && PrevDecl) { + // Don't introduce NewFD into scope; there's already something + // with the same name in the same scope. + } else if (II) { + PushOnScopeChains(NewPD, S); + } else + Record->addDecl(NewPD); + + return NewPD; +} diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 66fdc67e41..f33e7bcb16 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -151,7 +151,8 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, if (ObjCMethodFamily Family = Overridden->getMethodFamily()) Diag(Overridden->getLocation(), - diag::note_related_result_type_overridden_family) + diag::note_related_result_type_family) + << /*overridden method*/ 0 << Family; else Diag(Overridden->getLocation(), @@ -192,7 +193,7 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, /// \brief Check a method declaration for compatibility with the Objective-C /// ARC conventions. -static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { +bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) { ObjCMethodFamily family = method->getMethodFamily(); switch (family) { case OMF_None: @@ -206,17 +207,17 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { return false; case OMF_dealloc: - if (!S.Context.hasSameType(method->getResultType(), S.Context.VoidTy)) { + if (!Context.hasSameType(method->getResultType(), Context.VoidTy)) { SourceRange ResultTypeRange; if (const TypeSourceInfo *ResultTypeInfo = method->getResultTypeSourceInfo()) ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); if (ResultTypeRange.isInvalid()) - S.Diag(method->getLocation(), diag::error_dealloc_bad_result_type) + Diag(method->getLocation(), diag::error_dealloc_bad_result_type) << method->getResultType() << FixItHint::CreateInsertion(method->getSelectorLoc(0), "(void)"); else - S.Diag(method->getLocation(), diag::error_dealloc_bad_result_type) + Diag(method->getLocation(), diag::error_dealloc_bad_result_type) << method->getResultType() << FixItHint::CreateReplacement(ResultTypeRange, "void"); return true; @@ -225,11 +226,11 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { case OMF_init: // If the method doesn't obey the init rules, don't bother annotating it. - if (S.checkInitMethod(method, QualType())) + if (checkInitMethod(method, QualType())) return true; - method->addAttr(new (S.Context) NSConsumesSelfAttr(SourceLocation(), - S.Context)); + method->addAttr(new (Context) NSConsumesSelfAttr(SourceLocation(), + Context)); // Don't add a second copy of this attribute, but otherwise don't // let it be suppressed. @@ -248,8 +249,8 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { break; } - method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(), - S.Context)); + method->addAttr(new (Context) NSReturnsRetainedAttr(SourceLocation(), + Context)); return false; } @@ -520,8 +521,14 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { QualType T = TDecl->getUnderlyingType(); if (T->isObjCObjectType()) { - if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) + if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); + // This handles the following case: + // @interface NewI @end + // typedef NewI DeprI __attribute__((deprecated("blah"))) + // @interface SI : DeprI /* warn here */ @end + (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc); + } } } @@ -738,7 +745,10 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, << ProtocolId[i].first; continue; } - + // If this is a forward protocol declaration, get its definition. + if (!PDecl->isThisDeclarationADefinition() && PDecl->getDefinition()) + PDecl = PDecl->getDefinition(); + (void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second); // If this is a forward declaration and we are supposed to warn in this @@ -1035,7 +1045,7 @@ Decl *Sema::ActOnStartClassImplementation( ObjCImplementationDecl* IMPDecl = ObjCImplementationDecl::Create(Context, CurContext, IDecl, SDecl, - ClassLoc, AtClassImplLoc); + ClassLoc, AtClassImplLoc, SuperClassLoc); if (CheckObjCDeclScope(IMPDecl)) return ActOnObjCContainerStartDefinition(IMPDecl); @@ -1176,14 +1186,18 @@ void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, return; } - if (!IncompleteImpl) { - Diag(ImpLoc, diag::warn_incomplete_impl); - IncompleteImpl = true; - } - if (DiagID == diag::warn_unimplemented_protocol_method) - Diag(ImpLoc, DiagID) << method->getDeclName(); - else - Diag(method->getLocation(), DiagID) << method->getDeclName(); + // FIXME: For now ignore 'IncompleteImpl'. + // Previously we grouped all unimplemented methods under a single + // warning, but some users strongly voiced that they would prefer + // separate warnings. We will give that approach a try, as that + // matches what we do with protocols. + + Diag(ImpLoc, DiagID) << method->getDeclName(); + + // Issue a note to the original declaration. + SourceLocation MethodLoc = method->getLocStart(); + if (MethodLoc.isValid()) + Diag(MethodLoc, diag::note_method_declared_at) << method; } /// Determines if type B can be substituted for type A. Returns true if we can @@ -1627,8 +1641,6 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, if (Diags.getDiagnosticLevel(DIAG, ImpLoc) != DiagnosticsEngine::Ignored) { WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); - Diag(method->getLocation(), diag::note_method_declared_at) - << method->getDeclName(); Diag(CDecl->getLocation(), diag::note_required_for_protocol_at) << PDecl->getDeclName(); } @@ -1650,8 +1662,6 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, if (Diags.getDiagnosticLevel(DIAG, ImpLoc) != DiagnosticsEngine::Ignored) { WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); - Diag(method->getLocation(), diag::note_method_declared_at) - << method->getDeclName(); Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) << PDecl->getDeclName(); } @@ -1686,7 +1696,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, !InsMap.count((*I)->getSelector())) { if (ImmediateClass) WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl, - diag::note_undef_method_impl); + diag::warn_undef_method_impl); continue; } else { ObjCMethodDecl *ImpMethodDecl = @@ -1716,7 +1726,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, if (!ClsMap.count((*I)->getSelector())) { if (ImmediateClass) WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl, - diag::note_undef_method_impl); + diag::warn_undef_method_impl); } else { ObjCMethodDecl *ImpMethodDecl = IMPDecl->getClassMethod((*I)->getSelector()); @@ -1826,7 +1836,7 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, if (!(LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCRuntime.isNonFragile()) || IDecl->isObjCRequiresPropertyDefs()) - DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); + DiagnoseUnimplementedProperties(S, IMPDecl, CDecl); SelectorSet ClsMap; for (ObjCImplementationDecl::classmeth_iterator @@ -1873,17 +1883,7 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, E = C->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, InsMap, ClsMap, CDecl); - // Report unimplemented properties in the category as well. - // When reporting on missing setter/getters, do not report when - // setter/getter is implemented in category's primary class - // implementation. - if (ObjCInterfaceDecl *ID = C->getClassInterface()) - if (ObjCImplDecl *IMP = ID->getImplementation()) { - for (ObjCImplementationDecl::instmeth_iterator - I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I) - InsMap.insert((*I)->getSelector()); - } - DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); + DiagnoseUnimplementedProperties(S, IMPDecl, CDecl); } } else llvm_unreachable("invalid ObjCContainerDecl type."); @@ -2075,17 +2075,24 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, } void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { + // Record at the head of the list whether there were 0, 1, or >= 2 methods + // inside categories. + if (ObjCCategoryDecl * + CD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) + if (!CD->IsClassExtension() && List->getBits() < 2) + List->setBits(List->getBits()+1); + // If the list is empty, make it a singleton list. if (List->Method == 0) { List->Method = Method; - List->Next = 0; + List->setNext(0); return; } // We've seen a method with this name, see if we have already seen this type // signature. ObjCMethodList *Previous = List; - for (; List; Previous = List, List = List->Next) { + for (; List; Previous = List, List = List->getNext()) { if (!MatchTwoMethodDeclarations(Method, List->Method)) continue; @@ -2114,7 +2121,7 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>(); - Previous->Next = new (Mem) ObjCMethodList(Method, 0); + Previous->setNext(new (Mem) ObjCMethodList(Method, 0)); } /// \brief Read the contents of the method pool for a given selector from @@ -2176,7 +2183,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, // Gather the non-hidden methods. ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; llvm::SmallVector<ObjCMethodDecl *, 4> Methods; - for (ObjCMethodList *M = &MethList; M; M = M->Next) { + for (ObjCMethodList *M = &MethList; M; M = M->getNext()) { if (M->Method && !M->Method->isHidden()) { // If we're not supposed to warn about mismatches, we're done. if (!warn) @@ -2726,9 +2733,9 @@ private: return; // - categories, - for (ObjCInterfaceDecl::visible_categories_iterator - cat = iface->visible_categories_begin(), - catEnd = iface->visible_categories_end(); + for (ObjCInterfaceDecl::known_categories_iterator + cat = iface->known_categories_begin(), + catEnd = iface->known_categories_end(); cat != catEnd; ++cat) { search(*cat); } @@ -2758,7 +2765,8 @@ private: void search(ObjCContainerDecl *container) { // Check for a method in this container which matches this selector. ObjCMethodDecl *meth = container->getMethod(Method->getSelector(), - Method->isInstanceMethod()); + Method->isInstanceMethod(), + /*AllowHidden=*/true); // If we find one, record it and bail out. if (meth) { @@ -2792,10 +2800,47 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, i = overrides.begin(), e = overrides.end(); i != e; ++i) { ObjCMethodDecl *overridden = *i; - if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) || - CurrentClass != overridden->getClassInterface() || - overridden->isOverriding()) - hasOverriddenMethodsInBaseOrProtocol = true; + if (!hasOverriddenMethodsInBaseOrProtocol) { + if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) || + CurrentClass != overridden->getClassInterface() || + overridden->isOverriding()) { + hasOverriddenMethodsInBaseOrProtocol = true; + + } else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) { + // OverrideSearch will return as "overridden" the same method in the + // interface. For hasOverriddenMethodsInBaseOrProtocol, we need to + // check whether a category of a base class introduced a method with the + // same selector, after the interface method declaration. + // To avoid unnecessary lookups in the majority of cases, we use the + // extra info bits in GlobalMethodPool to check whether there were any + // category methods with this selector. + GlobalMethodPool::iterator It = + MethodPool.find(ObjCMethod->getSelector()); + if (It != MethodPool.end()) { + ObjCMethodList &List = + ObjCMethod->isInstanceMethod()? It->second.first: It->second.second; + unsigned CategCount = List.getBits(); + if (CategCount > 0) { + // If the method is in a category we'll do lookup if there were at + // least 2 category methods recorded, otherwise only one will do. + if (CategCount > 1 || + !isa<ObjCCategoryImplDecl>(overridden->getDeclContext())) { + OverrideSearch overrides(*this, overridden); + for (OverrideSearch::iterator + OI= overrides.begin(), OE= overrides.end(); OI!=OE; ++OI) { + ObjCMethodDecl *SuperOverridden = *OI; + if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) || + CurrentClass != SuperOverridden->getClassInterface()) { + hasOverriddenMethodsInBaseOrProtocol = true; + overridden->setOverriding(true); + break; + } + } + } + } + } + } + } // Propagate down the 'related result type' bit from overridden methods. if (RTC != Sema::RTC_Incompatible && overridden->hasRelatedResultType()) @@ -2928,7 +2973,7 @@ Decl *Sema::ActOnMethodDeclaration( ParmVarDecl* Param = CheckParameter(ObjCMethod, StartLoc, ArgInfo[i].NameLoc, ArgInfo[i].Name, - ArgType, DI, SC_None, SC_None); + ArgType, DI, SC_None); Param->setObjCMethodScopeInfo(i); @@ -3030,7 +3075,7 @@ Decl *Sema::ActOnMethodDeclaration( bool ARCError = false; if (getLangOpts().ObjCAutoRefCount) - ARCError = CheckARCMethodDecl(*this, ObjCMethod); + ARCError = CheckARCMethodDecl(ObjCMethod); // Infer the related result type when possible. if (!ARCError && RTC == Sema::RTC_Compatible && @@ -3159,7 +3204,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T, } VarDecl *New = VarDecl::Create(Context, CurContext, StartLoc, IdLoc, Id, - T, TInfo, SC_None, SC_None); + T, TInfo, SC_None); New->setExceptionVariable(true); // In ARC, infer 'retaining' for variables of retainable type. @@ -3179,15 +3224,17 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { Diag(DS.getStorageClassSpecLoc(), diag::warn_register_objc_catch_parm) << FixItHint::CreateRemoval(SourceRange(DS.getStorageClassSpecLoc())); - } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { + } else if (DeclSpec::SCS SCS = DS.getStorageClassSpec()) { Diag(DS.getStorageClassSpecLoc(), diag::err_storage_spec_on_catch_parm) - << DS.getStorageClassSpec(); - } - if (D.getDeclSpec().isThreadSpecified()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + << DeclSpec::getSpecifierName(SCS); + } + if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_invalid_thread) + << DeclSpec::getSpecifierName(TSCS); D.getMutableDeclSpec().ClearStorageClassSpecs(); - DiagnoseFunctionSpecifiers(D); + DiagnoseFunctionSpecifiers(D.getDeclSpec()); // Check that there are no default arguments inside the type of this // exception object (C++ only). diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index ab8dcd1ad4..1a5f4824d0 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -124,7 +124,7 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { return SourceFPT; // Compute or instantiate the exception specification now. - if (FPT->getExceptionSpecType() == EST_Unevaluated) + if (SourceFPT->getExceptionSpecType() == EST_Unevaluated) EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl)); else InstantiateExceptionSpec(Loc, SourceDecl); @@ -1011,7 +1011,6 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::ConditionalOperatorClass: case Expr::CompoundLiteralExprClass: case Expr::CXXConstCastExprClass: - case Expr::CXXDefaultArgExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::DesignatedInitExprClass: case Expr::ExprWithCleanupsClass: @@ -1044,6 +1043,12 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::StmtExprClass: return CT_Can; + case Expr::CXXDefaultArgExprClass: + return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr()); + + case Expr::CXXDefaultInitExprClass: + return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr()); + case Expr::ChooseExprClass: if (E->isTypeDependent() || E->isValueDependent()) return CT_Dependent; @@ -1111,6 +1116,9 @@ CanThrowResult Sema::canThrow(const Expr *E) { // These expressions can never throw. return CT_Cannot; + case Expr::MSPropertyRefExprClass: + llvm_unreachable("Invalid class for expression"); + #define STMT(CLASS, PARENT) case Expr::CLASS##Class: #define STMT_RANGE(Base, First, Last) #define LAST_STMT_RANGE(BASE, FIRST, LAST) diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 69e06ea88f..dd05b82236 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -55,6 +55,12 @@ bool Sema::CanUseDecl(NamedDecl *D) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isDeleted()) return false; + + // If the function has a deduced return type, and we can't deduce it, + // then we can't use it either. + if (getLangOpts().CPlusPlus1y && FD->getResultType()->isUndeducedType() && + DeduceReturnType(FD, SourceLocation(), /*Diagnose*/false)) + return false; } // See if this function is unavailable. @@ -162,7 +168,7 @@ static bool hasAnyExplicitStorageClass(const FunctionDecl *D) { for (FunctionDecl::redecl_iterator I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I) { - if (I->getStorageClassAsWritten() != SC_None) + if (I->getStorageClass() != SC_None) return true; } return false; @@ -214,19 +220,24 @@ static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S, : diag::warn_internal_in_extern_inline) << /*IsVar=*/!UsedFn << D; - // Suggest "static" on the inline function, if possible. - if (!hasAnyExplicitStorageClass(Current)) { - const FunctionDecl *FirstDecl = Current->getCanonicalDecl(); - SourceLocation DeclBegin = FirstDecl->getSourceRange().getBegin(); - S.Diag(DeclBegin, diag::note_convert_inline_to_static) - << Current << FixItHint::CreateInsertion(DeclBegin, "static "); - } + S.MaybeSuggestAddingStaticToDecl(Current); S.Diag(D->getCanonicalDecl()->getLocation(), diag::note_internal_decl_declared_here) << D; } +void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) { + const FunctionDecl *First = Cur->getFirstDeclaration(); + + // Suggest "static" on the function, if possible. + if (!hasAnyExplicitStorageClass(First)) { + SourceLocation DeclBegin = First->getSourceRange().getBegin(); + Diag(DeclBegin, diag::note_convert_inline_to_static) + << Cur << FixItHint::CreateInsertion(DeclBegin, "static "); + } +} + /// \brief Determine whether the use of this declaration is valid, and /// emit any corresponding diagnostics. /// @@ -273,6 +284,12 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, NoteDeletedFunction(FD); return true; } + + // If the function has a deduced return type, and we can't deduce it, + // then we can't use it either. + if (getLangOpts().CPlusPlus1y && FD->getResultType()->isUndeducedType() && + DeduceReturnType(FD, Loc)) + return true; } DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass); @@ -450,6 +467,62 @@ static void CheckForNullPointerDereference(Sema &S, Expr *E) { } } +static void DiagnoseDirectIsaAccess(Sema &S, const ObjCIvarRefExpr *OIRE, + SourceLocation AssignLoc, + const Expr* RHS) { + const ObjCIvarDecl *IV = OIRE->getDecl(); + if (!IV) + return; + + DeclarationName MemberName = IV->getDeclName(); + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); + if (!Member || !Member->isStr("isa")) + return; + + const Expr *Base = OIRE->getBase(); + QualType BaseType = Base->getType(); + if (OIRE->isArrow()) + BaseType = BaseType->getPointeeType(); + if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) + if (ObjCInterfaceDecl *IDecl = OTy->getInterface()) { + ObjCInterfaceDecl *ClassDeclared = 0; + ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); + if (!ClassDeclared->getSuperClass() + && (*ClassDeclared->ivar_begin()) == IV) { + if (RHS) { + NamedDecl *ObjectSetClass = + S.LookupSingleName(S.TUScope, + &S.Context.Idents.get("object_setClass"), + SourceLocation(), S.LookupOrdinaryName); + if (ObjectSetClass) { + SourceLocation RHSLocEnd = S.PP.getLocForEndOfToken(RHS->getLocEnd()); + S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_assign) << + FixItHint::CreateInsertion(OIRE->getLocStart(), "object_setClass(") << + FixItHint::CreateReplacement(SourceRange(OIRE->getOpLoc(), + AssignLoc), ",") << + FixItHint::CreateInsertion(RHSLocEnd, ")"); + } + else + S.Diag(OIRE->getLocation(), diag::warn_objc_isa_assign); + } else { + NamedDecl *ObjectGetClass = + S.LookupSingleName(S.TUScope, + &S.Context.Idents.get("object_getClass"), + SourceLocation(), S.LookupOrdinaryName); + if (ObjectGetClass) + S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_use) << + FixItHint::CreateInsertion(OIRE->getLocStart(), "object_getClass(") << + FixItHint::CreateReplacement( + SourceRange(OIRE->getOpLoc(), + OIRE->getLocEnd()), ")"); + else + S.Diag(OIRE->getLocation(), diag::warn_objc_isa_use); + } + S.Diag(IV->getLocation(), diag::note_ivar_decl); + } + } +} + ExprResult Sema::DefaultLvalueConversion(Expr *E) { // Handle any placeholder expressions which made it here. if (E->getType()->isPlaceholderType()) { @@ -491,7 +564,22 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { } CheckForNullPointerDereference(*this, E); - + if (const ObjCIsaExpr *OISA = dyn_cast<ObjCIsaExpr>(E->IgnoreParenCasts())) { + NamedDecl *ObjectGetClass = LookupSingleName(TUScope, + &Context.Idents.get("object_getClass"), + SourceLocation(), LookupOrdinaryName); + if (ObjectGetClass) + Diag(E->getExprLoc(), diag::warn_objc_isa_use) << + FixItHint::CreateInsertion(OISA->getLocStart(), "object_getClass(") << + FixItHint::CreateReplacement( + SourceRange(OISA->getOpLoc(), OISA->getIsaMemberLoc()), ")"); + else + Diag(E->getExprLoc(), diag::warn_objc_isa_use); + } + else if (const ObjCIvarRefExpr *OIRE = + dyn_cast<ObjCIvarRefExpr>(E->IgnoreParenCasts())) + DiagnoseDirectIsaAccess(*this, OIRE, SourceLocation(), /* Expr*/0); + // C++ [conv.lval]p1: // [...] If T is a non-class type, the type of the prvalue is the // cv-unqualified version of T. Otherwise, the type of the @@ -730,7 +818,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return ExprError(); ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), - E->getLocStart(), MultiExprArg(), + E->getLocStart(), None, E->getLocEnd()); if (Call.isInvalid()) return ExprError(); @@ -1431,7 +1519,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, ExprResult Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, - const CXXScopeSpec *SS) { + const CXXScopeSpec *SS, NamedDecl *FoundD) { if (getLangOpts().CUDA) if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) { @@ -1455,7 +1543,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, : NestedNameSpecifierLoc(), SourceLocation(), D, refersToEnclosingScope, - NameInfo, Ty, VK); + NameInfo, Ty, VK, FoundD); MarkDeclRefReferenced(E); @@ -1563,9 +1651,10 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>( CallsUndergoingInstantiation.back()->getCallee()); - CXXMethodDecl *DepMethod; - if (CurMethod->getTemplatedKind() == + if (CurMethod->isDependentContext()) + DepMethod = CurMethod; + else if (CurMethod->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization) DepMethod = cast<CXXMethodDecl>(CurMethod->getPrimaryTemplate()-> getInstantiatedFromMemberTemplate()->getTemplatedDecl()); @@ -1839,15 +1928,17 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. if (R.empty()) { - // In Microsoft mode, if we are inside a template class member function - // and we can't resolve an identifier then assume the identifier is type - // dependent. The goal is to postpone name lookup to instantiation time - // to be able to search into type dependent base classes. - if (getLangOpts().MicrosoftMode && CurContext->isDependentContext() && - isa<CXXMethodDecl>(CurContext)) - return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, - IsAddressOfOperand, TemplateArgs); + // whose parent class has dependent base classes, and we can't resolve + // an identifier, then assume the identifier is type dependent. The + // goal is to postpone name lookup to instantiation time to be able to + // search into the type dependent base classes. + if (getLangOpts().MicrosoftMode) { + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext); + if (MD && MD->getParent()->hasAnyDependentBases()) + return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, + IsAddressOfOperand, TemplateArgs); + } CorrectionCandidateCallback DefaultValidator; if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator)) @@ -2055,7 +2146,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(), - Loc, + Loc, IV->getLocation(), SelfExpr.take(), true, true); @@ -2360,8 +2451,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // If this is a single, fully-resolved result and we don't need ADL, // just build an ordinary singleton decl ref. if (!NeedsADL && R.isSingleResult() && !R.getAsSingle<FunctionTemplateDecl>()) - return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), - R.getFoundDecl()); + return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(), + R.getRepresentativeDecl()); // We only need to check the declaration if there's exactly one // result, because in the overloaded case the results can only be @@ -2389,7 +2480,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, - NamedDecl *D) { + NamedDecl *D, NamedDecl *FoundD) { assert(D && "Cannot refer to a NULL declaration"); assert(!isa<FunctionTemplateDecl>(D) && "Cannot refer unambiguously to a function template"); @@ -2559,6 +2650,10 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, break; } + case Decl::MSProperty: + valueKind = VK_LValue; + break; + case Decl::CXXMethod: // If we're referring to a method with an __unknown_anytype // result type, make the entire expression __unknown_anytype. @@ -2585,7 +2680,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, break; } - return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS); + return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD); } } @@ -2683,8 +2778,7 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) { // C++11 [lex.ext]p6: The literal L is treated as a call of the form // operator "" X (ch) return BuildCookedLiteralOperatorCall(*this, UDLScope, UDSuffix, UDSuffixLoc, - llvm::makeArrayRef(&Lit, 1), - Tok.getLocation()); + Lit, Tok.getLocation()); } ExprResult Sema::ActOnIntegerConstant(SourceLocation Loc, uint64_t Val) { @@ -2781,7 +2875,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { // Perform literal operator lookup to determine if we're building a raw // literal or a cooked one. LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName); - switch (LookupLiteralOperator(UDLScope, R, llvm::makeArrayRef(&CookedTy, 1), + switch (LookupLiteralOperator(UDLScope, R, CookedTy, /*AllowRawAndTemplate*/true)) { case LOLR_Error: return ExprError(); @@ -2797,8 +2891,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Lit = IntegerLiteral::Create(Context, ResultVal, CookedTy, Tok.getLocation()); } - return BuildLiteralOperatorCall(R, OpNameInfo, - llvm::makeArrayRef(&Lit, 1), + return BuildLiteralOperatorCall(R, OpNameInfo, Lit, Tok.getLocation()); } @@ -2814,8 +2907,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Expr *Lit = StringLiteral::Create( Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii, /*Pascal*/false, StrTy, &TokLoc, 1); - return BuildLiteralOperatorCall(R, OpNameInfo, - llvm::makeArrayRef(&Lit, 1), TokLoc); + return BuildLiteralOperatorCall(R, OpNameInfo, Lit, TokLoc); } case LOLR_Template: @@ -2833,8 +2925,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { TemplateArgumentLocInfo ArgInfo; ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); } - return BuildLiteralOperatorCall(R, OpNameInfo, ArrayRef<Expr*>(), - Tok.getLocation(), &ExplicitArgs); + return BuildLiteralOperatorCall(R, OpNameInfo, None, Tok.getLocation(), + &ExplicitArgs); } llvm_unreachable("unexpected literal operator lookup result"); @@ -3012,16 +3104,17 @@ static bool CheckExtensionTraitOperandType(Sema &S, QualType T, SourceRange ArgRange, UnaryExprOrTypeTrait TraitKind) { // C99 6.5.3.4p1: - if (T->isFunctionType()) { - // alignof(function) is allowed as an extension. - if (TraitKind == UETT_SizeOf) - S.Diag(Loc, diag::ext_sizeof_function_type) << ArgRange; + if (T->isFunctionType() && + (TraitKind == UETT_SizeOf || TraitKind == UETT_AlignOf)) { + // sizeof(function)/alignof(function) is allowed as an extension. + S.Diag(Loc, diag::ext_sizeof_alignof_function_type) + << TraitKind << ArgRange; return false; } // Allow sizeof(void)/alignof(void) as an extension. if (T->isVoidType()) { - S.Diag(Loc, diag::ext_sizeof_void_type) << TraitKind << ArgRange; + S.Diag(Loc, diag::ext_sizeof_alignof_void_type) << TraitKind << ArgRange; return false; } @@ -3044,6 +3137,24 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T, return false; } +/// \brief Check whether E is a pointer from a decayed array type (the decayed +/// pointer type is equal to T) and emit a warning if it is. +static void warnOnSizeofOnArrayDecay(Sema &S, SourceLocation Loc, QualType T, + Expr *E) { + // Don't warn if the operation changed the type. + if (T != E->getType()) + return; + + // Now look for array decays. + ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E); + if (!ICE || ICE->getCastKind() != CK_ArrayToPointerDecay) + return; + + S.Diag(Loc, diag::warn_sizeof_array_decay) << ICE->getSourceRange() + << ICE->getType() + << ICE->getSubExpr()->getType(); +} + /// \brief Check the constrains on expression operands to unary type expression /// and type traits. /// @@ -3054,13 +3165,7 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T, bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind) { QualType ExprTy = E->getType(); - - // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, - // the result is the size of the referenced type." - // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the - // result shall be the alignment of the referenced type." - if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>()) - ExprTy = Ref->getPointeeType(); + assert(!ExprTy->isReferenceType()); if (ExprKind == UETT_VecStep) return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(), @@ -3076,10 +3181,9 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, ExprKind, E->getSourceRange())) return true; - // Completeing the expression's type may have changed it. + // Completing the expression's type may have changed it. ExprTy = E->getType(); - if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>()) - ExprTy = Ref->getPointeeType(); + assert(!ExprTy->isReferenceType()); if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(), E->getSourceRange(), ExprKind)) @@ -3097,6 +3201,16 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, } } } + + // Warn on "sizeof(array op x)" and "sizeof(x op array)", where the array + // decays into a pointer and returns an unintended result. This is most + // likely a typo for "sizeof(array) op x". + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E->IgnoreParens())) { + warnOnSizeofOnArrayDecay(*this, BO->getOperatorLoc(), BO->getType(), + BO->getLHS()); + warnOnSizeofOnArrayDecay(*this, BO->getOperatorLoc(), BO->getType(), + BO->getRHS()); + } } return false; @@ -3154,25 +3268,67 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, static bool CheckAlignOfExpr(Sema &S, Expr *E) { E = E->IgnoreParens(); - // alignof decl is always ok. - if (isa<DeclRefExpr>(E)) - return false; - // Cannot know anything else if the expression is dependent. if (E->isTypeDependent()) return false; - if (E->getBitField()) { + if (E->getObjectKind() == OK_BitField) { S.Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 1 << E->getSourceRange(); return true; } - // Alignment of a field access is always okay, so long as it isn't a - // bit-field. - if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) - if (isa<FieldDecl>(ME->getMemberDecl())) + ValueDecl *D = 0; + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + D = DRE->getDecl(); + } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + D = ME->getMemberDecl(); + } + + // If it's a field, require the containing struct to have a + // complete definition so that we can compute the layout. + // + // This requires a very particular set of circumstances. For a + // field to be contained within an incomplete type, we must in the + // process of parsing that type. To have an expression refer to a + // field, it must be an id-expression or a member-expression, but + // the latter are always ill-formed when the base type is + // incomplete, including only being partially complete. An + // id-expression can never refer to a field in C because fields + // are not in the ordinary namespace. In C++, an id-expression + // can implicitly be a member access, but only if there's an + // implicit 'this' value, and all such contexts are subject to + // delayed parsing --- except for trailing return types in C++11. + // And if an id-expression referring to a field occurs in a + // context that lacks a 'this' value, it's ill-formed --- except, + // agian, in C++11, where such references are allowed in an + // unevaluated context. So C++11 introduces some new complexity. + // + // For the record, since __alignof__ on expressions is a GCC + // extension, GCC seems to permit this but always gives the + // nonsensical answer 0. + // + // We don't really need the layout here --- we could instead just + // directly check for all the appropriate alignment-lowing + // attributes --- but that would require duplicating a lot of + // logic that just isn't worth duplicating for such a marginal + // use-case. + if (FieldDecl *FD = dyn_cast_or_null<FieldDecl>(D)) { + // Fast path this check, since we at least know the record has a + // definition if we can find a member of it. + if (!FD->getParent()->isCompleteDefinition()) { + S.Diag(E->getExprLoc(), diag::err_alignof_member_of_incomplete_type) + << E->getSourceRange(); + return true; + } + + // Otherwise, if it's a field, and the field doesn't have + // reference type, then it must have a complete type (or be a + // flexible array member, which we explicitly want to + // white-list anyway), which makes the following checks trivial. + if (!FD->getType()->isReferenceType()) return false; + } return S.CheckUnaryExprOrTypeTraitOperand(E, UETT_AlignOf); } @@ -3227,7 +3383,7 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, isInvalid = CheckAlignOfExpr(*this, E); } else if (ExprKind == UETT_VecStep) { isInvalid = CheckVecStepExpr(E); - } else if (E->getBitField()) { // C99 6.5.3.4p1. + } else if (E->refersToBitField()) { // C99 6.5.3.4p1. Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0; isInvalid = true; } else { @@ -3559,14 +3715,11 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, Param); // Instantiate the expression. - MultiLevelTemplateArgumentList ArgList + MultiLevelTemplateArgumentList MutiLevelArgList = getTemplateInstantiationArgs(FD, 0, /*RelativeToPrimary=*/true); - std::pair<const TemplateArgument *, unsigned> Innermost - = ArgList.getInnermost(); InstantiatingTemplate Inst(*this, CallLoc, Param, - ArrayRef<TemplateArgument>(Innermost.first, - Innermost.second)); + MutiLevelArgList.getInnermost()); if (Inst) return ExprError(); @@ -3578,7 +3731,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, // default argument expression appears. ContextRAII SavedContext(*this, FD); LocalInstantiationScope Local(*this); - Result = SubstExpr(UninstExpr, ArgList); + Result = SubstExpr(UninstExpr, MutiLevelArgList); } if (Result.isInvalid()) return ExprError(); @@ -3591,7 +3744,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, /*FIXME:EqualLoc*/UninstExpr->getLocStart()); Expr *ResultE = Result.takeAs<Expr>(); - InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1); + InitializationSequence InitSeq(*this, Entity, Kind, ResultE); Result = InitSeq.Perform(*this, Entity, Kind, ResultE); if (Result.isInvalid()) return ExprError(); @@ -3807,6 +3960,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, Arg = ArgE.takeAs<Expr>(); } else { + assert(FDecl && "can't use default arguments without a known callee"); Param = FDecl->getParamDecl(i); ExprResult ArgExpr = @@ -3916,6 +4070,63 @@ Sema::CheckStaticArrayArgument(SourceLocation CallLoc, /// to have a function type. static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn); +/// Is the given type a placeholder that we need to lower out +/// immediately during argument processing? +static bool isPlaceholderToRemoveAsArg(QualType type) { + // Placeholders are never sugared. + const BuiltinType *placeholder = dyn_cast<BuiltinType>(type); + if (!placeholder) return false; + + switch (placeholder->getKind()) { + // Ignore all the non-placeholder types. +#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) +#define BUILTIN_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: +#include "clang/AST/BuiltinTypes.def" + return false; + + // We cannot lower out overload sets; they might validly be resolved + // by the call machinery. + case BuiltinType::Overload: + return false; + + // Unbridged casts in ARC can be handled in some call positions and + // should be left in place. + case BuiltinType::ARCUnbridgedCast: + return false; + + // Pseudo-objects should be converted as soon as possible. + case BuiltinType::PseudoObject: + return true; + + // The debugger mode could theoretically but currently does not try + // to resolve unknown-typed arguments based on known parameter types. + case BuiltinType::UnknownAny: + return true; + + // These are always invalid as call arguments and should be reported. + case BuiltinType::BoundMember: + case BuiltinType::BuiltinFn: + return true; + } + llvm_unreachable("bad builtin type kind"); +} + +/// Check an argument list for placeholders that we won't try to +/// handle later. +static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) { + // Apply this processing to all the arguments at once instead of + // dying at the first failure. + bool hasInvalid = false; + for (size_t i = 0, e = args.size(); i != e; i++) { + if (isPlaceholderToRemoveAsArg(args[i]->getType())) { + ExprResult result = S.CheckPlaceholderExpr(args[i]); + if (result.isInvalid()) hasInvalid = true; + else args[i] = result.take(); + } + } + return hasInvalid; +} + /// 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. @@ -3928,6 +4139,9 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, if (Result.isInvalid()) return ExprError(); Fn = Result.take(); + if (checkArgsForPlaceholders(*this, ArgExprs)) + return ExprError(); + if (getLangOpts().CPlusPlus) { // If this is a pseudo-destructor expression, build the call immediately. if (isa<CXXPseudoDestructorExpr>(Fn)) { @@ -3939,10 +4153,15 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, ArgExprs.back()->getLocEnd())); } - return Owned(new (Context) CallExpr(Context, Fn, MultiExprArg(), + return Owned(new (Context) CallExpr(Context, Fn, None, Context.VoidTy, VK_RValue, RParenLoc)); } + if (Fn->getType() == Context.PseudoObjectTy) { + ExprResult result = CheckPlaceholderExpr(Fn); + if (result.isInvalid()) return ExprError(); + Fn = result.take(); + } // Determine whether this is a dependent call inside a C++ template, // in which case we won't do any semantic analysis now. @@ -4290,12 +4509,12 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, return ExprError(); InitializedEntity Entity - = InitializedEntity::InitializeTemporary(literalType); + = InitializedEntity::InitializeCompoundLiteralInit(TInfo); InitializationKind Kind = InitializationKind::CreateCStyleCast(LParenLoc, SourceRange(LParenLoc, RParenLoc), /*InitList=*/true); - InitializationSequence InitSeq(*this, Entity, Kind, &LiteralExpr, 1); + InitializationSequence InitSeq(*this, Entity, Kind, LiteralExpr); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, LiteralExpr, &literalType); if (Result.isInvalid()) @@ -4808,7 +5027,7 @@ static bool checkCondition(Sema &S, Expr *Cond) { // C99 6.5.15p2 if (CondTy->isScalarType()) return false; - // OpenCL: Sec 6.3.i says the condition is allowed to be a vector or scalar. + // OpenCL v1.1 s6.3.i says the condition is allowed to be a vector or scalar. if (S.getLangOpts().OpenCL && CondTy->isVectorType()) return false; @@ -5069,9 +5288,9 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (LHSTy->isVectorType() || RHSTy->isVectorType()) return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false); - // OpenCL: If the condition is a vector, and both operands are scalar, + // If the condition is a vector, and both operands are scalar, // attempt to implicity convert them to the vector type to act like the - // built in select. + // built in select. (OpenCL v1.1 s6.3.i) if (getLangOpts().OpenCL && CondTy->isVectorType()) if (checkConditionalConvertScalarsToVectors(*this, LHS, RHS, CondTy)) return QualType(); @@ -5338,7 +5557,8 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, // Make sure this is really a binary operator that is safe to pass into // BinaryOperator::getOverloadedOpcode(), e.g. it's not a subscript op. OverloadedOperatorKind OO = Call->getOperator(); - if (OO < OO_Plus || OO > OO_Arrow) + if (OO < OO_Plus || OO > OO_Arrow || + OO == OO_PlusPlus || OO == OO_MinusMinus) return false; BinaryOperatorKind OpKind = BinaryOperator::getOverloadedOpcode(OO); @@ -6715,18 +6935,6 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, bool IsCompAssign) { checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); - // C99 6.5.7p2: Each of the operands shall have integer type. - if (!LHS.get()->getType()->hasIntegerRepresentation() || - !RHS.get()->getType()->hasIntegerRepresentation()) - return InvalidOperands(Loc, LHS, RHS); - - // C++0x: Don't allow scoped enums. FIXME: Use something better than - // hasIntegerRepresentation() above instead of this. - if (isScopedEnumerationType(LHS.get()->getType()) || - isScopedEnumerationType(RHS.get()->getType())) { - return InvalidOperands(Loc, LHS, RHS); - } - // Vector shifts promote their scalar inputs to vector type. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) @@ -6748,7 +6956,19 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, RHS = UsualUnaryConversions(RHS.take()); if (RHS.isInvalid()) return QualType(); + QualType RHSType = RHS.get()->getType(); + // C99 6.5.7p2: Each of the operands shall have integer type. + if (!LHSType->hasIntegerRepresentation() || + !RHSType->hasIntegerRepresentation()) + return InvalidOperands(Loc, LHS, RHS); + + // C++0x: Don't allow scoped enums. FIXME: Use something better than + // hasIntegerRepresentation() above instead of this. + if (isScopedEnumerationType(LHSType) || + isScopedEnumerationType(RHSType)) { + return InvalidOperands(Loc, LHS, RHS); + } // Sanity-check shift operands DiagnoseBadShiftValues(*this, LHS, RHS, Loc, Opc, LHSType); @@ -7105,17 +7325,6 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } if (literalString) { - std::string resultComparison; - switch (Opc) { - case BO_LT: resultComparison = ") < 0"; break; - case BO_GT: resultComparison = ") > 0"; break; - case BO_LE: resultComparison = ") <= 0"; break; - case BO_GE: resultComparison = ") >= 0"; break; - case BO_EQ: resultComparison = ") == 0"; break; - case BO_NE: resultComparison = ") != 0"; break; - default: llvm_unreachable("Invalid comparison operator"); - } - DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_stringcompare) << isa<ObjCEncodeExpr>(literalStringStripped) @@ -8138,6 +8347,9 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp, << op->getType() << op->getSourceRange(); if (sfinae) return QualType(); + // Materialize the temporary as an lvalue so that we can take its address. + OrigOp = op = new (S.Context) + MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true); } else if (isa<ObjCSelectorExpr>(op)) { return S.Context.getPointerType(op->getType()); } else if (lval == Expr::LV_MemberFunction) { @@ -8393,6 +8605,36 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr, << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); } +/// Check if a bitwise-& is performed on an Objective-C pointer. This +/// is usually indicative of introspection within the Objective-C pointer. +static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R, + SourceLocation OpLoc) { + if (!S.getLangOpts().ObjC1) + return; + + const Expr *ObjCPointerExpr = 0, *OtherExpr = 0; + const Expr *LHS = L.get(); + const Expr *RHS = R.get(); + + if (LHS->IgnoreParenCasts()->getType()->isObjCObjectPointerType()) { + ObjCPointerExpr = LHS; + OtherExpr = RHS; + } + else if (RHS->IgnoreParenCasts()->getType()->isObjCObjectPointerType()) { + ObjCPointerExpr = RHS; + OtherExpr = LHS; + } + + // This warning is deliberately made very specific to reduce false + // positives with logic that uses '&' for hashing. This logic mainly + // looks for code trying to introspect into tagged pointers, which + // code should generally never do. + if (ObjCPointerExpr && isa<IntegerLiteral>(OtherExpr->IgnoreParenCasts())) { + S.Diag(OpLoc, diag::warn_objc_pointer_masking) + << ObjCPointerExpr->getSourceRange(); + } +} + /// CreateBuiltinBinOp - Creates a new built-in binary operation with /// operator @p Opc at location @c TokLoc. This routine only supports /// built-in operations; ActOnBinOp handles overloaded operators. @@ -8410,7 +8652,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, InitializationKind::CreateDirectList(RHSExpr->getLocStart()); InitializedEntity Entity = InitializedEntity::InitializeTemporary(LHSExpr->getType()); - InitializationSequence InitSeq(*this, Entity, Kind, &RHSExpr, 1); + InitializationSequence InitSeq(*this, Entity, Kind, RHSExpr); ExprResult Init = InitSeq.Perform(*this, Entity, Kind, RHSExpr); if (Init.isInvalid()) return Init; @@ -8470,6 +8712,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false); break; case BO_And: + checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc); case BO_Xor: case BO_Or: ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc); @@ -8532,6 +8775,24 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, CheckArrayAccess(LHS.get()); CheckArrayAccess(RHS.get()); + if (const ObjCIsaExpr *OISA = dyn_cast<ObjCIsaExpr>(LHS.get()->IgnoreParenCasts())) { + NamedDecl *ObjectSetClass = LookupSingleName(TUScope, + &Context.Idents.get("object_setClass"), + SourceLocation(), LookupOrdinaryName); + if (ObjectSetClass && isa<ObjCIsaExpr>(LHS.get())) { + SourceLocation RHSLocEnd = PP.getLocForEndOfToken(RHS.get()->getLocEnd()); + Diag(LHS.get()->getExprLoc(), diag::warn_objc_isa_assign) << + FixItHint::CreateInsertion(LHS.get()->getLocStart(), "object_setClass(") << + FixItHint::CreateReplacement(SourceRange(OISA->getOpLoc(), OpLoc), ",") << + FixItHint::CreateInsertion(RHSLocEnd, ")"); + } + else + Diag(LHS.get()->getExprLoc(), diag::warn_objc_isa_assign); + } + else if (const ObjCIvarRefExpr *OIRE = + dyn_cast<ObjCIvarRefExpr>(LHS.get()->IgnoreParenCasts())) + DiagnoseDirectIsaAccess(*this, OIRE, OpLoc, RHS.get()); + if (CompResultTy.isNull()) return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc, ResultTy, VK, OK, OpLoc, @@ -8693,6 +8954,33 @@ static void DiagnoseAdditionInShift(Sema &S, SourceLocation OpLoc, } } +static void DiagnoseShiftCompare(Sema &S, SourceLocation OpLoc, + Expr *LHSExpr, Expr *RHSExpr) { + CXXOperatorCallExpr *OCE = dyn_cast<CXXOperatorCallExpr>(LHSExpr); + if (!OCE) + return; + + FunctionDecl *FD = OCE->getDirectCallee(); + if (!FD || !FD->isOverloadedOperator()) + return; + + OverloadedOperatorKind Kind = FD->getOverloadedOperator(); + if (Kind != OO_LessLess && Kind != OO_GreaterGreater) + return; + + S.Diag(OpLoc, diag::warn_overloaded_shift_in_comparison) + << LHSExpr->getSourceRange() << RHSExpr->getSourceRange() + << (Kind == OO_LessLess); + SuggestParentheses(S, OCE->getOperatorLoc(), + S.PDiag(diag::note_precedence_silence) + << (Kind == OO_LessLess ? "<<" : ">>"), + OCE->getSourceRange()); + SuggestParentheses(S, OpLoc, + S.PDiag(diag::note_evaluate_comparison_first), + SourceRange(OCE->getArg(1)->getLocStart(), + RHSExpr->getLocEnd())); +} + /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky /// precedence. static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, @@ -8721,6 +9009,11 @@ static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, DiagnoseAdditionInShift(Self, OpLoc, LHSExpr, Shift); DiagnoseAdditionInShift(Self, OpLoc, RHSExpr, Shift); } + + // Warn on overloaded shift operators and comparisons, such as: + // cout << 5 == 4; + if (BinaryOperator::isComparisonOp(Opc)) + DiagnoseShiftCompare(Self, OpLoc, LHSExpr, RHSExpr); } // Binary Operators. 'Tok' is the token for the operator. @@ -9485,7 +9778,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, FunctionProtoType::ExtProtoInfo EPI; EPI.HasTrailingReturn = false; EPI.TypeQuals |= DeclSpec::TQ_const; - T = Context.getFunctionType(Context.DependentTy, ArrayRef<QualType>(), EPI); + T = Context.getFunctionType(Context.DependentTy, None, EPI); Sig = Context.getTrivialTypeSourceInfo(T); } @@ -9664,7 +9957,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (isa<FunctionNoProtoType>(FTy)) { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = Ext; - BlockTy = Context.getFunctionType(RetTy, ArrayRef<QualType>(), EPI); + BlockTy = Context.getFunctionType(RetTy, None, EPI); // Otherwise, if we don't need to change anything about the function type, // preserve its sugar structure. @@ -9689,7 +9982,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, } else { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn); - BlockTy = Context.getFunctionType(RetTy, ArrayRef<QualType>(), EPI); + BlockTy = Context.getFunctionType(RetTy, None, EPI); } DiagnoseUnusedParameters(BSI->TheDecl->param_begin(), @@ -9921,6 +10214,10 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, if (Hint.isNull() && !CheckInferredResultType) { ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); } + else if (CheckInferredResultType) { + SrcType = SrcType.getUnqualifiedType(); + DstType = DstType.getUnqualifiedType(); + } MayHaveConvFixit = true; break; case IncompatiblePointerSign: @@ -10037,6 +10334,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, if (CheckInferredResultType) EmitRelatedResultTypeNote(SrcExpr); + + if (Action == AA_Returning && ConvTy == IncompatiblePointer) + EmitRelatedResultTypeNoteForReturn(DstType); if (Complained) *Complained = true; @@ -10317,11 +10617,11 @@ namespace { } ExprResult Sema::TransformToPotentiallyEvaluated(Expr *E) { - assert(ExprEvalContexts.back().Context == Unevaluated && + assert(isUnevaluatedContext() && "Should only transform unevaluated expressions"); ExprEvalContexts.back().Context = ExprEvalContexts[ExprEvalContexts.size()-2].Context; - if (ExprEvalContexts.back().Context == Unevaluated) + if (isUnevaluatedContext()) return E; return TransformToPE(*this).TransformExpr(E); } @@ -10353,7 +10653,7 @@ void Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back(); if (!Rec.Lambdas.empty()) { - if (Rec.Context == Unevaluated) { + if (Rec.isUnevaluated()) { // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand // (Clause 5). @@ -10379,7 +10679,7 @@ void Sema::PopExpressionEvaluationContext() { // temporaries that we may have created as part of the evaluation of // the expression in that context: they aren't relevant because they // will never be constructed. - if (Rec.Context == Unevaluated || Rec.Context == ConstantEvaluated) { + if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) { ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects, ExprCleanupObjects.end()); ExprNeedsCleanups = Rec.ParentNeedsCleanups; @@ -10418,6 +10718,7 @@ static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) { switch (SemaRef.ExprEvalContexts.back().Context) { case Sema::Unevaluated: + case Sema::UnevaluatedAbstract: // We are in an expression that is not potentially evaluated; do nothing. // (Depending on how you read the standard, we actually do need to do // something here for null pointer constants, but the standard's @@ -10500,6 +10801,9 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { if (!Constructor->isUsed(false)) DefineImplicitMoveConstructor(Loc, Constructor); } + } else if (Constructor->getInheritedConstructor()) { + if (!Constructor->isUsed(false)) + DefineInheritingConstructor(Loc, Constructor); } MarkVTableUsed(Loc, Constructor->getParent()); @@ -10594,7 +10898,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { // Keep track of used but undefined functions. if (!Func->isDefined()) { - if (Func->getLinkage() != ExternalLinkage) + if (mightHaveNonExternalLinkage(Func)) UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); else if (Func->getMostRecentDecl()->isInlined() && (LangOpts.CPlusPlus || !LangOpts.GNUInline) && @@ -10661,6 +10965,34 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, // capture. } +/// \brief Capture the given variable in the captured region. +static ExprResult captureInCapturedRegion(Sema &S, CapturedRegionScopeInfo *RSI, + VarDecl *Var, QualType FieldType, + QualType DeclRefType, + SourceLocation Loc, + bool RefersToEnclosingLocal) { + // The current implemention assumes that all variables are captured + // by references. Since there is no capture by copy, no expression evaluation + // will be needed. + // + RecordDecl *RD = RSI->TheRecordDecl; + + FieldDecl *Field + = FieldDecl::Create(S.Context, RD, Loc, Loc, 0, FieldType, + S.Context.getTrivialTypeSourceInfo(FieldType, Loc), + 0, false, ICIS_NoInit); + Field->setImplicit(true); + Field->setAccess(AS_private); + RD->addDecl(Field); + + Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal, + DeclRefType, VK_LValue, Loc); + Var->setReferenced(true); + Var->setUsed(true); + + return Ref; +} + /// \brief Capture the given variable in the given lambda expression. static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, VarDecl *Var, QualType FieldType, @@ -10690,7 +11022,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, // Introduce a new evaluation context for the initialization, so // that temporaries introduced as part of the capture are retained // to be re-"exported" from the lambda expression itself. - S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); + EnterExpressionEvaluationContext scope(S, Sema::PotentiallyEvaluated); // C++ [expr.prim.labda]p12: // An entity captured by a lambda-expression is odr-used (3.2) in @@ -10722,7 +11054,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, = VarDecl::Create(S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType, S.Context.getTrivialTypeSourceInfo(SizeType, Loc), - SC_None, SC_None); + SC_None); IndexVariables.push_back(IterationVar); LSI->ArrayIndexVars.push_back(IterationVar); @@ -10741,7 +11073,6 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, if (Subscript.isInvalid()) { S.CleanupVarDeclMarking(); S.DiscardCleanupsInEvaluationContext(); - S.PopExpressionEvaluationContext(); return ExprError(); } @@ -10763,9 +11094,9 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc); - InitializationSequence Init(S, Entities.back(), InitKind, &Ref, 1); + InitializationSequence Init(S, Entities.back(), InitKind, Ref); ExprResult Result(true); - if (!Init.Diagnose(S, Entities.back(), InitKind, &Ref, 1)) + if (!Init.Diagnose(S, Entities.back(), InitKind, Ref)) Result = Init.Perform(S, Entities.back(), InitKind, Ref); // If this initialization requires any cleanups (e.g., due to a @@ -10777,7 +11108,6 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, // Exit the expression evaluation context used for the capture. S.CleanupVarDeclMarking(); S.DiscardCleanupsInEvaluationContext(); - S.PopExpressionEvaluationContext(); return Result; } @@ -10803,10 +11133,10 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit = (Kind != TryCapture_Implicit); unsigned FunctionScopesIndex = FunctionScopes.size() - 1; do { - // Only block literals and lambda expressions can capture; other - // scopes don't work. + // Only block literals, captured statements, and lambda expressions can + // capture; other scopes don't work. DeclContext *ParentDC; - if (isa<BlockDecl>(DC)) + if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC)) ParentDC = DC->getParent(); else if (isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call && @@ -10840,7 +11170,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, } bool IsBlock = isa<BlockScopeInfo>(CSI); - bool IsLambda = !IsBlock; + bool IsLambda = isa<LambdaScopeInfo>(CSI); // Lambdas are not allowed to capture unnamed variables // (e.g. anonymous unions). @@ -10964,6 +11294,10 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, if (isa<ParmVarDecl>(Var)) FinalizeVarWithDestructor(Var, Record); + // Enter a new evaluation context to insulate the copy + // full-expression. + EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated); + // According to the blocks spec, the capture of a variable from // the stack requires a const copy constructor. This is not true // of the copy/move done to move a __block variable to the heap. @@ -10996,8 +11330,31 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, SourceLocation(), CaptureType, CopyExpr); Nested = true; continue; - } - + } + + if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) { + // By default, capture variables by reference. + bool ByRef = true; + // Using an LValue reference type is consistent with Lambdas (see below). + CaptureType = Context.getLValueReferenceType(DeclRefType); + + Expr *CopyExpr = 0; + if (BuildAndDiagnose) { + ExprResult Result = captureInCapturedRegion(*this, RSI, Var, + CaptureType, DeclRefType, + Loc, Nested); + if (!Result.isInvalid()) + CopyExpr = Result.take(); + } + + // Actually capture the variable. + if (BuildAndDiagnose) + CSI->addCapture(Var, /*isBlock*/false, ByRef, Nested, Loc, + SourceLocation(), CaptureType, CopyExpr); + Nested = true; + continue; + } + LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI); // Determine whether we are capturing by reference or by value. @@ -11446,6 +11803,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD) { switch (ExprEvalContexts.back().Context) { case Unevaluated: + case UnevaluatedAbstract: // The argument will never be evaluated, so don't complain. break; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 09f04b7c43..27032a9111 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -38,6 +38,43 @@ using namespace clang; using namespace sema; +/// \brief Handle the result of the special case name lookup for inheriting +/// constructor declarations. 'NS::X::X' and 'NS::X<...>::X' are treated as +/// constructor names in member using declarations, even if 'X' is not the +/// name of the corresponding type. +ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, + SourceLocation NameLoc, + IdentifierInfo &Name) { + NestedNameSpecifier *NNS = SS.getScopeRep(); + + // Convert the nested-name-specifier into a type. + QualType Type; + switch (NNS->getKind()) { + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + Type = QualType(NNS->getAsType(), 0); + break; + + case NestedNameSpecifier::Identifier: + // Strip off the last layer of the nested-name-specifier and build a + // typename type for it. + assert(NNS->getAsIdentifier() == &Name && "not a constructor name"); + Type = Context.getDependentNameType(ETK_None, NNS->getPrefix(), + NNS->getAsIdentifier()); + break; + + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + llvm_unreachable("Nested name specifier is not a type for inheriting ctor"); + } + + // This reference to the type is located entirely at the location of the + // final identifier in the qualified-id. + return CreateParsedType(Type, + Context.getTrivialTypeSourceInfo(Type, NameLoc)); +} + ParsedType Sema::getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, @@ -264,8 +301,16 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, } else if (ObjectTypePtr) Diag(NameLoc, diag::err_ident_in_dtor_not_a_type) << &II; - else - Diag(NameLoc, diag::err_destructor_class_name); + else { + SemaDiagnosticBuilder DtorDiag = Diag(NameLoc, + diag::err_destructor_class_name); + if (S) { + const DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()); + if (const CXXRecordDecl *Class = dyn_cast_or_null<CXXRecordDecl>(Ctx)) + DtorDiag << FixItHint::CreateReplacement(SourceRange(NameLoc), + Class->getNameAsString()); + } + } return ParsedType(); } @@ -639,7 +684,8 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, MarkFunctionReferenced(E->getExprLoc(), Destructor); CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_exception) << Ty); - DiagnoseUseOfDecl(Destructor, E->getExprLoc()); + if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) + return ExprError(); return Owned(E); } @@ -683,9 +729,21 @@ Sema::CXXThisScopeRAII::~CXXThisScopeRAII() { } } +static Expr *captureThis(ASTContext &Context, RecordDecl *RD, + QualType ThisTy, SourceLocation Loc) { + FieldDecl *Field + = FieldDecl::Create(Context, RD, Loc, Loc, 0, ThisTy, + Context.getTrivialTypeSourceInfo(ThisTy, Loc), + 0, false, ICIS_NoInit); + Field->setImplicit(true); + Field->setAccess(AS_private); + RD->addDecl(Field); + return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/true); +} + void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { // We don't need to capture this in an unevaluated context. - if (ExprEvalContexts.back().Context == Unevaluated && !Explicit) + if (isUnevaluatedContext() && !Explicit) return; // Otherwise, check that we can capture 'this'. @@ -701,6 +759,7 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block || + CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_CapturedRegion || Explicit) { // This closure can capture 'this'; continue looking upwards. NumClosures++; @@ -722,18 +781,13 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]); Expr *ThisExpr = 0; QualType ThisTy = getCurrentThisType(); - if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) { + if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) // For lambda expressions, build a field and an initializing expression. - CXXRecordDecl *Lambda = LSI->Lambda; - FieldDecl *Field - = FieldDecl::Create(Context, Lambda, Loc, Loc, 0, ThisTy, - Context.getTrivialTypeSourceInfo(ThisTy, Loc), - 0, false, ICIS_NoInit); - Field->setImplicit(true); - Field->setAccess(AS_private); - Lambda->addDecl(Field); - ThisExpr = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/true); - } + ThisExpr = captureThis(Context, LSI->Lambda, ThisTy, Loc); + else if (CapturedRegionScopeInfo *RSI + = dyn_cast<CapturedRegionScopeInfo>(FunctionScopes[idx])) + ThisExpr = captureThis(Context, RSI->TheRecordDecl, ThisTy, Loc); + bool isNested = NumClosures > 1; CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr); } @@ -786,23 +840,20 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, ExprResult Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, SourceLocation LParenLoc, - MultiExprArg exprs, + MultiExprArg Exprs, SourceLocation RParenLoc) { QualType Ty = TInfo->getType(); SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); - if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(exprs)) { + if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) { return Owned(CXXUnresolvedConstructExpr::Create(Context, TInfo, LParenLoc, - exprs, + Exprs, RParenLoc)); } - unsigned NumExprs = exprs.size(); - Expr **Exprs = exprs.data(); - bool ListInitialization = LParenLoc.isInvalid(); - assert((!ListInitialization || (NumExprs == 1 && isa<InitListExpr>(Exprs[0]))) + assert((!ListInitialization || (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) && "List initialization must have initializer list as expression."); SourceRange FullRange = SourceRange(TyBeginLoc, ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc); @@ -811,7 +862,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, // If the expression list is a single expression, the type conversion // expression is equivalent (in definedness, and if defined in meaning) to the // corresponding cast expression. - if (NumExprs == 1 && !ListInitialization) { + if (Exprs.size() == 1 && !ListInitialization) { Expr *Arg = Exprs[0]; return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc); } @@ -834,15 +885,13 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, return ExprError(); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); - InitializationKind Kind - = NumExprs ? ListInitialization - ? InitializationKind::CreateDirectList(TyBeginLoc) - : InitializationKind::CreateDirect(TyBeginLoc, - LParenLoc, RParenLoc) - : InitializationKind::CreateValue(TyBeginLoc, - LParenLoc, RParenLoc); - InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, exprs); + InitializationKind Kind = + Exprs.size() ? ListInitialization + ? InitializationKind::CreateDirectList(TyBeginLoc) + : InitializationKind::CreateDirect(TyBeginLoc, LParenLoc, RParenLoc) + : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc); + InitializationSequence InitSeq(*this, Entity, Kind, Exprs); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs); if (!Result.isInvalid() && ListInitialization && isa<InitListExpr>(Result.get())) { @@ -938,7 +987,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, Expr *Initializer) { - bool TypeContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType(); Expr *ArraySize = 0; // If the specified type is an array, unwrap it and save the expression. @@ -1065,9 +1114,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, HaveCompleteInit = true; // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. - AutoType *AT = 0; - if (TypeMayContainAuto && - (AT = AllocType->getContainedAutoType()) && !AT->isDeduced()) { + if (TypeMayContainAuto && AllocType->isUndeducedType()) { if (initStyle == CXXNewExpr::NoInit || NumInits == 0) return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) << AllocType << TypeRange); @@ -1082,16 +1129,14 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, << AllocType << TypeRange); } Expr *Deduce = Inits[0]; - TypeSourceInfo *DeducedType = 0; + QualType DeducedType; if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) << AllocType << Deduce->getType() << TypeRange << Deduce->getSourceRange()); - if (!DeducedType) + if (DeducedType.isNull()) return ExprError(); - - AllocTypeInfo = DeducedType; - AllocType = AllocTypeInfo->getType(); + AllocType = DeducedType; } // Per C++0x [expr.new]p5, the type being constructed may be a @@ -1125,6 +1170,11 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, QualType ResultType = Context.getPointerType(AllocType); + if (ArraySize && ArraySize->getType()->isNonOverloadPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(ArraySize); + if (result.isInvalid()) return ExprError(); + ArraySize = result.take(); + } // C++98 5.3.4p6: "The expression in a direct-new-declarator shall have // integral or enumeration type with a non-negative value." // C++11 [expr.new]p6: The expression [...] shall be of integral or unscoped @@ -1360,7 +1410,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, InitType); - InitializationSequence InitSeq(*this, Entity, Kind, Inits, NumInits); + InitializationSequence InitSeq(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); if (FullInit.isInvalid()) @@ -1377,11 +1427,13 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // Mark the new and delete operators as referenced. if (OperatorNew) { - DiagnoseUseOfDecl(OperatorNew, StartLoc); + if (DiagnoseUseOfDecl(OperatorNew, StartLoc)) + return ExprError(); MarkFunctionReferenced(StartLoc, OperatorNew); } if (OperatorDelete) { - DiagnoseUseOfDecl(OperatorDelete, StartLoc); + if (DiagnoseUseOfDecl(OperatorDelete, StartLoc)) + return ExprError(); MarkFunctionReferenced(StartLoc, OperatorDelete); } @@ -1397,7 +1449,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, CheckDestructorAccess(StartLoc, dtor, PDiag(diag::err_access_dtor) << BaseAllocType); - DiagnoseUseOfDecl(dtor, StartLoc); + if (DiagnoseUseOfDecl(dtor, StartLoc)) + return ExprError(); } } } @@ -1901,8 +1954,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), SourceLocation(), Name, - FnType, /*TInfo=*/0, SC_None, - SC_None, false, true); + FnType, /*TInfo=*/0, SC_None, false, true); Alloc->setImplicit(); if (AddMallocAttr) @@ -1911,7 +1963,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), SourceLocation(), 0, Argument, /*TInfo=*/0, - SC_None, SC_None, 0); + SC_None, 0); Alloc->setParams(Param); // FIXME: Also add this declaration to the IdentifierResolver, but @@ -2156,7 +2208,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { MarkFunctionReferenced(StartLoc, const_cast<CXXDestructorDecl*>(Dtor)); - DiagnoseUseOfDecl(Dtor, StartLoc); + if (DiagnoseUseOfDecl(Dtor, StartLoc)) + return ExprError(); } // C++ [expr.delete]p3: @@ -2222,6 +2275,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, bool ConvertToBoolean) { + if (ConditionVar->isInvalidDecl()) + return ExprError(); + QualType T = ConditionVar->getType(); // C++ [stmt.select]p2: @@ -2930,10 +2986,13 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, // type due to the overarching C++0x type predicates being implemented // requiring the complete type. case UTT_HasNothrowAssign: + case UTT_HasNothrowMoveAssign: case UTT_HasNothrowConstructor: case UTT_HasNothrowCopy: case UTT_HasTrivialAssign: + case UTT_HasTrivialMoveAssign: case UTT_HasTrivialDefaultConstructor: + case UTT_HasTrivialMoveConstructor: case UTT_HasTrivialCopy: case UTT_HasTrivialDestructor: case UTT_HasVirtualDestructor: @@ -2952,6 +3011,42 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, llvm_unreachable("Type trait not handled by switch"); } +static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, + Sema &Self, SourceLocation KeyLoc, ASTContext &C, + bool (CXXRecordDecl::*HasTrivial)() const, + bool (CXXRecordDecl::*HasNonTrivial)() const, + bool (CXXMethodDecl::*IsDesiredOp)() const) +{ + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)()) + return true; + + DeclarationName Name = C.DeclarationNames.getCXXOperatorName(Op); + DeclarationNameInfo NameInfo(Name, KeyLoc); + LookupResult Res(Self, NameInfo, Sema::LookupOrdinaryName); + if (Self.LookupQualifiedName(Res, RD)) { + bool FoundOperator = false; + Res.suppressDiagnostics(); + for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end(); + Op != OpEnd; ++Op) { + if (isa<FunctionTemplateDecl>(*Op)) + continue; + + CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op); + if((Operator->*IsDesiredOp)()) { + FoundOperator = true; + const FunctionProtoType *CPT = + Operator->getType()->getAs<FunctionProtoType>(); + CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); + if (!CPT || !CPT->isNothrow(Self.Context)) + return false; + } + } + return FoundOperator; + } + return false; +} + static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, SourceLocation KeyLoc, QualType T) { assert(!T->isDependentType() && "Cannot evaluate traits of dependent type"); @@ -3036,7 +3131,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, case UTT_IsPOD: return T.isPODType(Self.Context); case UTT_IsLiteral: - return T->isLiteralType(); + return T->isLiteralType(Self.Context); case UTT_IsEmpty: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isEmpty(); @@ -3088,6 +3183,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return RD->hasTrivialDefaultConstructor() && !RD->hasNonTrivialDefaultConstructor(); return false; + case UTT_HasTrivialMoveConstructor: + // This trait is implemented by MSVC 2012 and needed to parse the + // standard library headers. Specifically this is used as the logic + // behind std::is_trivially_move_constructible (20.9.4.3). + if (T.isPODType(Self.Context)) + return true; + if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) + return RD->hasTrivialMoveConstructor() && !RD->hasNonTrivialMoveConstructor(); + return false; case UTT_HasTrivialCopy: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __is_pod (type) is true or type is a reference type then @@ -3100,6 +3204,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return RD->hasTrivialCopyConstructor() && !RD->hasNonTrivialCopyConstructor(); return false; + case UTT_HasTrivialMoveAssign: + // This trait is implemented by MSVC 2012 and needed to parse the + // standard library headers. Specifically it is used as the logic + // behind std::is_trivially_move_assignable (20.9.4.3) + if (T.isPODType(Self.Context)) + return true; + if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) + return RD->hasTrivialMoveAssignment() && !RD->hasNonTrivialMoveAssignment(); + return false; case UTT_HasTrivialAssign: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If type is const qualified or is a reference type then the @@ -3153,38 +3266,26 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, if (T->isReferenceType()) return false; if (T.isPODType(Self.Context) || T->isObjCLifetimeType()) - return true; - if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) { - if (RD->hasTrivialCopyAssignment() && !RD->hasNonTrivialCopyAssignment()) - return true; + return true; - bool FoundAssign = false; - DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal); - LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc), - Sema::LookupOrdinaryName); - if (Self.LookupQualifiedName(Res, RD)) { - Res.suppressDiagnostics(); - for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end(); - Op != OpEnd; ++Op) { - if (isa<FunctionTemplateDecl>(*Op)) - continue; - - CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op); - if (Operator->isCopyAssignmentOperator()) { - FoundAssign = true; - const FunctionProtoType *CPT - = Operator->getType()->getAs<FunctionProtoType>(); - CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); - if (!CPT) - return false; - if (!CPT->isNothrow(Self.Context)) - return false; - } - } - } - - return FoundAssign; - } + if (const RecordType *RT = T->getAs<RecordType>()) + return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C, + &CXXRecordDecl::hasTrivialCopyAssignment, + &CXXRecordDecl::hasNonTrivialCopyAssignment, + &CXXMethodDecl::isCopyAssignmentOperator); + return false; + case UTT_HasNothrowMoveAssign: + // This trait is implemented by MSVC 2012 and needed to parse the + // standard library headers. Specifically this is used as the logic + // behind std::is_nothrow_move_assignable (20.9.4.3). + if (T.isPODType(Self.Context)) + return true; + + if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) + return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C, + &CXXRecordDecl::hasTrivialMoveAssignment, + &CXXRecordDecl::hasNonTrivialMoveAssignment, + &CXXMethodDecl::isMoveAssignmentOperator); return false; case UTT_HasNothrowCopy: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: @@ -3397,8 +3498,7 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, InitializedEntity To(InitializedEntity::InitializeTemporary(Args[0])); InitializationKind InitKind(InitializationKind::CreateDirect(KWLoc, KWLoc, RParenLoc)); - InitializationSequence Init(S, To, InitKind, - ArgExprs.begin(), ArgExprs.size()); + InitializationSequence Init(S, To, InitKind, ArgExprs); if (Init.Failed()) return false; @@ -3556,7 +3656,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); - InitializationSequence Init(Self, To, Kind, &FromPtr, 1); + InitializationSequence Init(Self, To, Kind, FromPtr); if (Init.Failed()) return false; @@ -3956,7 +4056,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, QualType T = Self.Context.getLValueReferenceType(ToType); InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); - InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); + InitializationSequence InitSeq(Self, Entity, Kind, From); if (InitSeq.isDirectReferenceBinding()) { ToType = T; HaveConversion = true; @@ -3964,7 +4064,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, } if (InitSeq.isAmbiguous()) - return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); + return InitSeq.Diagnose(Self, Entity, Kind, From); } // -- If E2 is an rvalue, or if the conversion above cannot be done: @@ -3984,14 +4084,14 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, if (FRec == TRec || FDerivedFromT) { if (TTy.isAtLeastAsQualifiedAs(FTy)) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); - InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); + InitializationSequence InitSeq(Self, Entity, Kind, From); if (InitSeq) { HaveConversion = true; return false; } if (InitSeq.isAmbiguous()) - return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); + return InitSeq.Diagnose(Self, Entity, Kind, From); } } @@ -4009,11 +4109,11 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, TTy = TTy.getUnqualifiedType(); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); - InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); + InitializationSequence InitSeq(Self, Entity, Kind, From); HaveConversion = !InitSeq.Failed(); ToType = TTy; if (InitSeq.isAmbiguous()) - return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); + return InitSeq.Diagnose(Self, Entity, Kind, From); return false; } @@ -4027,7 +4127,7 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS SourceLocation QuestionLoc) { Expr *Args[2] = { LHS.get(), RHS.get() }; OverloadCandidateSet CandidateSet(QuestionLoc); - Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args, 2, + Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args, CandidateSet); OverloadCandidateSet::iterator Best; @@ -4086,7 +4186,7 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) { InitializationKind Kind = InitializationKind::CreateCopy(E.get()->getLocStart(), SourceLocation()); Expr *Arg = E.take(); - InitializationSequence InitSeq(Self, Entity, Kind, &Arg, 1); + InitializationSequence InitSeq(Self, Entity, Kind, Arg); ExprResult Result = InitSeq.Perform(Self, Entity, Kind, Arg); if (Result.isInvalid()) return true; @@ -4535,8 +4635,8 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, = InitializedEntity::InitializeTemporary(Composite1); InitializationKind Kind = InitializationKind::CreateCopy(Loc, SourceLocation()); - InitializationSequence E1ToC1(*this, Entity1, Kind, &E1, 1); - InitializationSequence E2ToC1(*this, Entity1, Kind, &E2, 1); + InitializationSequence E1ToC1(*this, Entity1, Kind, E1); + InitializationSequence E2ToC1(*this, Entity1, Kind, E2); if (E1ToC1 && E2ToC1) { // Conversion to Composite1 is viable. @@ -4545,8 +4645,8 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // Composite2 is also viable. InitializedEntity Entity2 = InitializedEntity::InitializeTemporary(Composite2); - InitializationSequence E1ToC2(*this, Entity2, Kind, &E1, 1); - InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1); + InitializationSequence E1ToC2(*this, Entity2, Kind, E1); + InitializationSequence E2ToC2(*this, Entity2, Kind, E2); if (E1ToC2 && E2ToC2) { // Both Composite1 and Composite2 are viable and are different; // this is an ambiguity. @@ -4574,8 +4674,8 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // Check whether Composite2 is viable. InitializedEntity Entity2 = InitializedEntity::InitializeTemporary(Composite2); - InitializationSequence E1ToC2(*this, Entity2, Kind, &E1, 1); - InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1); + InitializationSequence E1ToC2(*this, Entity2, Kind, E1); + InitializationSequence E2ToC2(*this, Entity2, Kind, E2); if (!E1ToC2 || !E2ToC2) return QualType(); @@ -4724,7 +4824,8 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_temp) << E->getType()); - DiagnoseUseOfDecl(Destructor, E->getExprLoc()); + if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) + return ExprError(); // If destructor is trivial, we can avoid the extra copy. if (Destructor->isTrivial()) @@ -4879,7 +4980,8 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) { CheckDestructorAccess(Bind->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_temp) << Bind->getType()); - DiagnoseUseOfDecl(Destructor, Bind->getExprLoc()); + if (DiagnoseUseOfDecl(Destructor, Bind->getExprLoc())) + return ExprError(); // We need a cleanup, but we don't need to remember the temporary. ExprNeedsCleanups = true; @@ -4997,7 +5099,7 @@ ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, return ActOnCallExpr(/*Scope*/ 0, MemExpr, /*LPLoc*/ ExpectedLParenLoc, - MultiExprArg(), + None, /*RPLoc*/ ExpectedLParenLoc); } @@ -5345,7 +5447,7 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, ResultType = ResultType.getNonLValueExprType(Context); CXXMemberCallExpr *CE = - new (Context) CXXMemberCallExpr(Context, ME, MultiExprArg(), ResultType, VK, + new (Context) CXXMemberCallExpr(Context, ME, None, ResultType, VK, Exp.get()->getLocEnd()); return CE; } diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index 7b016c6574..545ac2746d 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -60,6 +60,9 @@ enum IMAKind { /// The reference may be to an unresolved using declaration. IMA_Unresolved, + /// The reference is a contextually-permitted abstract member reference. + IMA_Abstract, + /// The reference may be to an unresolved using declaration and the /// context is not an instance method. IMA_Unresolved_StaticContext, @@ -105,7 +108,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, NamedDecl *D = *I; if (D->isCXXInstanceMember()) { - if (dyn_cast<FieldDecl>(D) || dyn_cast<IndirectFieldDecl>(D)) + if (dyn_cast<FieldDecl>(D) || dyn_cast<MSPropertyDecl>(D) + || dyn_cast<IndirectFieldDecl>(D)) isField = true; CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext()); @@ -119,19 +123,32 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, // member reference. if (Classes.empty()) return IMA_Static; - - bool IsCXX11UnevaluatedField = false; - if (SemaRef.getLangOpts().CPlusPlus11 && isField) { - // C++11 [expr.prim.general]p12: - // An id-expression that denotes a non-static data member or non-static - // member function of a class can only be used: - // (...) - // - if that id-expression denotes a non-static data member and it - // appears in an unevaluated operand. - const Sema::ExpressionEvaluationContextRecord& record - = SemaRef.ExprEvalContexts.back(); - if (record.Context == Sema::Unevaluated) - IsCXX11UnevaluatedField = true; + + // C++11 [expr.prim.general]p12: + // An id-expression that denotes a non-static data member or non-static + // member function of a class can only be used: + // (...) + // - if that id-expression denotes a non-static data member and it + // appears in an unevaluated operand. + // + // This rule is specific to C++11. However, we also permit this form + // in unevaluated inline assembly operands, like the operand to a SIZE. + IMAKind AbstractInstanceResult = IMA_Static; // happens to be 'false' + assert(!AbstractInstanceResult); + switch (SemaRef.ExprEvalContexts.back().Context) { + case Sema::Unevaluated: + if (isField && SemaRef.getLangOpts().CPlusPlus11) + AbstractInstanceResult = IMA_Field_Uneval_Context; + break; + + case Sema::UnevaluatedAbstract: + AbstractInstanceResult = IMA_Abstract; + break; + + case Sema::ConstantEvaluated: + case Sema::PotentiallyEvaluated: + case Sema::PotentiallyEvaluatedIfUsed: + break; } // If the current context is not an instance method, it can't be @@ -140,8 +157,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, if (hasNonInstance) return IMA_Mixed_StaticContext; - return IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context - : IMA_Error_StaticContext; + return AbstractInstanceResult ? AbstractInstanceResult + : IMA_Error_StaticContext; } CXXRecordDecl *contextClass; @@ -171,8 +188,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, // which case it's an error if any of those members are selected). if (isProvablyNotDerivedFrom(SemaRef, contextClass, Classes)) return hasNonInstance ? IMA_Mixed_Unrelated : - IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context : - IMA_Error_Unrelated; + AbstractInstanceResult ? AbstractInstanceResult : + IMA_Error_Unrelated; return (hasNonInstance ? IMA_Mixed : IMA_Instance); } @@ -232,6 +249,7 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, << R.getLookupNameInfo().getName(); // Fall through. case IMA_Static: + case IMA_Abstract: case IMA_Mixed_StaticContext: case IMA_Unresolved_StaticContext: if (TemplateArgs || TemplateKWLoc.isValid()) @@ -778,6 +796,19 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, return Owned(result); } +static ExprResult +BuildMSPropertyRefExpr(Sema &S, Expr *BaseExpr, bool IsArrow, + const CXXScopeSpec &SS, + MSPropertyDecl *PD, + const DeclarationNameInfo &NameInfo) { + // Property names are always simple identifiers and therefore never + // require any interesting additional storage. + return new (S.Context) MSPropertyRefExpr(BaseExpr, PD, IsArrow, + S.Context.PseudoObjectTy, VK_LValue, + SS.getWithLocInContext(S.Context), + NameInfo.getLoc()); +} + /// \brief Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr(Sema &SemaRef, ASTContext &C, Expr *Base, bool isArrow, @@ -935,6 +966,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, SS, FD, FoundDecl, MemberNameInfo); + if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl)) + return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD, + MemberNameInfo); + if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl)) // We may have found a field within an anonymous union or struct // (C++ [class.union]). @@ -1130,30 +1165,15 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // There's an implicit 'isa' ivar on all objects. // But we only actually find it this way on objects of type 'id', // apparently. - if (OTy->isObjCId() && Member->isStr("isa")) { - Diag(MemberLoc, diag::warn_objc_isa_use); + if (OTy->isObjCId() && Member->isStr("isa")) return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc, + OpLoc, Context.getObjCClassType())); - } - if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, ObjCImpDecl, HasTemplateArgs); goto fail; } - else if (Member && Member->isStr("isa")) { - // If an ivar is (1) the first ivar in a root class and (2) named `isa`, - // then issue the same deprecated warning that id->isa gets. - ObjCInterfaceDecl *ClassDeclared = 0; - if (ObjCIvarDecl *IV = - IDecl->lookupInstanceVariable(Member, ClassDeclared)) { - if (!ClassDeclared->getSuperClass() - && (*ClassDeclared->ivar_begin()) == IV) { - Diag(MemberLoc, diag::warn_objc_isa_use); - Diag(IV->getLocation(), diag::note_ivar_decl); - } - } - } if (RequireCompleteType(OpLoc, BaseType, diag::err_typecheck_incomplete_tag, BaseExpr.get())) @@ -1267,7 +1287,7 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, } ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(), - MemberLoc, + MemberLoc, OpLoc, BaseExpr.take(), IsArrow); diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index b0d5453808..cf77896cb8 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -238,8 +238,8 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, SourceLocation(), SourceLocation(), &CX.Idents.get("value"), NumberType, /*TInfo=*/0, SC_None, - SC_None, 0); - Method->setMethodParams(S.Context, value, ArrayRef<SourceLocation>()); + 0); + Method->setMethodParams(S.Context, value, None); } if (!validateBoxingMethod(S, Loc, S.NSNumberDecl, Sel, Method)) @@ -343,7 +343,7 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element, InitializationKind Kind = InitializationKind::CreateCopy(Element->getLocStart(), SourceLocation()); - InitializationSequence Seq(S, Entity, Kind, &Element, 1); + InitializationSequence Seq(S, Entity, Kind, Element); if (!Seq.Failed()) return Seq.Perform(S, Entity, Kind, Element); } @@ -489,8 +489,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { &Context.Idents.get("value"), Context.getPointerType(ConstCharType), /*TInfo=*/0, - SC_None, SC_None, 0); - M->setMethodParams(Context, value, ArrayRef<SourceLocation>()); + SC_None, 0); + M->setMethodParams(Context, value, None); BoxingMethod = M; } @@ -656,18 +656,16 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { SourceLocation(), &Context.Idents.get("objects"), Context.getPointerType(IdT), - /*TInfo=*/0, SC_None, SC_None, - 0); + /*TInfo=*/0, SC_None, 0); Params.push_back(objects); ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method, SourceLocation(), SourceLocation(), &Context.Idents.get("cnt"), Context.UnsignedLongTy, - /*TInfo=*/0, SC_None, SC_None, - 0); + /*TInfo=*/0, SC_None, 0); Params.push_back(cnt); - Method->setMethodParams(Context, Params, ArrayRef<SourceLocation>()); + Method->setMethodParams(Context, Params, None); } if (!validateBoxingMethod(*this, SR.getBegin(), NSArrayDecl, Sel, Method)) @@ -774,26 +772,23 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, SourceLocation(), &Context.Idents.get("objects"), Context.getPointerType(IdT), - /*TInfo=*/0, SC_None, SC_None, - 0); + /*TInfo=*/0, SC_None, 0); Params.push_back(objects); ParmVarDecl *keys = ParmVarDecl::Create(Context, Method, SourceLocation(), SourceLocation(), &Context.Idents.get("keys"), Context.getPointerType(IdT), - /*TInfo=*/0, SC_None, SC_None, - 0); + /*TInfo=*/0, SC_None, 0); Params.push_back(keys); ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method, SourceLocation(), SourceLocation(), &Context.Idents.get("cnt"), Context.UnsignedLongTy, - /*TInfo=*/0, SC_None, SC_None, - 0); + /*TInfo=*/0, SC_None, 0); Params.push_back(cnt); - Method->setMethodParams(Context, Params, ArrayRef<SourceLocation>()); + Method->setMethodParams(Context, Params, None); } if (!validateBoxingMethod(*this, SR.getBegin(), NSDictionaryDecl, Sel, @@ -1094,6 +1089,73 @@ QualType Sema::getMessageSendResultType(QualType ReceiverType, return ReceiverType; } +/// Look for an ObjC method whose result type exactly matches the given type. +static const ObjCMethodDecl * +findExplicitInstancetypeDeclarer(const ObjCMethodDecl *MD, + QualType instancetype) { + if (MD->getResultType() == instancetype) return MD; + + // For these purposes, a method in an @implementation overrides a + // declaration in the @interface. + if (const ObjCImplDecl *impl = + dyn_cast<ObjCImplDecl>(MD->getDeclContext())) { + const ObjCContainerDecl *iface; + if (const ObjCCategoryImplDecl *catImpl = + dyn_cast<ObjCCategoryImplDecl>(impl)) { + iface = catImpl->getCategoryDecl(); + } else { + iface = impl->getClassInterface(); + } + + const ObjCMethodDecl *ifaceMD = + iface->getMethod(MD->getSelector(), MD->isInstanceMethod()); + if (ifaceMD) return findExplicitInstancetypeDeclarer(ifaceMD, instancetype); + } + + SmallVector<const ObjCMethodDecl *, 4> overrides; + MD->getOverriddenMethods(overrides); + for (unsigned i = 0, e = overrides.size(); i != e; ++i) { + if (const ObjCMethodDecl *result = + findExplicitInstancetypeDeclarer(overrides[i], instancetype)) + return result; + } + + return 0; +} + +void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) { + // Only complain if we're in an ObjC method and the required return + // type doesn't match the method's declared return type. + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurContext); + if (!MD || !MD->hasRelatedResultType() || + Context.hasSameUnqualifiedType(destType, MD->getResultType())) + return; + + // Look for a method overridden by this method which explicitly uses + // 'instancetype'. + if (const ObjCMethodDecl *overridden = + findExplicitInstancetypeDeclarer(MD, Context.getObjCInstanceType())) { + SourceLocation loc; + SourceRange range; + if (TypeSourceInfo *TSI = overridden->getResultTypeSourceInfo()) { + range = TSI->getTypeLoc().getSourceRange(); + loc = range.getBegin(); + } + if (loc.isInvalid()) + loc = overridden->getLocation(); + Diag(loc, diag::note_related_result_type_explicit) + << /*current method*/ 1 << range; + return; + } + + // Otherwise, if we have an interesting method family, note that. + // This should always trigger if the above didn't. + if (ObjCMethodFamily family = MD->getMethodFamily()) + Diag(MD->getLocation(), diag::note_related_result_type_family) + << /*current method*/ 1 + << family; +} + void Sema::EmitRelatedResultTypeNote(const Expr *E) { E = E->IgnoreParenImpCasts(); const ObjCMessageExpr *MsgSend = dyn_cast<ObjCMessageExpr>(E); @@ -1129,6 +1191,12 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, SourceLocation rbrac, QualType &ReturnType, ExprValueKind &VK) { + SourceLocation SelLoc; + if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) + SelLoc = SelectorLocs.front(); + else + SelLoc = lbrac; + if (!Method) { // Apply default argument promotion as for (C99 6.5.2.2p6). for (unsigned i = 0; i != NumArgs; i++) { @@ -1138,7 +1206,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, ExprResult result; if (getLangOpts().DebuggerSupport) { QualType paramTy; // ignored - result = checkUnknownAnyArg(lbrac, Args[i], paramTy); + result = checkUnknownAnyArg(SelLoc, Args[i], paramTy); } else { result = DefaultArgumentPromotion(Args[i]); } @@ -1154,7 +1222,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, DiagID = isClassMessage ? diag::warn_class_method_not_found : diag::warn_inst_method_not_found; if (!getLangOpts().DebuggerSupport) - Diag(lbrac, DiagID) + Diag(SelLoc, DiagID) << Sel << isClassMessage << SourceRange(SelectorLocs.front(), SelectorLocs.back()); @@ -1180,7 +1248,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, NumNamedArgs = Method->param_size(); // FIXME. This need be cleaned up. if (NumArgs < NumNamedArgs) { - Diag(lbrac, diag::err_typecheck_call_too_few_args) + Diag(SelLoc, diag::err_typecheck_call_too_few_args) << 2 << NumNamedArgs << NumArgs; return false; } @@ -1206,7 +1274,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, // from the argument. if (param->getType() == Context.UnknownAnyTy) { QualType paramType; - ExprResult argE = checkUnknownAnyArg(lbrac, argExpr, paramType); + ExprResult argE = checkUnknownAnyArg(SelLoc, argExpr, paramType); if (argE.isInvalid()) { IsError = true; } else { @@ -1225,7 +1293,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, param); - ExprResult ArgE = PerformCopyInitialization(Entity, lbrac, Owned(argExpr)); + ExprResult ArgE = PerformCopyInitialization(Entity, SelLoc, Owned(argExpr)); if (ArgE.isInvalid()) IsError = true; else @@ -1255,10 +1323,11 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, } } - DiagnoseSentinelCalls(Method, lbrac, Args, NumArgs); + DiagnoseSentinelCalls(Method, SelLoc, Args, NumArgs); // Do additional checkings on method. - IsError |= CheckObjCMethodCall(Method, lbrac, Args, NumArgs); + IsError |= CheckObjCMethodCall(Method, SelLoc, + llvm::makeArrayRef<const Expr *>(Args, NumArgs)); return IsError; } @@ -1266,7 +1335,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, bool Sema::isSelfExpr(Expr *receiver) { // 'self' is objc 'self' in an objc method only. ObjCMethodDecl *method = - dyn_cast<ObjCMethodDecl>(CurContext->getNonClosureAncestor()); + dyn_cast_or_null<ObjCMethodDecl>(CurContext->getNonClosureAncestor()); if (!method) return false; receiver = receiver->IgnoreParenLValueCasts(); @@ -1724,9 +1793,11 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, QualType T; if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) T = Context.getObjCInterfaceType(Class); - else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND)) + else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND)) { T = Context.getTypeDeclType(Type); - else + DiagnoseUseOfDecl(Type, NameLoc); + } + else return ObjCInstanceMessage; // We have a class message, and T is the type we're @@ -1929,7 +2000,12 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, << FixItHint::CreateInsertion(Loc, "["); LBracLoc = Loc; } - + SourceLocation SelLoc; + if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) + SelLoc = SelectorLocs.front(); + else + SelLoc = Loc; + if (ReceiverType->isDependentType()) { // If the receiver type is dependent, we can't type-check anything // at this point. Build a dependent expression. @@ -1954,7 +2030,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, assert(Class && "We don't know which class we're messaging?"); // objc++ diagnoses during typename annotation. if (!getLangOpts().CPlusPlus) - (void)DiagnoseUseOfDecl(Class, Loc); + (void)DiagnoseUseOfDecl(Class, SelLoc); // Find the method we are messaging. if (!Method) { SourceRange TypeRange @@ -1979,7 +2055,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, if (!Method) Method = Class->lookupPrivateClassMethod(Sel); - if (Method && DiagnoseUseOfDecl(Method, Loc)) + if (Method && DiagnoseUseOfDecl(Method, SelLoc)) return ExprError(); } @@ -2095,7 +2171,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, bool isImplicit) { // The location of the receiver. SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart(); - + SourceRange RecRange = + SuperLoc.isValid()? SuperLoc : Receiver->getSourceRange(); + SourceLocation SelLoc; + if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) + SelLoc = SelectorLocs.front(); + else + SelLoc = Loc; + if (LBracLoc.isInvalid()) { Diag(Loc, diag::err_missing_open_square_message_send) << FixItHint::CreateInsertion(Loc, "["); @@ -2200,7 +2283,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = LookupMethodInQualifiedType(Sel, QClassTy, true); // warn if instance method found for a Class message. if (Method) { - Diag(Loc, diag::warn_instance_method_on_class_found) + Diag(SelLoc, diag::warn_instance_method_on_class_found) << Method->getSelector() << Sel; Diag(Method->getLocation(), diag::note_method_declared_at) << Method->getDeclName(); @@ -2215,7 +2298,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!Method) Method = ClassDecl->lookupPrivateClassMethod(Sel); } - if (Method && DiagnoseUseOfDecl(Method, Loc)) + if (Method && DiagnoseUseOfDecl(Method, SelLoc)) return ExprError(); } if (!Method) { @@ -2234,7 +2317,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { if (ID->getSuperClass()) - Diag(Loc, diag::warn_root_inst_method_not_found) + Diag(SelLoc, diag::warn_root_inst_method_not_found) << Sel << SourceRange(LBracLoc, RBracLoc); } } @@ -2253,7 +2336,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = LookupMethodInQualifiedType(Sel, QIdTy, true); if (!Method) Method = LookupMethodInQualifiedType(Sel, QIdTy, false); - if (Method && DiagnoseUseOfDecl(Method, Loc)) + if (Method && DiagnoseUseOfDecl(Method, SelLoc)) return ExprError(); } else if (const ObjCObjectPointerType *OCIType = ReceiverType->getAsObjCInterfacePointerType()) { @@ -2289,8 +2372,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = ClassDecl->lookupPrivateMethod(Sel); if (!Method && getLangOpts().ObjCAutoRefCount) { - Diag(Loc, diag::err_arc_may_not_respond) - << OCIType->getPointeeType() << Sel + Diag(SelLoc, diag::err_arc_may_not_respond) + << OCIType->getPointeeType() << Sel << RecRange << SourceRange(SelectorLocs.front(), SelectorLocs.back()); return ExprError(); } @@ -2303,12 +2386,13 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc)); if (Method && !forwardClass) - Diag(Loc, diag::warn_maynot_respond) - << OCIType->getInterfaceDecl()->getIdentifier() << Sel; + Diag(SelLoc, diag::warn_maynot_respond) + << OCIType->getInterfaceDecl()->getIdentifier() + << Sel << RecRange; } } } - if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass)) + if (Method && DiagnoseUseOfDecl(Method, SelLoc, forwardClass)) return ExprError(); } else { // Reject other random receiver types (e.g. structs). @@ -2337,8 +2421,6 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, diag::err_illegal_message_expr_incomplete_type)) return ExprError(); - SourceLocation SelLoc = SelectorLocs.front(); - // In ARC, forbid the user from sending messages to // retain/release/autorelease/dealloc/retainCount explicitly. if (getLangOpts().ObjCAutoRefCount) { @@ -2363,8 +2445,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, case OMF_release: case OMF_autorelease: case OMF_retainCount: - Diag(Loc, diag::err_arc_illegal_explicit_message) - << Sel << SelLoc; + Diag(SelLoc, diag::err_arc_illegal_explicit_message) + << Sel << RecRange; break; case OMF_performSelector: diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index baa5243e7c..9e8936e17b 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -82,6 +82,24 @@ static Expr *IsStringInit(Expr *init, QualType declType, ASTContext &Context) { return IsStringInit(init, arrayType, Context); } +/// Update the type of a string literal, including any surrounding parentheses, +/// to match the type of the object which it is initializing. +static void updateStringLiteralType(Expr *E, QualType Ty) { + while (true) { + E->setType(Ty); + if (isa<StringLiteral>(E) || isa<ObjCEncodeExpr>(E)) + break; + else if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) + E = PE->getSubExpr(); + else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) + E = UO->getSubExpr(); + else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E)) + E = GSE->getResultExpr(); + else + llvm_unreachable("unexpected expr in string literal init"); + } +} + static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, Sema &S) { // Get the length of the string as parsed. @@ -97,6 +115,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, DeclT = S.Context.getConstantArrayType(IAT->getElementType(), ConstVal, ArrayType::Normal, 0); + updateStringLiteralType(Str, DeclT); return; } @@ -106,7 +125,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, // the size may be smaller or larger than the string we are initializing. // FIXME: Avoid truncation for 64-bit length strings. if (S.getLangOpts().CPlusPlus) { - if (StringLiteral *SL = dyn_cast<StringLiteral>(Str)) { + if (StringLiteral *SL = dyn_cast<StringLiteral>(Str->IgnoreParens())) { // For Pascal strings it's OK to strip off the terminating null character, // so the example below is valid: // @@ -132,7 +151,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, // something like: // char x[1] = "foo"; // then this will set the string literal's type to char[1]. - Str->setType(DeclT); + updateStringLiteralType(Str, DeclT); } //===----------------------------------------------------------------------===// @@ -279,7 +298,7 @@ void InitListChecker::CheckValueInitializable(const InitializedEntity &Entity) { SourceLocation Loc; InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, true); - InitializationSequence InitSeq(SemaRef, Entity, Kind, 0, 0); + InitializationSequence InitSeq(SemaRef, Entity, Kind, None); if (InitSeq.Failed()) hadError = true; } @@ -293,6 +312,21 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, InitializedEntity MemberEntity = InitializedEntity::InitializeMember(Field, &ParentEntity); if (Init >= NumInits || !ILE->getInit(Init)) { + // If there's no explicit initializer but we have a default initializer, use + // that. This only happens in C++1y, since classes with default + // initializers are not aggregates in C++11. + if (Field->hasInClassInitializer()) { + Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, + ILE->getRBraceLoc(), Field); + if (Init < NumInits) + ILE->setInit(Init, DIE); + else { + ILE->updateInit(SemaRef.Context, Init, DIE); + RequiresSecondPass = true; + } + return; + } + // FIXME: We probably don't need to handle references // specially here, since value-initialization of references is // handled in InitializationSequence. @@ -312,15 +346,15 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, true); - InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, 0, 0); + InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, None); if (!InitSeq) { - InitSeq.Diagnose(SemaRef, MemberEntity, Kind, 0, 0); + InitSeq.Diagnose(SemaRef, MemberEntity, Kind, None); hadError = true; return; } ExprResult MemberInit - = InitSeq.Perform(SemaRef, MemberEntity, Kind, MultiExprArg()); + = InitSeq.Perform(SemaRef, MemberEntity, Kind, None); if (MemberInit.isInvalid()) { hadError = true; return; @@ -358,15 +392,24 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, Loc = ILE->getSyntacticForm()->getLocStart(); if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) { - if (RType->getDecl()->isUnion() && - ILE->getInitializedFieldInUnion()) + const RecordDecl *RDecl = RType->getDecl(); + if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) FillInValueInitForField(0, ILE->getInitializedFieldInUnion(), Entity, ILE, RequiresSecondPass); - else { + else if (RDecl->isUnion() && isa<CXXRecordDecl>(RDecl) && + cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) { + for (RecordDecl::field_iterator Field = RDecl->field_begin(), + FieldEnd = RDecl->field_end(); + Field != FieldEnd; ++Field) { + if (Field->hasInClassInitializer()) { + FillInValueInitForField(0, *Field, Entity, ILE, RequiresSecondPass); + break; + } + } + } else { unsigned Init = 0; - for (RecordDecl::field_iterator - Field = RType->getDecl()->field_begin(), - FieldEnd = RType->getDecl()->field_end(); + for (RecordDecl::field_iterator Field = RDecl->field_begin(), + FieldEnd = RDecl->field_end(); Field != FieldEnd; ++Field) { if (Field->isUnnamedBitfield()) continue; @@ -381,7 +424,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, ++Init; // Only look at the first initialization of a union. - if (RType->getDecl()->isUnion()) + if (RDecl->isUnion()) break; } } @@ -421,15 +464,15 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, if (!InitExpr && !ILE->hasArrayFiller()) { InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, true); - InitializationSequence InitSeq(SemaRef, ElementEntity, Kind, 0, 0); + InitializationSequence InitSeq(SemaRef, ElementEntity, Kind, None); if (!InitSeq) { - InitSeq.Diagnose(SemaRef, ElementEntity, Kind, 0, 0); + InitSeq.Diagnose(SemaRef, ElementEntity, Kind, None); hadError = true; return; } ExprResult ElementInit - = InitSeq.Perform(SemaRef, ElementEntity, Kind, MultiExprArg()); + = InitSeq.Perform(SemaRef, ElementEntity, Kind, None); if (ElementInit.isInvalid()) { hadError = true; return; @@ -784,12 +827,12 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // FIXME: Better EqualLoc? InitializationKind Kind = InitializationKind::CreateCopy(expr->getLocStart(), SourceLocation()); - InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1); + InitializationSequence Seq(SemaRef, Entity, Kind, expr); if (Seq) { if (!VerifyOnly) { ExprResult Result = - Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1)); + Seq.Perform(SemaRef, Entity, Kind, expr); if (Result.isInvalid()) hadError = true; @@ -819,8 +862,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, hadError = true; else { ExprRes = SemaRef.DefaultFunctionArrayLvalueConversion(ExprRes.take()); - if (ExprRes.isInvalid()) - hadError = true; + if (ExprRes.isInvalid()) + hadError = true; } UpdateStructuredListElement(StructuredList, StructuredIndex, ExprRes.takeAs<Expr>()); @@ -1323,8 +1366,23 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, } if (DeclType->isUnionType() && IList->getNumInits() == 0) { - // Value-initialize the first named member of the union. RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); + + // If there's a default initializer, use it. + if (isa<CXXRecordDecl>(RD) && cast<CXXRecordDecl>(RD)->hasInClassInitializer()) { + if (VerifyOnly) + return; + for (RecordDecl::field_iterator FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + if (Field->hasInClassInitializer()) { + StructuredList->setInitializedFieldInUnion(*Field); + // FIXME: Actually build a CXXDefaultInitExpr? + return; + } + } + } + + // Value-initialize the first named member of the union. for (RecordDecl::field_iterator FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { if (Field->getDeclName()) { @@ -1428,7 +1486,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, // Find first (if any) named field and emit warning. for (RecordDecl::field_iterator it = Field, end = RD->field_end(); it != end; ++it) { - if (!it->isUnnamedBitfield()) { + if (!it->isUnnamedBitfield() && !it->hasInClassInitializer()) { SemaRef.Diag(IList->getSourceRange().getEnd(), diag::warn_missing_field_initializers) << it->getName(); break; @@ -1441,7 +1499,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, !Field->getType()->isIncompleteArrayType()) { // FIXME: Should check for holes left by designated initializers too. for (; Field != FieldEnd && !hadError; ++Field) { - if (!Field->isUnnamedBitfield()) + if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer()) CheckValueInitializable( InitializedEntity::InitializeMember(*Field, &Entity)); } @@ -2073,7 +2131,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, InitListExpr *Result = new (SemaRef.Context) InitListExpr(SemaRef.Context, - InitRange.getBegin(), MultiExprArg(), + InitRange.getBegin(), None, InitRange.getEnd()); QualType ResultType = CurrentObjectType; @@ -2336,6 +2394,7 @@ DeclarationName InitializedEntity::getName() const { case EK_VectorElement: case EK_ComplexElement: case EK_BlockElement: + case EK_CompoundLiteralInit: return DeclarationName(); } @@ -2362,6 +2421,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_ComplexElement: case EK_BlockElement: case EK_LambdaCapture: + case EK_CompoundLiteralInit: return 0; } @@ -2379,6 +2439,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_Member: case EK_New: case EK_Temporary: + case EK_CompoundLiteralInit: case EK_Base: case EK_Delegating: case EK_ArrayElement: @@ -2409,6 +2470,7 @@ void InitializationSequence::Step::Destroy() { case SK_QualificationConversionRValue: case SK_QualificationConversionXValue: case SK_QualificationConversionLValue: + case SK_LValueToRValue: case SK_ListInitialization: case SK_ListConstructorCall: case SK_UnwrapInitList: @@ -2555,6 +2617,15 @@ void InitializationSequence::AddQualificationConversionStep(QualType Ty, Steps.push_back(S); } +void InitializationSequence::AddLValueToRValueStep(QualType Ty) { + assert(!Ty.hasQualifiers() && "rvalues may not have qualifiers"); + + Step S; + S.Kind = SK_LValueToRValue; + S.Type = Ty; + Steps.push_back(S); +} + void InitializationSequence::AddConversionSequenceStep( const ImplicitConversionSequence &ICS, QualType T) { @@ -2758,7 +2829,7 @@ static bool TryInitializerListConstruction(Sema &S, static OverloadingResult ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, - Expr **Args, unsigned NumArgs, + MultiExprArg Args, OverloadCandidateSet &CandidateSet, ArrayRef<NamedDecl *> Ctors, OverloadCandidateSet::iterator &Best, @@ -2784,7 +2855,7 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, // If we're performing copy initialization using a copy constructor, we // suppress user-defined conversions on the arguments. We do the same for // move constructors. - if ((CopyInitializing || (InitListSyntax && NumArgs == 1)) && + if ((CopyInitializing || (InitListSyntax && Args.size() == 1)) && Constructor->isCopyOrMoveConstructor()) SuppressUserConversions = true; } @@ -2794,8 +2865,7 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, (!OnlyListConstructors || S.isInitListConstructor(Constructor))) { if (ConstructorTmpl) S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, - /*ExplicitArgs*/ 0, - llvm::makeArrayRef(Args, NumArgs), + /*ExplicitArgs*/ 0, Args, CandidateSet, SuppressUserConversions); else { // C++ [over.match.copy]p1: @@ -2805,10 +2875,9 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, // context of direct-initialization, explicit conversion functions // are also considered. bool AllowExplicitConv = AllowExplicit && !CopyInitializing && - NumArgs == 1 && + Args.size() == 1 && Constructor->isCopyOrMoveConstructor(); - S.AddOverloadCandidate(Constructor, FoundDecl, - llvm::makeArrayRef(Args, NumArgs), CandidateSet, + S.AddOverloadCandidate(Constructor, FoundDecl, Args, CandidateSet, SuppressUserConversions, /*PartialOverloading=*/false, /*AllowExplicit=*/AllowExplicitConv); @@ -2828,11 +2897,10 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, static void TryConstructorInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, - Expr **Args, unsigned NumArgs, - QualType DestType, + MultiExprArg Args, QualType DestType, InitializationSequence &Sequence, bool InitListSyntax = false) { - assert((!InitListSyntax || (NumArgs == 1 && isa<InitListExpr>(Args[0]))) && + assert((!InitListSyntax || (Args.size() == 1 && isa<InitListExpr>(Args[0]))) && "InitListSyntax must come with a single initializer list argument."); // The type we're constructing needs to be complete. @@ -2881,15 +2949,14 @@ static void TryConstructorInitialization(Sema &S, // If the initializer list has no elements and T has a default constructor, // the first phase is omitted. if (ILE->getNumInits() != 0 || !DestRecordDecl->hasDefaultConstructor()) - Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs, + Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, CandidateSet, Ctors, Best, CopyInitialization, AllowExplicit, /*OnlyListConstructor=*/true, InitListSyntax); // Time to unwrap the init list. - Args = ILE->getInits(); - NumArgs = ILE->getNumInits(); + Args = MultiExprArg(ILE->getInits(), ILE->getNumInits()); } // C++11 [over.match.list]p1: @@ -2899,7 +2966,7 @@ static void TryConstructorInitialization(Sema &S, // elements of the initializer list. if (Result == OR_No_Viable_Function) { AsInitializerList = false; - Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs, + Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, CandidateSet, Ctors, Best, CopyInitialization, AllowExplicit, /*OnlyListConstructors=*/false, @@ -3106,8 +3173,8 @@ static void TryListInitialization(Sema &S, return; // - Otherwise, if T is a class type, constructors are considered. - Expr *Arg = InitList; - TryConstructorInitialization(S, Entity, Kind, &Arg, 1, DestType, + Expr *InitListAsExpr = InitList; + TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType, Sequence, /*InitListSyntax*/true); } else Sequence.SetFailed( @@ -3351,6 +3418,57 @@ static void TryReferenceInitialization(Sema &S, T1Quals, cv2T2, T2, T2Quals, Sequence); } +/// Converts the target of reference initialization so that it has the +/// appropriate qualifiers and value kind. +/// +/// In this case, 'x' is an 'int' lvalue, but it needs to be 'const int'. +/// \code +/// int x; +/// const int &r = x; +/// \endcode +/// +/// In this case the reference is binding to a bitfield lvalue, which isn't +/// valid. Perform a load to create a lifetime-extended temporary instead. +/// \code +/// const int &r = someStruct.bitfield; +/// \endcode +static ExprValueKind +convertQualifiersAndValueKindIfNecessary(Sema &S, + InitializationSequence &Sequence, + Expr *Initializer, + QualType cv1T1, + Qualifiers T1Quals, + Qualifiers T2Quals, + bool IsLValueRef) { + bool IsNonAddressableType = Initializer->refersToBitField() || + Initializer->refersToVectorElement(); + + if (IsNonAddressableType) { + // C++11 [dcl.init.ref]p5: [...] Otherwise, the reference shall be an + // lvalue reference to a non-volatile const type, or the reference shall be + // an rvalue reference. + // + // If not, we can't make a temporary and bind to that. Give up and allow the + // error to be diagnosed later. + if (IsLValueRef && (!T1Quals.hasConst() || T1Quals.hasVolatile())) { + assert(Initializer->isGLValue()); + return Initializer->getValueKind(); + } + + // Force a load so we can materialize a temporary. + Sequence.AddLValueToRValueStep(cv1T1.getUnqualifiedType()); + return VK_RValue; + } + + if (T1Quals != T2Quals) { + Sequence.AddQualificationConversionStep(cv1T1, + Initializer->getValueKind()); + } + + return Initializer->getValueKind(); +} + + /// \brief Reference initialization without resolving overloaded functions. static void TryReferenceInitializationCore(Sema &S, const InitializedEntity &Entity, @@ -3406,11 +3524,11 @@ static void TryReferenceInitializationCore(Sema &S, Sequence.AddObjCObjectConversionStep( S.Context.getQualifiedType(T1, T2Quals)); - if (T1Quals != T2Quals) - Sequence.AddQualificationConversionStep(cv1T1, VK_LValue); - bool BindingTemporary = T1Quals.hasConst() && !T1Quals.hasVolatile() && - (Initializer->getBitField() || Initializer->refersToVectorElement()); - Sequence.AddReferenceBindingStep(cv1T1, BindingTemporary); + ExprValueKind ValueKind = + convertQualifiersAndValueKindIfNecessary(S, Sequence, Initializer, + cv1T1, T1Quals, T2Quals, + isLValueRef); + Sequence.AddReferenceBindingStep(cv1T1, ValueKind == VK_RValue); return; } @@ -3493,10 +3611,12 @@ static void TryReferenceInitializationCore(Sema &S, Sequence.AddObjCObjectConversionStep( S.Context.getQualifiedType(T1, T2Quals)); - if (T1Quals != T2Quals) - Sequence.AddQualificationConversionStep(cv1T1, ValueKind); - Sequence.AddReferenceBindingStep(cv1T1, - /*bindingTemporary=*/InitCategory.isPRValue()); + ValueKind = convertQualifiersAndValueKindIfNecessary(S, Sequence, + Initializer, cv1T1, + T1Quals, T2Quals, + isLValueRef); + + Sequence.AddReferenceBindingStep(cv1T1, ValueKind == VK_RValue); return; } @@ -3518,6 +3638,14 @@ static void TryReferenceInitializationCore(Sema &S, return; } + if ((RefRelationship == Sema::Ref_Compatible || + RefRelationship == Sema::Ref_Compatible_With_Added_Qualification) && + isRValueRef && InitCategory.isLValue()) { + Sequence.SetFailed( + InitializationSequence::FK_RValueReferenceBindingToLValue); + return; + } + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } @@ -3660,12 +3788,11 @@ static void TryValueInitialization(Sema &S, // building the constructor call. This affects the semantics of a few // things (such as whether an explicit default constructor can be called). Expr *InitListAsExpr = InitList; - Expr **Args = InitList ? &InitListAsExpr : 0; - unsigned NumArgs = InitList ? 1 : 0; + MultiExprArg Args(&InitListAsExpr, InitList ? 1 : 0); bool InitListSyntax = InitList; - return TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, T, - Sequence, InitListSyntax); + return TryConstructorInitialization(S, Entity, Kind, Args, T, Sequence, + InitListSyntax); } } @@ -3688,7 +3815,7 @@ static void TryDefaultInitialization(Sema &S, // constructor for T is called (and the initialization is ill-formed if // T has no accessible default constructor); if (DestType->isRecordType() && S.getLangOpts().CPlusPlus) { - TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType, Sequence); + TryConstructorInitialization(S, Entity, Kind, None, DestType, Sequence); return; } @@ -4060,11 +4187,25 @@ static bool TryOCLZeroEventInitialization(Sema &S, InitializationSequence::InitializationSequence(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, - Expr **Args, - unsigned NumArgs) + MultiExprArg Args) : FailedCandidateSet(Kind.getLocation()) { ASTContext &Context = S.Context; + // Eliminate non-overload placeholder types in the arguments. We + // need to do this before checking whether types are dependent + // because lowering a pseudo-object expression might well give us + // something of dependent type. + for (unsigned I = 0, E = Args.size(); I != E; ++I) + if (Args[I]->getType()->isNonOverloadPlaceholderType()) { + // FIXME: should we be doing this here? + ExprResult result = S.CheckPlaceholderExpr(Args[I]); + if (result.isInvalid()) { + SetFailed(FK_PlaceholderType); + return; + } + Args[I] = result.take(); + } + // C++0x [dcl.init]p16: // The semantics of initializers are as follows. The destination type is // the type of the object or reference being initialized and the source @@ -4074,7 +4215,7 @@ InitializationSequence::InitializationSequence(Sema &S, QualType DestType = Entity.getType(); if (DestType->isDependentType() || - Expr::hasAnyTypeDependentArguments(llvm::makeArrayRef(Args, NumArgs))) { + Expr::hasAnyTypeDependentArguments(Args)) { SequenceKind = DependentSequence; return; } @@ -4082,21 +4223,9 @@ InitializationSequence::InitializationSequence(Sema &S, // Almost everything is a normal sequence. setSequenceKind(NormalSequence); - for (unsigned I = 0; I != NumArgs; ++I) - if (Args[I]->getType()->isNonOverloadPlaceholderType()) { - // FIXME: should we be doing this here? - ExprResult result = S.CheckPlaceholderExpr(Args[I]); - if (result.isInvalid()) { - SetFailed(FK_PlaceholderType); - return; - } - Args[I] = result.take(); - } - - QualType SourceType; Expr *Initializer = 0; - if (NumArgs == 1) { + if (Args.size() == 1) { Initializer = Args[0]; if (!isa<InitListExpr>(Initializer)) SourceType = Initializer->getType(); @@ -4118,7 +4247,7 @@ InitializationSequence::InitializationSequence(Sema &S, // (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. // (Therefore, multiple arguments are not permitted.) - if (NumArgs != 1) + if (Args.size() != 1) SetFailed(FK_TooManyInitsForReference); else TryReferenceInitialization(S, Entity, Kind, Args[0], *this); @@ -4127,7 +4256,7 @@ InitializationSequence::InitializationSequence(Sema &S, // - If the initializer is (), the object is value-initialized. if (Kind.getKind() == InitializationKind::IK_Value || - (Kind.getKind() == InitializationKind::IK_Direct && NumArgs == 0)) { + (Kind.getKind() == InitializationKind::IK_Direct && Args.empty())) { TryValueInitialization(S, Entity, Kind, *this); return; } @@ -4224,7 +4353,7 @@ InitializationSequence::InitializationSequence(Sema &S, (Kind.getKind() == InitializationKind::IK_Copy && (Context.hasSameUnqualifiedType(SourceType, DestType) || S.IsDerivedFrom(SourceType, DestType)))) - TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, + TryConstructorInitialization(S, Entity, Kind, Args, Entity.getType(), *this); // - Otherwise (i.e., for the remaining copy-initialization cases), // user-defined conversion sequences that can convert from the source @@ -4237,11 +4366,11 @@ InitializationSequence::InitializationSequence(Sema &S, return; } - if (NumArgs > 1) { + if (Args.size() > 1) { SetFailed(FK_TooManyInitsForScalar); return; } - assert(NumArgs == 1 && "Zero-argument case handled above"); + assert(Args.size() == 1 && "Zero-argument case handled above"); // - Otherwise, if the source type is a (possibly cv-qualified) class // type, conversion functions are considered. @@ -4342,6 +4471,7 @@ getAssignmentAction(const InitializedEntity &Entity) { case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: case InitializedEntity::EK_LambdaCapture: + case InitializedEntity::EK_CompoundLiteralInit: return Sema::AA_Initializing; } @@ -4364,6 +4494,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Exception: case InitializedEntity::EK_BlockElement: case InitializedEntity::EK_LambdaCapture: + case InitializedEntity::EK_CompoundLiteralInit: return false; case InitializedEntity::EK_Parameter: @@ -4394,6 +4525,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Temporary: case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_Exception: + case InitializedEntity::EK_CompoundLiteralInit: return true; } @@ -4475,6 +4607,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity, case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_CompoundLiteralInit: return Initializer->getLocStart(); } llvm_unreachable("missed an InitializedEntity kind?"); @@ -4611,8 +4744,7 @@ static ExprResult CopyObject(Sema &S, // Determine the arguments required to actually perform the // constructor call (we might have derived-to-base conversions, or // the copy constructor may have default arguments). - if (S.CompleteConstructorCall(Constructor, MultiExprArg(&CurInitExpr, 1), - Loc, ConstructorArgs)) + if (S.CompleteConstructorCall(Constructor, CurInitExpr, Loc, ConstructorArgs)) return ExprError(); // Actually perform the constructor call. @@ -4703,6 +4835,31 @@ static bool isReferenceBinding(const InitializationSequence::Step &s) { s.Kind == InitializationSequence::SK_BindReferenceToTemporary; } +/// Returns true if the parameters describe a constructor initialization of +/// an explicit temporary object, e.g. "Point(x, y)". +static bool isExplicitTemporary(const InitializedEntity &Entity, + const InitializationKind &Kind, + unsigned NumArgs) { + switch (Entity.getKind()) { + case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_CompoundLiteralInit: + break; + default: + return false; + } + + switch (Kind.getKind()) { + case InitializationKind::IK_DirectList: + return true; + // FIXME: Hack to work around cast weirdness. + case InitializationKind::IK_Direct: + case InitializationKind::IK_Value: + return NumArgs != 1; + default: + return false; + } +} + static ExprResult PerformConstructorInitialization(Sema &S, const InitializedEntity &Entity, @@ -4753,14 +4910,11 @@ PerformConstructorInitialization(Sema &S, return ExprError(); - if (Entity.getKind() == InitializedEntity::EK_Temporary && - (Kind.getKind() == InitializationKind::IK_DirectList || - (NumArgs != 1 && // FIXME: Hack to work around cast weirdness - (Kind.getKind() == InitializationKind::IK_Direct || - Kind.getKind() == InitializationKind::IK_Value)))) { + if (isExplicitTemporary(Entity, Kind, NumArgs)) { // An explicitly-constructed temporary, e.g., X(1, 2). S.MarkFunctionReferenced(Loc, Constructor); - S.DiagnoseUseOfDecl(Constructor, Loc); + if (S.DiagnoseUseOfDecl(Constructor, Loc)) + return ExprError(); TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); if (!TSInfo) @@ -4819,7 +4973,8 @@ PerformConstructorInitialization(Sema &S, // Only check access if all of that succeeded. S.CheckConstructorAccess(Loc, Constructor, Entity, Step.Function.FoundDecl.getAccess()); - S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc); + if (S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc)) + return ExprError(); if (shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); @@ -4857,6 +5012,7 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) { case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Temporary: case InitializedEntity::EK_LambdaCapture: + case InitializedEntity::EK_CompoundLiteralInit: // The entity being initialized might not outlive the full-expression. return false; } @@ -4871,8 +5027,7 @@ InitializationSequence::Perform(Sema &S, MultiExprArg Args, QualType *ResultType) { if (Failed()) { - unsigned NumArgs = Args.size(); - Diagnose(S, Entity, Kind, Args.data(), NumArgs); + Diagnose(S, Entity, Kind, Args); return ExprError(); } @@ -4980,6 +5135,7 @@ InitializationSequence::Perform(Sema &S, case SK_QualificationConversionLValue: case SK_QualificationConversionXValue: case SK_QualificationConversionRValue: + case SK_LValueToRValue: case SK_ConversionSequence: case SK_ListInitialization: case SK_UnwrapInitList: @@ -5022,7 +5178,8 @@ InitializationSequence::Perform(Sema &S, // Overload resolution determined which function invoke; update the // initializer to reflect that choice. S.CheckAddressOfMemberAccess(CurInit.get(), Step->Function.FoundDecl); - S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation()); + if (S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation())) + return ExprError(); CurInit = S.FixOverloadedFunctionReference(CurInit, Step->Function.FoundDecl, Step->Function.Function); @@ -5068,13 +5225,18 @@ InitializationSequence::Perform(Sema &S, } case SK_BindReference: - if (FieldDecl *BitField = CurInit.get()->getBitField()) { - // References cannot bind to bit fields (C++ [dcl.init.ref]p5). + // References cannot bind to bit-fields (C++ [dcl.init.ref]p5). + if (CurInit.get()->refersToBitField()) { + // We don't necessarily have an unambiguous source bit-field. + FieldDecl *BitField = CurInit.get()->getSourceBitField(); S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield) << Entity.getType().isVolatileQualified() - << BitField->getDeclName() + << (BitField ? BitField->getDeclName() : DeclarationName()) + << (BitField != NULL) << CurInit.get()->getSourceRange(); - S.Diag(BitField->getLocation(), diag::note_bitfield_decl); + if (BitField) + S.Diag(BitField->getLocation(), diag::note_bitfield_decl); + return ExprError(); } @@ -5096,6 +5258,9 @@ InitializationSequence::Perform(Sema &S, break; case SK_BindReferenceToTemporary: + // Make sure the "temporary" is actually an rvalue. + assert(CurInit.get()->isRValue() && "not a temporary"); + // Check exception specifications if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType)) return ExprError(); @@ -5155,7 +5320,8 @@ InitializationSequence::Perform(Sema &S, S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity, FoundFn.getAccess()); - S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); + if (S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation())) + return ExprError(); CastKind = CK_ConstructorConversion; QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); @@ -5169,7 +5335,8 @@ InitializationSequence::Perform(Sema &S, CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); S.CheckMemberOperatorAccess(Kind.getLocation(), CurInit.get(), 0, FoundFn); - S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); + if (S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation())) + return ExprError(); // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because @@ -5203,7 +5370,8 @@ InitializationSequence::Perform(Sema &S, S.CheckDestructorAccess(CurInit.get()->getLocStart(), Destructor, S.PDiag(diag::err_access_dtor_temp) << T); S.MarkFunctionReferenced(CurInit.get()->getLocStart(), Destructor); - S.DiagnoseUseOfDecl(Destructor, CurInit.get()->getLocStart()); + if (S.DiagnoseUseOfDecl(Destructor, CurInit.get()->getLocStart())) + return ExprError(); } } @@ -5233,6 +5401,16 @@ InitializationSequence::Perform(Sema &S, break; } + case SK_LValueToRValue: { + assert(CurInit.get()->isGLValue() && "cannot load from a prvalue"); + CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, Step->Type, + CK_LValueToRValue, + CurInit.take(), + /*BasePath=*/0, + VK_RValue)); + break; + } + case SK_ConversionSequence: { Sema::CheckedConversionKind CCK = Kind.isCStyleCast()? Sema::CCK_CStyleCast @@ -5464,7 +5642,7 @@ InitializationSequence::Perform(Sema &S, case SK_StdInitializerList: { QualType Dest = Step->Type; QualType E; - bool Success = S.isStdInitializerList(Dest, &E); + bool Success = S.isStdInitializerList(Dest.getNonReferenceType(), &E); (void)Success; assert(Success && "Destination type changed?"); @@ -5475,7 +5653,8 @@ InitializationSequence::Perform(Sema &S, S.MarkFunctionReferenced(Kind.getLocation(), Destructor); S.CheckDestructorAccess(Kind.getLocation(), Destructor, S.PDiag(diag::err_access_dtor_temp) << E); - S.DiagnoseUseOfDecl(Destructor, Kind.getLocation()); + if (S.DiagnoseUseOfDecl(Destructor, Kind.getLocation())) + return ExprError(); } } } @@ -5590,10 +5769,30 @@ static bool DiagnoseUninitializedReference(Sema &S, SourceLocation Loc, //===----------------------------------------------------------------------===// // Diagnose initialization failures //===----------------------------------------------------------------------===// + +/// Emit notes associated with an initialization that failed due to a +/// "simple" conversion failure. +static void emitBadConversionNotes(Sema &S, const InitializedEntity &entity, + Expr *op) { + QualType destType = entity.getType(); + if (destType.getNonReferenceType()->isObjCObjectPointerType() && + op->getType()->isObjCObjectPointerType()) { + + // Emit a possible note about the conversion failing because the + // operand is a message send with a related result type. + S.EmitRelatedResultTypeNote(op); + + // Emit a possible note about a return failing because we're + // expecting a related result type. + if (entity.getKind() == InitializedEntity::EK_Result) + S.EmitRelatedResultTypeNoteForReturn(destType); + } +} + bool InitializationSequence::Diagnose(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, - Expr **Args, unsigned NumArgs) { + ArrayRef<Expr *> Args) { if (!Failed()) return false; @@ -5601,7 +5800,7 @@ bool InitializationSequence::Diagnose(Sema &S, switch (Failure) { case FK_TooManyInitsForReference: // FIXME: Customize for the initialized entity? - if (NumArgs == 0) { + if (Args.empty()) { // Dig out the reference subobject which is uninitialized and diagnose it. // If this is value-initialization, this could be nested some way within // the target type. @@ -5613,7 +5812,7 @@ bool InitializationSequence::Diagnose(Sema &S, (void)Diagnosed; } else // FIXME: diagnostic below could be better! S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits) - << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); + << SourceRange(Args.front()->getLocStart(), Args.back()->getLocEnd()); break; case FK_ArrayNeedsInitList: @@ -5660,16 +5859,14 @@ bool InitializationSequence::Diagnose(Sema &S, << DestType << Args[0]->getType() << Args[0]->getSourceRange(); - FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, - llvm::makeArrayRef(Args, NumArgs)); + FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args); break; case OR_No_Viable_Function: S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) << Args[0]->getType() << DestType.getNonReferenceType() << Args[0]->getSourceRange(); - FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, - llvm::makeArrayRef(Args, NumArgs)); + FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args); break; case OR_Deleted: { @@ -5734,9 +5931,7 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->isLValue() << Args[0]->getType() << Args[0]->getSourceRange(); - if (DestType.getNonReferenceType()->isObjCObjectPointerType() && - Args[0]->getType()->isObjCObjectPointerType()) - S.EmitRelatedResultTypeNote(Args[0]); + emitBadConversionNotes(S, Entity, Args[0]); break; case FK_ConversionFailed: { @@ -5749,9 +5944,7 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->getSourceRange(); S.HandleFunctionTypeMismatch(PDiag, FromType, DestType); S.Diag(Kind.getLocation(), PDiag); - if (DestType.getNonReferenceType()->isObjCObjectPointerType() && - Args[0]->getType()->isObjCObjectPointerType()) - S.EmitRelatedResultTypeNote(Args[0]); + emitBadConversionNotes(S, Entity, Args[0]); break; } @@ -5766,7 +5959,7 @@ bool InitializationSequence::Diagnose(Sema &S, R = SourceRange(InitList->getInit(0)->getLocEnd(), InitList->getLocEnd()); else - R = SourceRange(Args[0]->getLocEnd(), Args[NumArgs - 1]->getLocEnd()); + R = SourceRange(Args.front()->getLocEnd(), Args.back()->getLocEnd()); R.setBegin(S.PP.getLocForEndOfToken(R.getBegin())); if (Kind.isCStyleOrFunctionalCast()) @@ -5791,15 +5984,14 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_ListConstructorOverloadFailed: case FK_ConstructorOverloadFailed: { SourceRange ArgsRange; - if (NumArgs) - ArgsRange = SourceRange(Args[0]->getLocStart(), - Args[NumArgs - 1]->getLocEnd()); + if (Args.size()) + ArgsRange = SourceRange(Args.front()->getLocStart(), + Args.back()->getLocEnd()); if (Failure == FK_ListConstructorOverloadFailed) { - assert(NumArgs == 1 && "List construction from other than 1 argument."); + assert(Args.size() == 1 && "List construction from other than 1 argument."); InitListExpr *InitList = cast<InitListExpr>(Args[0]); - Args = InitList->getInits(); - NumArgs = InitList->getNumInits(); + Args = MultiExprArg(InitList->getInits(), InitList->getNumInits()); } // FIXME: Using "DestType" for the entity we're printing is probably @@ -5808,8 +6000,7 @@ bool InitializationSequence::Diagnose(Sema &S, case OR_Ambiguous: S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init) << DestType << ArgsRange; - FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, - llvm::makeArrayRef(Args, NumArgs)); + FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args); break; case OR_No_Viable_Function: @@ -5825,7 +6016,8 @@ bool InitializationSequence::Diagnose(Sema &S, = cast<CXXConstructorDecl>(S.CurContext); if (Entity.getKind() == InitializedEntity::EK_Base) { S.Diag(Kind.getLocation(), diag::err_missing_default_ctor) - << Constructor->isImplicit() + << (Constructor->getInheritedConstructor() ? 2 : + Constructor->isImplicit() ? 1 : 0) << S.Context.getTypeDeclType(Constructor->getParent()) << /*base=*/0 << Entity.getType(); @@ -5837,7 +6029,8 @@ bool InitializationSequence::Diagnose(Sema &S, << S.Context.getTagDeclType(BaseDecl); } else { S.Diag(Kind.getLocation(), diag::err_missing_default_ctor) - << Constructor->isImplicit() + << (Constructor->getInheritedConstructor() ? 2 : + Constructor->isImplicit() ? 1 : 0) << S.Context.getTypeDeclType(Constructor->getParent()) << /*member=*/1 << Entity.getName(); @@ -5854,8 +6047,7 @@ bool InitializationSequence::Diagnose(Sema &S, S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init) << DestType << ArgsRange; - FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, - llvm::makeArrayRef(Args, NumArgs)); + FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args); break; case OR_Deleted: { @@ -5898,7 +6090,8 @@ bool InitializationSequence::Diagnose(Sema &S, // initialized. CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(S.CurContext); S.Diag(Kind.getLocation(), diag::err_uninitialized_member_in_ctor) - << Constructor->isImplicit() + << (Constructor->getInheritedConstructor() ? 2 : + Constructor->isImplicit() ? 1 : 0) << S.Context.getTypeDeclType(Constructor->getParent()) << /*const=*/1 << Entity.getName(); @@ -5939,7 +6132,7 @@ bool InitializationSequence::Diagnose(Sema &S, unsigned NumInits = InitList->getNumInits(); QualType DestType = Entity.getType(); QualType E; - bool Success = S.isStdInitializerList(DestType, &E); + bool Success = S.isStdInitializerList(DestType.getNonReferenceType(), &E); (void)Success; assert(Success && "Where did the std::initializer_list go?"); InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary( @@ -6158,6 +6351,10 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "qualification conversion (lvalue)"; break; + case SK_LValueToRValue: + OS << "load (lvalue to rvalue)"; + break; + case SK_ConversionSequence: OS << "implicit conversion sequence ("; S->ICS->DebugPrint(); // FIXME: use OS @@ -6368,7 +6565,7 @@ Sema::CanPerformCopyInitialization(const InitializedEntity &Entity, InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(), SourceLocation()); - InitializationSequence Seq(*this, Entity, Kind, &InitE, 1); + InitializationSequence Seq(*this, Entity, Kind, InitE); return !Seq.Failed(); } @@ -6390,10 +6587,10 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity, InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(), EqualLoc, AllowExplicit); - InitializationSequence Seq(*this, Entity, Kind, &InitE, 1); + InitializationSequence Seq(*this, Entity, Kind, InitE); Init.release(); - ExprResult Result = Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1)); + ExprResult Result = Seq.Perform(*this, Entity, Kind, InitE); if (!Result.isInvalid() && TopLevelOfInitList) DiagnoseNarrowingInInitList(*this, Seq, Entity.getType(), diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 468fa0251e..c7ba3cc822 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -74,7 +74,6 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, IntroducerRange.getBegin(), MethodNameLoc), MethodType->getType(), MethodType, - /*isStatic=*/false, SC_None, /*isInline=*/true, /*isConstExpr=*/false, @@ -453,8 +452,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, FunctionProtoType::ExtProtoInfo EPI; EPI.HasTrailingReturn = true; EPI.TypeQuals |= DeclSpec::TQ_const; - QualType MethodTy = Context.getFunctionType(Context.DependentTy, - ArrayRef<QualType>(), + QualType MethodTy = Context.getFunctionType(Context.DependentTy, None, EPI); MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy); ExplicitParams = false; @@ -709,7 +707,7 @@ static void addFunctionPointerConversion(Sema &S, FunctionProtoType::ExtProtoInfo ExtInfo; ExtInfo.TypeQuals = Qualifiers::Const; QualType ConvTy = - S.Context.getFunctionType(FunctionPtrTy, ArrayRef<QualType>(), ExtInfo); + S.Context.getFunctionType(FunctionPtrTy, None, ExtInfo); SourceLocation Loc = IntroducerRange.getBegin(); DeclarationName Name @@ -738,7 +736,7 @@ static void addFunctionPointerConversion(Sema &S, = CXXMethodDecl::Create(S.Context, Class, Loc, DeclarationNameInfo(Name, Loc), FunctionTy, CallOperator->getTypeSourceInfo(), - /*IsStatic=*/true, SC_Static, /*IsInline=*/true, + SC_Static, /*IsInline=*/true, /*IsConstexpr=*/false, CallOperator->getBody()->getLocEnd()); SmallVector<ParmVarDecl *, 4> InvokeParams; @@ -751,7 +749,6 @@ static void addFunctionPointerConversion(Sema &S, From->getType(), From->getTypeSourceInfo(), From->getStorageClass(), - From->getStorageClassAsWritten(), /*DefaultArg=*/0)); } Invoke->setParams(InvokeParams); @@ -781,8 +778,7 @@ static void addBlockPointerConversion(Sema &S, FunctionProtoType::ExtProtoInfo ExtInfo; ExtInfo.TypeQuals = Qualifiers::Const; - QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, ArrayRef<QualType>(), - ExtInfo); + QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, None, ExtInfo); SourceLocation Loc = IntroducerRange.getBegin(); DeclarationName Name @@ -864,6 +860,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, CaptureDefault = LCD_ByCopy; break; + case CapturingScopeInfo::ImpCap_CapturedRegion: case CapturingScopeInfo::ImpCap_LambdaByref: CaptureDefault = LCD_ByRef; break; @@ -951,6 +948,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, if (!CurContext->isDependentContext()) { switch (ExprEvalContexts.back().Context) { case Unevaluated: + case UnevaluatedAbstract: // We don't actually diagnose this case immediately, because we // could be within a context where we might find out later that // the expression is potentially evaluated (e.g., for typeid). @@ -1010,7 +1008,6 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation, From->getType(), From->getTypeSourceInfo(), From->getStorageClass(), - From->getStorageClassAsWritten(), /*DefaultArg=*/0)); } Block->setParams(BlockParams); @@ -1025,7 +1022,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation, VarDecl *CapVar = VarDecl::Create(Context, Block, ConvLocation, ConvLocation, 0, Src->getType(), CapVarTSI, - SC_None, SC_None); + SC_None); BlockDecl::Capture Capture(/*Variable=*/CapVar, /*ByRef=*/false, /*Nested=*/false, /*Copy=*/Init.take()); Block->setCaptures(Context, &Capture, &Capture + 1, diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index eae6269ca6..9ab3b2d08e 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -287,10 +287,10 @@ void LookupResult::configure() { IDNS = getIDNS(LookupKind, SemaRef.getLangOpts().CPlusPlus, isForRedeclaration()); - // If we're looking for one of the allocation or deallocation - // operators, make sure that the implicitly-declared new and delete - // operators can be found. if (!isForRedeclaration()) { + // If we're looking for one of the allocation or deallocation + // operators, make sure that the implicitly-declared new and delete + // operators can be found. switch (NameInfo.getName().getCXXOverloadedOperator()) { case OO_New: case OO_Delete: @@ -302,6 +302,15 @@ void LookupResult::configure() { default: break; } + + // Compiler builtins are always visible, regardless of where they end + // up being declared. + if (IdentifierInfo *Id = NameInfo.getName().getAsIdentifierInfo()) { + if (unsigned BuiltinID = Id->getBuiltinID()) { + if (!SemaRef.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) + AllowHidden = true; + } + } } } @@ -722,7 +731,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { EPI.NumExceptions = 0; QualType ExpectedType = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), - ArrayRef<QualType>(), EPI); + None, EPI); // Perform template argument deduction against the type that we would // expect the function to have. @@ -875,6 +884,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // } // } // + UnqualUsingDirectiveSet UDirs; + bool VisitedUsingDirectives = false; DeclContext *OutsideOfTemplateParamDC = 0; for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()); @@ -945,6 +956,40 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { continue; } + // If this is a file context, we need to perform unqualified name + // lookup considering using directives. + if (Ctx->isFileContext()) { + // If we haven't handled using directives yet, do so now. + if (!VisitedUsingDirectives) { + // Add using directives from this context up to the top level. + for (DeclContext *UCtx = Ctx; UCtx; UCtx = UCtx->getParent()) { + if (UCtx->isTransparentContext()) + continue; + + UDirs.visit(UCtx, UCtx); + } + + // Find the innermost file scope, so we can add using directives + // from local scopes. + Scope *InnermostFileScope = S; + while (InnermostFileScope && + !isNamespaceOrTranslationUnitScope(InnermostFileScope)) + InnermostFileScope = InnermostFileScope->getParent(); + UDirs.visitScopeChain(Initial, InnermostFileScope); + + UDirs.done(); + + VisitedUsingDirectives = true; + } + + if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) { + R.resolveKind(); + return true; + } + + continue; + } + // Perform qualified name lookup into this context. // FIXME: In some cases, we know that every name that could be found by // this qualified name lookup will also be on the identifier chain. For @@ -970,16 +1015,15 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // // FIXME: Cache this sorted list in Scope structure, and DeclContext, so we // don't build it for each lookup! - - UnqualUsingDirectiveSet UDirs; - UDirs.visitScopeChain(Initial, S); - UDirs.done(); - + if (!VisitedUsingDirectives) { + UDirs.visitScopeChain(Initial, S); + UDirs.done(); + } + // Lookup namespace scope, and global scope. // Unqualified name lookup in C++ requires looking into scopes // that aren't strictly lexical, and therefore we walk through the // context as well as walking through the scopes. - for (; S; S = S->getParent()) { // Check whether the IdResolver has anything in this scope. bool Found = false; @@ -2043,6 +2087,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { case Type::Complex: break; + // Non-deduced auto types only get here for error cases. + case Type::Auto: + break; + // If T is an Objective-C object or interface type, or a pointer to an // object or interface type, the associated namespace is the global // namespace. @@ -2538,6 +2586,12 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R, bool IsRaw = false; bool IsExactMatch = false; + // If the declaration we found is invalid, skip it. + if (D->isInvalidDecl()) { + F.erase(); + continue; + } + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FD->getNumParams() == 1 && FD->getParamDecl(0)->getType()->getAs<PointerType>()) @@ -3382,7 +3436,7 @@ class NamespaceSpecifierSet { } DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) { - assert(Start && "Bulding a context chain from a null context"); + assert(Start && "Building a context chain from a null context"); DeclContextList Chain; for (DeclContext *DC = Start->getPrimaryContext(); DC != NULL; DC = DC->getLookupParent()) { @@ -3734,6 +3788,10 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, if (!ActiveTemplateInstantiations.empty()) return TypoCorrection(); + // Don't try to correct 'super'. + if (S && S->isInObjcMethodScope() && Typo == getSuperIdentifier()) + return TypoCorrection(); + NamespaceSpecifierSet Namespaces(Context, CurContext, SS); TypoCorrectionConsumer Consumer(*this, Typo); @@ -4114,3 +4172,21 @@ std::string TypoCorrection::getAsString(const LangOptions &LO) const { return CorrectionName.getAsString(); } + +bool CorrectionCandidateCallback::ValidateCandidate(const TypoCorrection &candidate) { + if (!candidate.isResolved()) + return true; + + if (candidate.isKeyword()) + return WantTypeSpecifiers || WantExpressionKeywords || WantCXXNamedCasts || + WantRemainingKeywords || WantObjCSuper; + + for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(), + CDeclEnd = candidate.end(); + CDecl != CDeclEnd; ++CDecl) { + if (!isa<TypeDecl>(*CDecl)) + return true; + } + + return WantTypeSpecifiers; +} diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index e046faa04d..91f0881ae0 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -996,8 +996,10 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, PropertyIvarType->getAs<ObjCObjectPointerType>()) { const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl(); if (ObjI && ObjI->isArcWeakrefUnavailable()) { - Diag(PropertyDiagLoc, diag::err_arc_weak_unavailable_property); - Diag(property->getLocation(), diag::note_property_declare); + Diag(property->getLocation(), + diag::err_arc_weak_unavailable_property) << PropertyIvarType; + Diag(ClassImpDecl->getLocation(), diag::note_implemented_by_class) + << ClassImpDecl->getName(); err = true; } } @@ -1134,6 +1136,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, MarkDeclRefReferenced(SelfExpr); Expr *IvarRefExpr = new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc, + Ivar->getLocation(), SelfExpr, true, true); ExprResult Res = PerformCopyInitialization(InitializedEntity::InitializeResult( @@ -1169,6 +1172,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, MarkDeclRefReferenced(SelfExpr); Expr *lhs = new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc, + Ivar->getLocation(), SelfExpr, true, true); ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); ParmVarDecl *Param = (*P); @@ -1585,13 +1589,33 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, for (unsigned i = 0, e = PropertyOrder.size(); i != e; i++) { ObjCPropertyDecl *Prop = PropertyOrder[i]; // If property to be implemented in the super class, ignore. - if (SuperPropMap[Prop->getIdentifier()]) + if (SuperPropMap[Prop->getIdentifier()]) { + ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()]; + if ((Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) && + (PropInSuperClass->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_readonly) && + !IMPDecl->getInstanceMethod(Prop->getSetterName()) && + !IDecl->HasUserDeclaredSetterMethod(Prop)) { + Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property) + << Prop->getIdentifier()->getName(); + Diag(PropInSuperClass->getLocation(), diag::note_property_declare); + } continue; + } // Is there a matching property synthesize/dynamic? if (Prop->isInvalidDecl() || - Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || - IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) + Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional) + continue; + if (ObjCPropertyImplDecl *PID = + IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) { + if (PID->getPropertyDecl() != Prop) { + Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property) + << Prop->getIdentifier()->getName(); + if (!PID->getLocation().isInvalid()) + Diag(PID->getLocation(), diag::note_property_synthesize); + } continue; + } // Property may have been synthesized by user. if (IMPDecl->FindPropertyImplDecl(Prop->getIdentifier())) continue; @@ -1638,8 +1662,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { } void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, - ObjCContainerDecl *CDecl, - const SelectorSet &InsMap) { + ObjCContainerDecl *CDecl) { ObjCContainerDecl::PropertyMap NoNeedToImplPropMap; ObjCInterfaceDecl *IDecl; // Gather properties which need not be implemented in this class @@ -1668,6 +1691,26 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, EI = IMPDecl->propimpl_end(); I != EI; ++I) PropImplMap.insert(I->getPropertyDecl()); + SelectorSet InsMap; + // Collect property accessors implemented in current implementation. + for (ObjCImplementationDecl::instmeth_iterator + I = IMPDecl->instmeth_begin(), E = IMPDecl->instmeth_end(); I!=E; ++I) + InsMap.insert((*I)->getSelector()); + + ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl); + ObjCInterfaceDecl *PrimaryClass = 0; + if (C && !C->IsClassExtension()) + if ((PrimaryClass = C->getClassInterface())) + // Report unimplemented properties in the category as well. + if (ObjCImplDecl *IMP = PrimaryClass->getImplementation()) { + // When reporting on missing setter/getters, do not report when + // setter/getter is implemented in category's primary class + // implementation. + for (ObjCImplementationDecl::instmeth_iterator + I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I) + InsMap.insert((*I)->getSelector()); + } + for (ObjCContainerDecl::PropertyMap::iterator P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { ObjCPropertyDecl *Prop = P->second; @@ -1677,7 +1720,13 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, PropImplMap.count(Prop) || Prop->getAvailability() == AR_Unavailable) continue; - if (!InsMap.count(Prop->getGetterName())) { + // When reporting on missing property getter implementation in + // categories, do not report when they are declared in primary class, + // class's protocol, or one of it super classes. This is because, + // the class is going to implement them. + if (!InsMap.count(Prop->getGetterName()) && + (PrimaryClass == 0 || + !PrimaryClass->lookupPropertyAccessor(Prop->getGetterName(), C))) { Diag(IMPDecl->getLocation(), isa<ObjCCategoryDecl>(CDecl) ? diag::warn_setter_getter_impl_required_in_category : @@ -1691,8 +1740,13 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, Diag(RID->getLocation(), diag::note_suppressed_class_declare); } - - if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { + // When reporting on missing property setter implementation in + // categories, do not report when they are declared in primary class, + // class's protocol, or one of it super classes. This is because, + // the class is going to implement them. + if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName()) && + (PrimaryClass == 0 || + !PrimaryClass->lookupPropertyAccessor(Prop->getSetterName(), C))) { Diag(IMPDecl->getLocation(), isa<ObjCCategoryDecl>(CDecl) ? diag::warn_setter_getter_impl_required_in_category : @@ -1912,6 +1966,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, if (property->hasAttr<NSReturnsNotRetainedAttr>()) GetterMethod->addAttr( ::new (Context) NSReturnsNotRetainedAttr(Loc, Context)); + + if (getLangOpts().ObjCAutoRefCount) + CheckARCMethodDecl(GetterMethod); } else // A user declared getter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation @@ -1949,10 +2006,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, property->getType().getUnqualifiedType(), /*TInfo=*/0, SC_None, - SC_None, 0); - SetterMethod->setMethodParams(Context, Argument, - ArrayRef<SourceLocation>()); + SetterMethod->setMethodParams(Context, Argument, None); AddPropertyAttrs(*this, SetterMethod, property); @@ -1961,6 +2016,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, // and the real context should be the same. if (lexicalDC) SetterMethod->setLexicalDeclContext(lexicalDC); + + // It's possible for the user to have set a very odd custom + // setter selector that causes it to have a method family. + if (getLangOpts().ObjCAutoRefCount) + CheckARCMethodDecl(SetterMethod); } else // A user declared setter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp new file mode 100644 index 0000000000..c815d4f9ab --- /dev/null +++ b/lib/Sema/SemaOpenMP.cpp @@ -0,0 +1,181 @@ +//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This file implements semantic analysis for OpenMP directives and +/// clauses +/// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/OpenMPKinds.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclOpenMP.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Lookup.h" +using namespace clang; + +namespace { + + class VarDeclFilterCCC : public CorrectionCandidateCallback { + private: + Sema &Actions; + public: + VarDeclFilterCCC(Sema &S) : Actions(S) { } + virtual bool ValidateCandidate(const TypoCorrection &Candidate) { + NamedDecl *ND = Candidate.getCorrectionDecl(); + if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) { + return VD->hasGlobalStorage() && + Actions.isDeclInScope(ND, Actions.getCurLexicalContext(), + Actions.getCurScope()); + } + return false; + } + }; +} +Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective( + SourceLocation Loc, + Scope *CurScope, + ArrayRef<DeclarationNameInfo> IdList) { + SmallVector<DeclRefExpr *, 5> Vars; + for (ArrayRef<DeclarationNameInfo>::iterator I = IdList.begin(), + E = IdList.end(); + I != E; ++I) { + LookupResult Lookup(*this, *I, LookupOrdinaryName); + LookupParsedName(Lookup, CurScope, NULL, true); + + if (Lookup.isAmbiguous()) + continue; + + VarDecl *VD; + if (!Lookup.isSingleResult()) { + VarDeclFilterCCC Validator(*this); + TypoCorrection Corrected = CorrectTypo(*I, LookupOrdinaryName, CurScope, + 0, Validator); + std::string CorrectedStr = Corrected.getAsString(getLangOpts()); + std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts()); + if (Lookup.empty()) { + if (Corrected.isResolved()) { + Diag(I->getLoc(), diag::err_undeclared_var_use_suggest) + << I->getName() << CorrectedQuotedStr + << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr); + } else { + Diag(I->getLoc(), diag::err_undeclared_var_use) + << I->getName(); + } + } else { + Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest) + << I->getName() << Corrected.isResolved() << CorrectedQuotedStr + << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr); + } + if (!Corrected.isResolved()) continue; + VD = Corrected.getCorrectionDeclAs<VarDecl>(); + } else { + if (!(VD = Lookup.getAsSingle<VarDecl>())) { + Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest) + << I->getName() << 0; + Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at); + continue; + } + } + + // OpenMP [2.9.2, Syntax, C/C++] + // Variables must be file-scope, namespace-scope, or static block-scope. + if (!VD->hasGlobalStorage()) { + Diag(I->getLoc(), diag::err_omp_global_var_arg) + << getOpenMPDirectiveName(OMPD_threadprivate) + << !VD->isStaticLocal(); + Diag(VD->getLocation(), diag::note_forward_declaration) << VD; + continue; + } + + // OpenMP [2.9.2, Restrictions, C/C++, p.2] + // A threadprivate directive for file-scope variables must appear outside + // any definition or declaration. + // OpenMP [2.9.2, Restrictions, C/C++, p.3] + // A threadprivate directive for static class member variables must appear + // in the class definition, in the same scope in which the member + // variables are declared. + // OpenMP [2.9.2, Restrictions, C/C++, p.4] + // A threadprivate directive for namespace-scope variables must appear + // outside any definition or declaration other than the namespace + // definition itself. + // OpenMP [2.9.2, Restrictions, C/C++, p.6] + // A threadprivate directive for static block-scope variables must appear + // in the scope of the variable and not in a nested scope. + NamedDecl *ND = cast<NamedDecl>(VD); + if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) { + Diag(I->getLoc(), diag::err_omp_var_scope) + << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + Diag(VD->getLocation(), diag::note_forward_declaration) << VD; + continue; + } + + // OpenMP [2.9.2, Restrictions, C/C++, p.2-6] + // A threadprivate directive must lexically precede all references to any + // of the variables in its list. + if (VD->isUsed()) { + Diag(I->getLoc(), diag::err_omp_var_used) + << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + continue; + } + + QualType ExprType = VD->getType().getNonReferenceType(); + DeclRefExpr *Var = cast<DeclRefExpr>(BuildDeclRefExpr(VD, + ExprType, + VK_RValue, + I->getLoc()).take()); + Vars.push_back(Var); + } + if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, Vars)) { + CurContext->addDecl(D); + return DeclGroupPtrTy::make(DeclGroupRef(D)); + } + return DeclGroupPtrTy(); +} + +OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( + SourceLocation Loc, + ArrayRef<DeclRefExpr *> VarList) { + SmallVector<DeclRefExpr *, 5> Vars; + for (ArrayRef<DeclRefExpr *>::iterator I = VarList.begin(), + E = VarList.end(); + I != E; ++I) { + VarDecl *VD = cast<VarDecl>((*I)->getDecl()); + SourceLocation ILoc = (*I)->getLocation(); + + // OpenMP [2.9.2, Restrictions, C/C++, p.10] + // A threadprivate variable must not have an incomplete type. + if (RequireCompleteType(ILoc, VD->getType(), + diag::err_omp_incomplete_type)) { + continue; + } + + // OpenMP [2.9.2, Restrictions, C/C++, p.10] + // A threadprivate variable must not have a reference type. + if (VD->getType()->isReferenceType()) { + Diag(ILoc, diag::err_omp_ref_type_arg) + << getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType(); + Diag(VD->getLocation(), diag::note_forward_declaration) << VD; + continue; + } + + // Check if this is a TLS variable. + if (VD->getTLSKind()) { + Diag(ILoc, diag::err_omp_var_thread_local) << VD; + Diag(VD->getLocation(), diag::note_forward_declaration) << VD; + continue; + } + + Vars.push_back(*I); + } + return Vars.empty() ? + 0 : OMPThreadPrivateDecl::Create(Context, + getCurLexicalContext(), + Loc, Vars); +} diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 16fd28e461..529ba127cb 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -42,13 +42,15 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, bool HadMultipleCandidates, SourceLocation Loc = SourceLocation(), const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){ + if (S.DiagnoseUseOfDecl(FoundDecl, Loc)) + return ExprError(); + DeclRefExpr *DRE = new (S.Context) DeclRefExpr(Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo); if (HadMultipleCandidates) DRE->setHadMultipleCandidates(true); S.MarkDeclRefReferenced(DRE); - S.DiagnoseUseOfDecl(FoundDecl, Loc); ExprResult E = S.Owned(DRE); E = S.DefaultFunctionArrayConversion(E.take()); @@ -920,7 +922,8 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, // function templates hide function templates with different // return types or template parameter lists. bool UseMemberUsingDeclRules = - (OldIsUsingDecl || NewIsUsingDecl) && CurContext->isRecord(); + (OldIsUsingDecl || NewIsUsingDecl) && CurContext->isRecord() && + !New->getFriendObjectKind(); if (FunctionTemplateDecl *OldT = dyn_cast<FunctionTemplateDecl>(OldD)) { if (!IsOverload(New, OldT->getTemplatedDecl(), UseMemberUsingDeclRules)) { @@ -939,6 +942,9 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, continue; } + if (!shouldLinkPossiblyHiddenDecl(*I, New)) + continue; + Match = *I; return Ovl_Match; } @@ -977,13 +983,8 @@ static bool canBeOverloaded(const FunctionDecl &D) { return true; } -bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, - bool UseUsingDeclRules) { - // If both of the functions are extern "C", then they are not - // overloads. - if (!canBeOverloaded(*Old) && !canBeOverloaded(*New)) - return false; - +static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old, + bool UseUsingDeclRules) { FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate(); FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate(); @@ -994,8 +995,8 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, return true; // Is the function New an overload of the function Old? - QualType OldQType = Context.getCanonicalType(Old->getType()); - QualType NewQType = Context.getCanonicalType(New->getType()); + QualType OldQType = S.Context.getCanonicalType(Old->getType()); + QualType NewQType = S.Context.getCanonicalType(New->getType()); // Compare the signatures (C++ 1.3.10) of the two functions to // determine whether they are overloads. If we find any mismatch @@ -1016,7 +1017,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, if (OldQType != NewQType && (OldType->getNumArgs() != NewType->getNumArgs() || OldType->isVariadic() != NewType->isVariadic() || - !FunctionArgTypesAreEqual(OldType, NewType))) + !S.FunctionArgTypesAreEqual(OldType, NewType))) return true; // C++ [temp.over.link]p4: @@ -1032,9 +1033,9 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, // However, we don't consider either of these when deciding whether // a member introduced by a shadow declaration is hidden. if (!UseUsingDeclRules && NewTemplate && - (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), - OldTemplate->getTemplateParameters(), - false, TPL_TemplateMatch) || + (!S.TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), + OldTemplate->getTemplateParameters(), + false, S.TPL_TemplateMatch) || OldType->getResultType() != NewType->getResultType())) return true; @@ -1060,9 +1061,9 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, // declarations with the same name, the same parameter-type-list, and // the same template parameter lists cannot be overloaded if any of // them, but not all, have a ref-qualifier (8.3.5). - Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload) + S.Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload) << NewMethod->getRefQualifier() << OldMethod->getRefQualifier(); - Diag(OldMethod->getLocation(), diag::note_previous_declaration); + S.Diag(OldMethod->getLocation(), diag::note_previous_declaration); } return true; } @@ -1082,6 +1083,19 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, return false; } +bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, + bool UseUsingDeclRules) { + if (!shouldTryToOverload(*this, New, Old, UseUsingDeclRules)) + return false; + + // If both of the functions are extern "C", then they are not + // overloads. + if (!canBeOverloaded(*Old) && !canBeOverloaded(*New)) + return false; + + return true; +} + /// \brief Checks availability of the function depending on the current /// function context. Inside an unavailable function, unavailability is ignored. /// @@ -1823,7 +1837,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // conversion. using llvm::APSInt; if (From) - if (FieldDecl *MemberDecl = From->getBitField()) { + if (FieldDecl *MemberDecl = From->getSourceBitField()) { APSInt BitWidth; if (FromType->isIntegralType(Context) && MemberDecl->getBitWidth()->isIntegerConstantExpr(BitWidth, Context)) { @@ -3929,6 +3943,15 @@ CompareDerivedToBaseConversions(Sema &S, return ImplicitConversionSequence::Indistinguishable; } +/// \brief Determine whether the given type is valid, e.g., it is not an invalid +/// C++ class. +static bool isTypeValid(QualType T) { + if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) + return !Record->isInvalidDecl(); + + return true; +} + /// CompareReferenceRelationship - Compare the two types T1 and T2 to /// determine whether they are reference-related, /// reference-compatible, reference-compatible with added @@ -3962,7 +3985,8 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, if (UnqualT1 == UnqualT2) { // Nothing to do. } else if (!RequireCompleteType(Loc, OrigT2, 0) && - IsDerivedFrom(UnqualT2, UnqualT1)) + isTypeValid(UnqualT1) && isTypeValid(UnqualT2) && + IsDerivedFrom(UnqualT2, UnqualT1)) DerivedToBase = true; else if (UnqualT1->isObjCObjectOrInterfaceType() && UnqualT2->isObjCObjectOrInterfaceType() && @@ -5005,7 +5029,7 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T, Expr::EvalResult Eval; Eval.Diag = &Notes; - if (!Result.get()->EvaluateAsRValue(Eval, Context)) { + if (!Result.get()->EvaluateAsRValue(Eval, Context) || !Eval.Val.isInt()) { // The expression can't be folded, so we can't keep it at this position in // the AST. Result = ExprError(); @@ -5454,7 +5478,7 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { NamedDecl *Decl = FoundDecl.getDecl(); @@ -5469,12 +5493,12 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, AddMethodTemplateCandidate(TD, FoundDecl, ActingContext, /*ExplicitArgs*/ 0, ObjectType, ObjectClassification, - llvm::makeArrayRef(Args, NumArgs), CandidateSet, + Args, CandidateSet, SuppressUserConversions); } else { AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext, ObjectType, ObjectClassification, - llvm::makeArrayRef(Args, NumArgs), + Args, CandidateSet, SuppressUserConversions); } } @@ -5702,6 +5726,14 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, if (!CandidateSet.isNewCandidate(Conversion)) return; + // If the conversion function has an undeduced return type, trigger its + // deduction now. + if (getLangOpts().CPlusPlus1y && ConvType->isUndeducedType()) { + if (DeduceReturnType(Conversion, From->getExprLoc())) + return; + ConvType = Conversion->getConversionType().getNonReferenceType(); + } + // Overload resolution is always an unevaluated context. EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); @@ -5781,7 +5813,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // there are 0 arguments (i.e., nothing is allocated using ASTContext's // allocator). QualType CallResultType = ConversionType.getNonLValueExprType(Context); - CallExpr Call(Context, &ConversionFn, MultiExprArg(), CallResultType, VK, + CallExpr Call(Context, &ConversionFn, None, CallResultType, VK, From->getLocStart()); ImplicitConversionSequence ICS = TryCopyInitialization(*this, &Call, ToType, @@ -5944,7 +5976,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // Determine the implicit conversion sequences for each of the // arguments. - for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) { + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { if (ArgIdx < NumArgsInProto) { // (C++ 13.3.2p3): for F to be a viable function, there shall // exist for each argument an implicit conversion sequence @@ -5981,7 +6013,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, /// [over.match.oper]). void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet, SourceRange OpRange) { DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); @@ -5996,13 +6028,15 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, // constructed as follows: QualType T1 = Args[0]->getType(); - // -- If T1 is a class type, the set of member candidates is the - // result of the qualified lookup of T1::operator@ - // (13.3.1.1.1); otherwise, the set of member candidates is - // empty. + // -- If T1 is a complete class type or a class currently being + // defined, the set of member candidates is the result of the + // qualified lookup of T1::operator@ (13.3.1.1.1); otherwise, + // the set of member candidates is empty. if (const RecordType *T1Rec = T1->getAs<RecordType>()) { - // Complete the type if it can be completed. Otherwise, we're done. - if (RequireCompleteType(OpLoc, T1, 0)) + // Complete the type if it can be completed. + RequireCompleteType(OpLoc, T1, 0); + // If the type is neither complete nor being defined, bail out now. + if (!T1Rec->getDecl()->getDefinition()) return; LookupResult Operators(*this, OpName, OpLoc, LookupOrdinaryName); @@ -6014,7 +6048,8 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, Oper != OperEnd; ++Oper) AddMethodCandidate(Oper.getPair(), Args[0]->getType(), - Args[0]->Classify(Context), Args + 1, NumArgs - 1, + Args[0]->Classify(Context), + Args.slice(1), CandidateSet, /* SuppressUserConversions = */ false); } @@ -6029,7 +6064,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, /// (at the beginning of the argument list) that will be contextually /// converted to bool. void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet, bool IsAssignmentOperator, unsigned NumContextualBoolArguments) { @@ -6037,20 +6072,20 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); // Add this candidate - OverloadCandidate &Candidate = CandidateSet.addCandidate(NumArgs); + OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size()); Candidate.FoundDecl = DeclAccessPair::make(0, AS_none); Candidate.Function = 0; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.BuiltinTypes.ResultTy = ResultTy; - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) Candidate.BuiltinTypes.ParamTypes[ArgIdx] = ParamTys[ArgIdx]; // Determine the implicit conversion sequences for each of the // arguments. Candidate.Viable = true; - Candidate.ExplicitCallArguments = NumArgs; - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + Candidate.ExplicitCallArguments = Args.size(); + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { // C++ [over.match.oper]p4: // For the built-in assignment operators, conversions of the // left operand are restricted as follows: @@ -6376,15 +6411,14 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, /// given type to the candidate set. static void AddBuiltinAssignmentOperatorCandidates(Sema &S, QualType T, - Expr **Args, - unsigned NumArgs, + ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet) { QualType ParamTypes[2]; // T& operator=(T&, T) ParamTypes[0] = S.Context.getLValueReferenceType(T); ParamTypes[1] = T; - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssignmentOperator=*/true); if (!S.Context.getCanonicalType(T).isVolatileQualified()) { @@ -6392,7 +6426,7 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S, ParamTypes[0] = S.Context.getLValueReferenceType(S.Context.getVolatileType(T)); ParamTypes[1] = T; - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssignmentOperator=*/true); } } @@ -6463,8 +6497,7 @@ namespace { class BuiltinOperatorOverloadBuilder { // Common instance state available to all overload candidate addition methods. Sema &S; - Expr **Args; - unsigned NumArgs; + ArrayRef<Expr *> Args; Qualifiers VisibleTypeConversionsQuals; bool HasArithmeticOrEnumeralCandidateType; SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes; @@ -6587,10 +6620,10 @@ class BuiltinOperatorOverloadBuilder { }; // Non-volatile version. - if (NumArgs == 1) - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + if (Args.size() == 1) + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet); else - S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet); // Use a heuristic to reduce number of builtin candidates in the set: // add volatile version only if there are conversions to a volatile type. @@ -6598,10 +6631,10 @@ class BuiltinOperatorOverloadBuilder { ParamTypes[0] = S.Context.getLValueReferenceType( S.Context.getVolatileType(CandidateTy)); - if (NumArgs == 1) - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + if (Args.size() == 1) + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet); else - S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet); } // Add restrict version only if there are conversions to a restrict type @@ -6611,10 +6644,10 @@ class BuiltinOperatorOverloadBuilder { ParamTypes[0] = S.Context.getLValueReferenceType( S.Context.getCVRQualifiedType(CandidateTy, Qualifiers::Restrict)); - if (NumArgs == 1) - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + if (Args.size() == 1) + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet); else - S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet); if (HasVolatile) { ParamTypes[0] @@ -6622,11 +6655,10 @@ class BuiltinOperatorOverloadBuilder { S.Context.getCVRQualifiedType(CandidateTy, (Qualifiers::Volatile | Qualifiers::Restrict))); - if (NumArgs == 1) - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, - CandidateSet); + if (Args.size() == 1) + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet); else - S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet); } } @@ -6634,12 +6666,12 @@ class BuiltinOperatorOverloadBuilder { public: BuiltinOperatorOverloadBuilder( - Sema &S, Expr **Args, unsigned NumArgs, + Sema &S, ArrayRef<Expr *> Args, Qualifiers VisibleTypeConversionsQuals, bool HasArithmeticOrEnumeralCandidateType, SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes, OverloadCandidateSet &CandidateSet) - : S(S), Args(Args), NumArgs(NumArgs), + : S(S), Args(Args), VisibleTypeConversionsQuals(VisibleTypeConversionsQuals), HasArithmeticOrEnumeralCandidateType( HasArithmeticOrEnumeralCandidateType), @@ -6741,7 +6773,7 @@ public: continue; S.AddBuiltinCandidate(S.Context.getLValueReferenceType(PointeeTy), - &ParamTy, Args, 1, CandidateSet); + &ParamTy, Args, CandidateSet); } } @@ -6758,7 +6790,7 @@ public: for (unsigned Arith = FirstPromotedArithmeticType; Arith < LastPromotedArithmeticType; ++Arith) { QualType ArithTy = getArithmeticType(Arith); - S.AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet); + S.AddBuiltinCandidate(ArithTy, &ArithTy, Args, CandidateSet); } // Extension: We also add these operators for vector types. @@ -6767,7 +6799,7 @@ public: VecEnd = CandidateTypes[0].vector_end(); Vec != VecEnd; ++Vec) { QualType VecTy = *Vec; - S.AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); + S.AddBuiltinCandidate(VecTy, &VecTy, Args, CandidateSet); } } @@ -6782,7 +6814,7 @@ public: PtrEnd = CandidateTypes[0].pointer_end(); Ptr != PtrEnd; ++Ptr) { QualType ParamTy = *Ptr; - S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet); + S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, CandidateSet); } } @@ -6798,7 +6830,7 @@ public: for (unsigned Int = FirstPromotedIntegralType; Int < LastPromotedIntegralType; ++Int) { QualType IntTy = getArithmeticType(Int); - S.AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet); + S.AddBuiltinCandidate(IntTy, &IntTy, Args, CandidateSet); } // Extension: We also add this operator for vector types. @@ -6807,7 +6839,7 @@ public: VecEnd = CandidateTypes[0].vector_end(); Vec != VecEnd; ++Vec) { QualType VecTy = *Vec; - S.AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); + S.AddBuiltinCandidate(VecTy, &VecTy, Args, CandidateSet); } } @@ -6821,7 +6853,7 @@ public: /// Set of (canonical) types that we've already handled. llvm::SmallPtrSet<QualType, 8> AddedTypes; - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { for (BuiltinCandidateTypeSet::iterator MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(), MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end(); @@ -6832,8 +6864,7 @@ public: continue; QualType ParamTypes[2] = { *MemPtr, *MemPtr }; - S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, - CandidateSet); + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet); } } } @@ -6865,7 +6896,7 @@ public: llvm::DenseSet<std::pair<CanQualType, CanQualType> > UserDefinedBinaryOperators; - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { if (CandidateTypes[ArgIdx].enumeration_begin() != CandidateTypes[ArgIdx].enumeration_end()) { for (OverloadCandidateSet::iterator C = CandidateSet.begin(), @@ -6898,7 +6929,7 @@ public: /// Set of (canonical) types that we've already handled. llvm::SmallPtrSet<QualType, 8> AddedTypes; - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes[ArgIdx].pointer_begin(), PtrEnd = CandidateTypes[ArgIdx].pointer_end(); @@ -6908,8 +6939,7 @@ public: continue; QualType ParamTypes[2] = { *Ptr, *Ptr }; - S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, - CandidateSet); + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet); } for (BuiltinCandidateTypeSet::iterator Enum = CandidateTypes[ArgIdx].enumeration_begin(), @@ -6925,17 +6955,16 @@ public: continue; QualType ParamTypes[2] = { *Enum, *Enum }; - S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, - CandidateSet); + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet); } if (CandidateTypes[ArgIdx].hasNullPtrType()) { CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy); if (AddedTypes.insert(NullPtrTy) && - !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy, + !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy, NullPtrTy))) { QualType ParamTypes[2] = { NullPtrTy, NullPtrTy }; - S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet); } } @@ -6980,8 +7009,7 @@ public: if (Arg == 0 || Op == OO_Plus) { // operator+(T*, ptrdiff_t) or operator-(T*, ptrdiff_t) // T* operator+(ptrdiff_t, T*); - S.AddBuiltinCandidate(*Ptr, AsymetricParamTypes, Args, 2, - CandidateSet); + S.AddBuiltinCandidate(*Ptr, AsymetricParamTypes, Args, CandidateSet); } if (Op == OO_Minus) { // ptrdiff_t operator-(T, T); @@ -6990,7 +7018,7 @@ public: QualType ParamTypes[2] = { *Ptr, *Ptr }; S.AddBuiltinCandidate(S.Context.getPointerDiffType(), ParamTypes, - Args, 2, CandidateSet); + Args, CandidateSet); } } } @@ -7038,7 +7066,7 @@ public: QualType Result = isComparison ? S.Context.BoolTy : getUsualArithmeticConversions(Left, Right); - S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + S.AddBuiltinCandidate(Result, LandR, Args, CandidateSet); } } @@ -7061,7 +7089,7 @@ public: Result = *Vec2; } - S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + S.AddBuiltinCandidate(Result, LandR, Args, CandidateSet); } } } @@ -7093,7 +7121,7 @@ public: QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater) ? LandR[0] : getUsualArithmeticConversions(Left, Right); - S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + S.AddBuiltinCandidate(Result, LandR, Args, CandidateSet); } } } @@ -7117,8 +7145,7 @@ public: if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum))) continue; - AddBuiltinAssignmentOperatorCandidates(S, *Enum, Args, 2, - CandidateSet); + AddBuiltinAssignmentOperatorCandidates(S, *Enum, Args, CandidateSet); } for (BuiltinCandidateTypeSet::iterator @@ -7128,8 +7155,7 @@ public: if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr))) continue; - AddBuiltinAssignmentOperatorCandidates(S, *MemPtr, Args, 2, - CandidateSet); + AddBuiltinAssignmentOperatorCandidates(S, *MemPtr, Args, CandidateSet); } } } @@ -7169,7 +7195,7 @@ public: S.Context.getLValueReferenceType(*Ptr), isEqualOp ? *Ptr : S.Context.getPointerDiffType(), }; - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/ isEqualOp); bool NeedVolatile = !(*Ptr).isVolatileQualified() && @@ -7178,7 +7204,7 @@ public: // volatile version ParamTypes[0] = S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr)); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); } @@ -7187,7 +7213,7 @@ public: // restrict version ParamTypes[0] = S.Context.getLValueReferenceType(S.Context.getRestrictType(*Ptr)); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); if (NeedVolatile) { @@ -7197,8 +7223,7 @@ public: S.Context.getCVRQualifiedType(*Ptr, (Qualifiers::Volatile | Qualifiers::Restrict))); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); } } @@ -7219,7 +7244,7 @@ public: }; // non-volatile version - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/true); bool NeedVolatile = !(*Ptr).isVolatileQualified() && @@ -7228,8 +7253,8 @@ public: // volatile version ParamTypes[0] = S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr)); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet, /*IsAssigmentOperator=*/true); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, + /*IsAssigmentOperator=*/true); } if (!(*Ptr).isRestrictQualified() && @@ -7237,8 +7262,8 @@ public: // restrict version ParamTypes[0] = S.Context.getLValueReferenceType(S.Context.getRestrictType(*Ptr)); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet, /*IsAssigmentOperator=*/true); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, + /*IsAssigmentOperator=*/true); if (NeedVolatile) { // volatile restrict version @@ -7247,9 +7272,8 @@ public: S.Context.getCVRQualifiedType(*Ptr, (Qualifiers::Volatile | Qualifiers::Restrict))); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet, /*IsAssigmentOperator=*/true); - + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, + /*IsAssigmentOperator=*/true); } } } @@ -7281,7 +7305,7 @@ public: // Add this built-in operator as a candidate (VQ is empty). ParamTypes[0] = S.Context.getLValueReferenceType(getArithmeticType(Left)); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); // Add this built-in operator as a candidate (VQ is 'volatile'). @@ -7289,8 +7313,7 @@ public: ParamTypes[0] = S.Context.getVolatileType(getArithmeticType(Left)); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); } } @@ -7309,15 +7332,14 @@ public: ParamTypes[1] = *Vec2; // Add this built-in operator as a candidate (VQ is empty). ParamTypes[0] = S.Context.getLValueReferenceType(*Vec1); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); // Add this built-in operator as a candidate (VQ is 'volatile'). if (VisibleTypeConversionsQuals.hasVolatile()) { ParamTypes[0] = S.Context.getVolatileType(*Vec1); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); } } @@ -7349,14 +7371,13 @@ public: // Add this built-in operator as a candidate (VQ is empty). ParamTypes[0] = S.Context.getLValueReferenceType(getArithmeticType(Left)); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet); if (VisibleTypeConversionsQuals.hasVolatile()) { // Add this built-in operator as a candidate (VQ is 'volatile'). ParamTypes[0] = getArithmeticType(Left); ParamTypes[0] = S.Context.getVolatileType(ParamTypes[0]); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet); } } } @@ -7371,13 +7392,13 @@ public: // bool operator||(bool, bool); void addExclaimOverload() { QualType ParamTy = S.Context.BoolTy; - S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet, + S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, CandidateSet, /*IsAssignmentOperator=*/false, /*NumContextualBoolArguments=*/1); } void addAmpAmpOrPipePipeOverload() { QualType ParamTypes[2] = { S.Context.BoolTy, S.Context.BoolTy }; - S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet, /*IsAssignmentOperator=*/false, /*NumContextualBoolArguments=*/2); } @@ -7405,7 +7426,7 @@ public: QualType ResultTy = S.Context.getLValueReferenceType(PointeeType); // T& operator[](T*, ptrdiff_t) - S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, CandidateSet); } for (BuiltinCandidateTypeSet::iterator @@ -7420,7 +7441,7 @@ public: QualType ResultTy = S.Context.getLValueReferenceType(PointeeType); // T& operator[](ptrdiff_t, T*) - S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, CandidateSet); } } @@ -7471,7 +7492,7 @@ public: continue; T = Q1.apply(S.Context, T); QualType ResultTy = S.Context.getLValueReferenceType(T); - S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, CandidateSet); } } } @@ -7499,7 +7520,7 @@ public: continue; QualType ParamTypes[2] = { *Ptr, *Ptr }; - S.AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(*Ptr, ParamTypes, Args, CandidateSet); } for (BuiltinCandidateTypeSet::iterator @@ -7510,7 +7531,7 @@ public: continue; QualType ParamTypes[2] = { *MemPtr, *MemPtr }; - S.AddBuiltinCandidate(*MemPtr, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(*MemPtr, ParamTypes, Args, CandidateSet); } if (S.getLangOpts().CPlusPlus11) { @@ -7525,7 +7546,7 @@ public: continue; QualType ParamTypes[2] = { *Enum, *Enum }; - S.AddBuiltinCandidate(*Enum, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(*Enum, ParamTypes, Args, CandidateSet); } } } @@ -7542,7 +7563,7 @@ public: void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, - Expr **Args, unsigned NumArgs, + llvm::ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet) { // Find all of the types that the arguments can convert to, but only // if the operator we're looking at has built-in operator candidates @@ -7550,13 +7571,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // candidate types or either arithmetic or enumeral candidate types. Qualifiers VisibleTypeConversionsQuals; VisibleTypeConversionsQuals.addConst(); - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]); bool HasNonRecordCandidateType = false; bool HasArithmeticOrEnumeralCandidateType = false; SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes; - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { CandidateTypes.push_back(BuiltinCandidateTypeSet(*this)); CandidateTypes[ArgIdx].AddTypesConvertedFrom(Args[ArgIdx]->getType(), OpLoc, @@ -7577,12 +7598,12 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // // We can't exit early for !, ||, or &&, since there we have always have // 'bool' overloads. - if (!HasNonRecordCandidateType && + if (!HasNonRecordCandidateType && !(Op == OO_Exclaim || Op == OO_AmpAmp || Op == OO_PipePipe)) return; // Setup an object to manage the common state for building overloads. - BuiltinOperatorOverloadBuilder OpBuilder(*this, Args, NumArgs, + BuiltinOperatorOverloadBuilder OpBuilder(*this, Args, VisibleTypeConversionsQuals, HasArithmeticOrEnumeralCandidateType, CandidateTypes, CandidateSet); @@ -7609,12 +7630,12 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, break; case OO_Plus: // '+' is either unary or binary - if (NumArgs == 1) + if (Args.size() == 1) OpBuilder.addUnaryPlusPointerOverloads(); // Fall through. case OO_Minus: // '-' is either unary or binary - if (NumArgs == 1) { + if (Args.size() == 1) { OpBuilder.addUnaryPlusOrMinusArithmeticOverloads(); } else { OpBuilder.addBinaryPlusOrMinusPointerOverloads(Op); @@ -7623,7 +7644,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, break; case OO_Star: // '*' is either unary or binary - if (NumArgs == 1) + if (Args.size() == 1) OpBuilder.addUnaryStarPointerOverloads(); else OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false); @@ -7661,7 +7682,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, break; case OO_Amp: // '&' is either unary or binary - if (NumArgs == 1) + if (Args.size() == 1) // C++ [over.match.oper]p3: // -- For the operator ',', the unary operator '&', or the // operator '->', the built-in candidates set is empty. @@ -8489,13 +8510,35 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, return; } - case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_NonDeducedMismatch: { // FIXME: Provide a source location to indicate what we couldn't match. + TemplateArgument FirstTA = *Cand->DeductionFailure.getFirstArg(); + TemplateArgument SecondTA = *Cand->DeductionFailure.getSecondArg(); + if (FirstTA.getKind() == TemplateArgument::Template && + SecondTA.getKind() == TemplateArgument::Template) { + TemplateName FirstTN = FirstTA.getAsTemplate(); + TemplateName SecondTN = SecondTA.getAsTemplate(); + if (FirstTN.getKind() == TemplateName::Template && + SecondTN.getKind() == TemplateName::Template) { + if (FirstTN.getAsTemplateDecl()->getName() == + SecondTN.getAsTemplateDecl()->getName()) { + // FIXME: This fixes a bad diagnostic where both templates are named + // the same. This particular case is a bit difficult since: + // 1) It is passed as a string to the diagnostic printer. + // 2) The diagnostic printer only attempts to find a better + // name for types, not decls. + // Ideally, this should folded into the diagnostic printer. + S.Diag(Fn->getLocation(), + diag::note_ovl_candidate_non_deduced_mismatch_qualified) + << FirstTN.getAsTemplateDecl() << SecondTN.getAsTemplateDecl(); + return; + } + } + } S.Diag(Fn->getLocation(), diag::note_ovl_candidate_non_deduced_mismatch) - << *Cand->DeductionFailure.getFirstArg() - << *Cand->DeductionFailure.getSecondArg(); + << FirstTA << SecondTA; return; - + } // TODO: diagnose these individually, then kill off // note_ovl_candidate_bad_deduction, which is uselessly vague. case Sema::TDK_MiscellaneousDeductionFailure: @@ -9090,17 +9133,19 @@ private: = S.DeduceTemplateArguments(FunctionTemplate, &OvlExplicitTemplateArgs, TargetFunctionType, Specialization, - Info)) { + Info, /*InOverloadResolution=*/true)) { // FIXME: make a note of the failed deduction for diagnostics. (void)Result; return false; } - // Template argument deduction ensures that we have an exact match. + // Template argument deduction ensures that we have an exact match or + // compatible pointer-to-function arguments that would be adjusted by ICS. // This function template specicalization works. Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl()); - assert(TargetFunctionType - == Context.getCanonicalType(Specialization->getType())); + assert(S.isSameOrCompatibleFunctionType( + Context.getCanonicalType(Specialization->getType()), + Context.getCanonicalType(TargetFunctionType))); Matches.push_back(std::make_pair(CurAccessFunPair, Specialization)); return true; } @@ -9122,6 +9167,13 @@ private: if (S.CheckCUDATarget(Caller, FunDecl)) return false; + // If any candidate has a placeholder return type, trigger its deduction + // now. + if (S.getLangOpts().CPlusPlus1y && + FunDecl->getResultType()->isUndeducedType() && + S.DeduceReturnType(FunDecl, SourceExpr->getLocStart(), Complain)) + return false; + QualType ResultTy; if (Context.hasSameUnqualifiedType(TargetFunctionType, FunDecl->getType()) || @@ -9365,7 +9417,8 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, TemplateDeductionInfo Info(ovl->getNameLoc()); if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs, - Specialization, Info)) { + Specialization, Info, + /*InOverloadResolution=*/true)) { // FIXME: make a note of the failed deduction for diagnostics. (void)Result; continue; @@ -9387,6 +9440,11 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, if (FoundResult) *FoundResult = I.getPair(); } + if (Matched && getLangOpts().CPlusPlus1y && + Matched->getResultType()->isUndeducedType() && + DeduceReturnType(Matched, ovl->getExprLoc(), Complain)) + return 0; + return Matched; } @@ -9913,7 +9971,8 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, case OR_Success: { FunctionDecl *FDecl = (*Best)->Function; SemaRef.CheckUnresolvedLookupAccess(ULE, (*Best)->FoundDecl); - SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc()); + if (SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc())) + return ExprError(); Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc, ExecConfig); @@ -10046,6 +10105,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, NumArgs = 2; } + ArrayRef<Expr *> ArgsArray(Args, NumArgs); + if (Input->isTypeDependent()) { if (Fns.empty()) return Owned(new (Context) UnaryOperator(Input, @@ -10060,8 +10121,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, NestedNameSpecifierLoc(), OpNameInfo, /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); - return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, - llvm::makeArrayRef(Args, NumArgs), + return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, ArgsArray, Context.DependentTy, VK_RValue, OpLoc, false)); @@ -10071,20 +10131,18 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, OverloadCandidateSet CandidateSet(OpLoc); // Add the candidates from the given function set. - AddFunctionCandidates(Fns, llvm::makeArrayRef(Args, NumArgs), CandidateSet, - false); + AddFunctionCandidates(Fns, ArgsArray, CandidateSet, false); // Add operator candidates that are member functions. - AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); + AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet); // Add candidates from ADL. - AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, - OpLoc, llvm::makeArrayRef(Args, NumArgs), - /*ExplicitTemplateArgs*/ 0, + AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, OpLoc, + ArgsArray, /*ExplicitTemplateArgs*/ 0, CandidateSet); // Add builtin operator candidates. - AddBuiltinOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); + AddBuiltinOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet); bool HadMultipleCandidates = (CandidateSet.size() > 1); @@ -10135,8 +10193,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, Args[0] = Input; CallExpr *TheCall = - new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(), - llvm::makeArrayRef(Args, NumArgs), + new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(), ArgsArray, ResultTy, VK, OpLoc, false); if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, @@ -10162,8 +10219,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // This is an erroneous use of an operator which can be overloaded by // a non-member function. Check for non-member operators which were // defined too late to be candidates. - if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, - llvm::makeArrayRef(Args, NumArgs))) + if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, ArgsArray)) // FIXME: Recover by calling the found function. return ExprError(); @@ -10176,8 +10232,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, << UnaryOperator::getOpcodeStr(Opc) << Input->getType() << Input->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, - llvm::makeArrayRef(Args, NumArgs), + CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, ArgsArray, UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); @@ -10187,8 +10242,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, << UnaryOperator::getOpcodeStr(Opc) << getDeletedOrUnavailableSuffix(Best->Function) << Input->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, - llvm::makeArrayRef(Args, NumArgs), + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, ArgsArray, UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); } @@ -10296,7 +10350,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, AddFunctionCandidates(Fns, Args, CandidateSet, false); // Add operator candidates that are member functions. - AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); + AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet); // Add candidates from ADL. AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, @@ -10305,7 +10359,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, CandidateSet); // Add builtin operator candidates. - AddBuiltinOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); + AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet); bool HadMultipleCandidates = (CandidateSet.size() > 1); @@ -10526,10 +10580,10 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Subscript can only be overloaded as a member function. // Add operator candidates that are member functions. - AddMemberOperatorCandidates(OO_Subscript, LLoc, Args, 2, CandidateSet); + AddMemberOperatorCandidates(OO_Subscript, LLoc, Args, CandidateSet); // Add builtin operator candidates. - AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, 2, CandidateSet); + AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, CandidateSet); bool HadMultipleCandidates = (CandidateSet.size() > 1); @@ -10796,7 +10850,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Method = cast<CXXMethodDecl>(Best->Function); FoundDecl = Best->FoundDecl; CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl); - DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc()); + if (DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc())) + return ExprError(); break; case OR_No_Viable_Function: @@ -10937,7 +10992,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { AddMethodCandidate(Oper.getPair(), Object.get()->getType(), - Object.get()->Classify(Context), Args, NumArgs, CandidateSet, + Object.get()->Classify(Context), + llvm::makeArrayRef(Args, NumArgs), CandidateSet, /*SuppressUserConversions=*/ false); } @@ -11047,7 +11103,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, Best->Conversions[0].UserDefined.ConversionFunction); CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl); - DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc); + if (DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc)) + return ExprError(); // We selected one of the surrogate functions that converts the // object parameter to a function pointer. Perform the conversion @@ -11229,7 +11286,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context), - 0, 0, CandidateSet, /*SuppressUserConversions=*/false); + None, CandidateSet, /*SuppressUserConversions=*/false); } bool HadMultipleCandidates = (CandidateSet.size() > 1); @@ -11344,7 +11401,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, // Check the argument types. This should almost always be a no-op, except // that array-to-pointer decay is applied to string literals. Expr *ConvArgs[2]; - for (unsigned ArgIdx = 0; ArgIdx != Args.size(); ++ArgIdx) { + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { ExprResult InputInit = PerformCopyInitialization( InitializedEntity::InitializeParameter(Context, FD->getParamDecl(ArgIdx)), SourceLocation(), Args[ArgIdx]); @@ -11401,7 +11458,7 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc, << RangeLoc << BEF << Range->getType(); return FRS_DiagnosticIssued; } - *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(), Loc, 0); + *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, None, Loc, 0); if (CallExpr->isInvalid()) { *CallExpr = ExprError(); Diag(Range->getLocStart(), diag::note_in_for_range) diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index 57706759f3..054d557e92 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -153,6 +153,23 @@ namespace { refExpr->getRBracket()); } }; + + struct MSPropertyRefRebuilder : Rebuilder<MSPropertyRefRebuilder> { + Expr *NewBase; + MSPropertyRefRebuilder(Sema &S, Expr *newBase) + : Rebuilder<MSPropertyRefRebuilder>(S), NewBase(newBase) {} + + typedef MSPropertyRefExpr specific_type; + Expr *rebuildSpecific(MSPropertyRefExpr *refExpr) { + assert(refExpr->getBaseExpr()); + + return new (S.Context) + MSPropertyRefExpr(NewBase, refExpr->getPropertyDecl(), + refExpr->isArrow(), refExpr->getType(), + refExpr->getValueKind(), refExpr->getQualifierLoc(), + refExpr->getMemberLoc()); + } + }; class PseudoOpBuilder { public: @@ -284,6 +301,18 @@ namespace { ExprResult buildSet(Expr *op, SourceLocation, bool); }; + class MSPropertyOpBuilder : public PseudoOpBuilder { + MSPropertyRefExpr *RefExpr; + + public: + MSPropertyOpBuilder(Sema &S, MSPropertyRefExpr *refExpr) : + PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), + RefExpr(refExpr) {} + + Expr *rebuildAndCaptureObject(Expr *); + ExprResult buildGet(); + ExprResult buildSet(Expr *op, SourceLocation, bool); + }; } /// Capture the given expression in an OpaqueValueExpr. @@ -412,7 +441,8 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, QualType resultType = result.get()->getType(); // That's the postfix result. - if (UnaryOperator::isPostfix(opcode) && CanCaptureValueOfType(resultType)) { + if (UnaryOperator::isPostfix(opcode) && + (result.get()->isTypeDependent() || CanCaptureValueOfType(resultType))) { result = capture(result.take()); setResultToLastSemantic(); } @@ -633,12 +663,11 @@ ExprResult ObjCPropertyOpBuilder::buildGet() { assert(InstanceReceiver || RefExpr->isSuperReceiver()); msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType, GenericLoc, Getter->getSelector(), - Getter, MultiExprArg()); + Getter, None); } else { msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(), - GenericLoc, - Getter->getSelector(), Getter, - MultiExprArg()); + GenericLoc, Getter->getSelector(), + Getter, None); } return msg; } @@ -1087,10 +1116,8 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { : S.Context.getObjCIdType(), /*TInfo=*/0, SC_None, - SC_None, 0); - AtIndexGetter->setMethodParams(S.Context, Argument, - ArrayRef<SourceLocation>()); + AtIndexGetter->setMethodParams(S.Context, Argument, None); } if (!AtIndexGetter) { @@ -1202,7 +1229,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { S.Context.getObjCIdType(), /*TInfo=*/0, SC_None, - SC_None, 0); Params.push_back(object); ParmVarDecl *key = ParmVarDecl::Create(S.Context, AtIndexSetter, @@ -1213,10 +1239,9 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { : S.Context.getObjCIdType(), /*TInfo=*/0, SC_None, - SC_None, 0); Params.push_back(key); - AtIndexSetter->setMethodParams(S.Context, Params, ArrayRef<SourceLocation>()); + AtIndexSetter->setMethodParams(S.Context, Params, None); } if (!AtIndexSetter) { @@ -1327,6 +1352,77 @@ ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, } //===----------------------------------------------------------------------===// +// MSVC __declspec(property) references +//===----------------------------------------------------------------------===// + +Expr *MSPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { + Expr *NewBase = capture(RefExpr->getBaseExpr()); + + syntacticBase = + MSPropertyRefRebuilder(S, NewBase).rebuild(syntacticBase); + + return syntacticBase; +} + +ExprResult MSPropertyOpBuilder::buildGet() { + if (!RefExpr->getPropertyDecl()->hasGetter()) { + S.Diag(RefExpr->getMemberLoc(), diag::err_no_getter_for_property) + << RefExpr->getPropertyDecl()->getName(); + return ExprError(); + } + + UnqualifiedId GetterName; + IdentifierInfo *II = RefExpr->getPropertyDecl()->getGetterId(); + GetterName.setIdentifier(II, RefExpr->getMemberLoc()); + CXXScopeSpec SS; + SS.Adopt(RefExpr->getQualifierLoc()); + ExprResult GetterExpr = S.ActOnMemberAccessExpr( + S.getCurScope(), RefExpr->getBaseExpr(), SourceLocation(), + RefExpr->isArrow() ? tok::arrow : tok::period, SS, SourceLocation(), + GetterName, 0, true); + if (GetterExpr.isInvalid()) { + S.Diag(RefExpr->getMemberLoc(), diag::error_cannot_find_suitable_getter) + << RefExpr->getPropertyDecl()->getName(); + return ExprError(); + } + + MultiExprArg ArgExprs; + return S.ActOnCallExpr(S.getCurScope(), GetterExpr.take(), + RefExpr->getSourceRange().getBegin(), ArgExprs, + RefExpr->getSourceRange().getEnd()); +} + +ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl, + bool captureSetValueAsResult) { + if (!RefExpr->getPropertyDecl()->hasSetter()) { + S.Diag(RefExpr->getMemberLoc(), diag::err_no_setter_for_property) + << RefExpr->getPropertyDecl()->getName(); + return ExprError(); + } + + UnqualifiedId SetterName; + IdentifierInfo *II = RefExpr->getPropertyDecl()->getSetterId(); + SetterName.setIdentifier(II, RefExpr->getMemberLoc()); + CXXScopeSpec SS; + SS.Adopt(RefExpr->getQualifierLoc()); + ExprResult SetterExpr = S.ActOnMemberAccessExpr( + S.getCurScope(), RefExpr->getBaseExpr(), SourceLocation(), + RefExpr->isArrow() ? tok::arrow : tok::period, SS, SourceLocation(), + SetterName, 0, true); + if (SetterExpr.isInvalid()) { + S.Diag(RefExpr->getMemberLoc(), diag::error_cannot_find_suitable_setter) + << RefExpr->getPropertyDecl()->getName(); + return ExprError(); + } + + SmallVector<Expr*, 1> ArgExprs; + ArgExprs.push_back(op); + return S.ActOnCallExpr(S.getCurScope(), SetterExpr.take(), + RefExpr->getSourceRange().getBegin(), ArgExprs, + op->getSourceRange().getEnd()); +} + +//===----------------------------------------------------------------------===// // General Sema routines. //===----------------------------------------------------------------------===// @@ -1341,6 +1437,10 @@ ExprResult Sema::checkPseudoObjectRValue(Expr *E) { = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { ObjCSubscriptOpBuilder builder(*this, refExpr); return builder.buildRValueOperation(E); + } else if (MSPropertyRefExpr *refExpr + = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { + MSPropertyOpBuilder builder(*this, refExpr); + return builder.buildRValueOperation(E); } else { llvm_unreachable("unknown pseudo-object kind!"); } @@ -1363,6 +1463,10 @@ ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc, } else if (isa<ObjCSubscriptRefExpr>(opaqueRef)) { Diag(opcLoc, diag::err_illegal_container_subscripting_op); return ExprError(); + } else if (MSPropertyRefExpr *refExpr + = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { + MSPropertyOpBuilder builder(*this, refExpr); + return builder.buildIncDecOperation(Sc, opcLoc, opcode, op); } else { llvm_unreachable("unknown pseudo-object kind!"); } @@ -1392,6 +1496,10 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc, = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { ObjCSubscriptOpBuilder builder(*this, refExpr); return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); + } else if (MSPropertyRefExpr *refExpr + = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { + MSPropertyOpBuilder builder(*this, refExpr); + return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); } else { llvm_unreachable("unknown pseudo-object kind!"); } @@ -1417,6 +1525,10 @@ static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) { OpaqueValueExpr *keyOVE = cast<OpaqueValueExpr>(refExpr->getKeyExpr()); return ObjCSubscriptRefRebuilder(S, baseOVE->getSourceExpr(), keyOVE->getSourceExpr()).rebuild(E); + } else if (MSPropertyRefExpr *refExpr + = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { + OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBaseExpr()); + return MSPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E); } else { llvm_unreachable("unknown pseudo-object kind!"); } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index b5b35fc48b..248665ac86 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -22,7 +22,6 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/TypeLoc.h" -#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" @@ -54,6 +53,11 @@ StmtResult Sema::ActOnExprStmt(ExprResult FE) { } +StmtResult Sema::ActOnExprStmtError() { + DiscardCleanupsInEvaluationContext(); + return StmtError(); +} + StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc, bool HasLeadingEmptyMacro) { return Owned(new (Context) NullStmt(SemiLoc, HasLeadingEmptyMacro)); @@ -72,9 +76,22 @@ StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc, void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { DeclGroupRef DG = dg.getAsVal<DeclGroupRef>(); - // If we have an invalid decl, just return. - if (DG.isNull() || !DG.isSingleDecl()) return; - VarDecl *var = cast<VarDecl>(DG.getSingleDecl()); + // If we don't have a declaration, or we have an invalid declaration, + // just return. + if (DG.isNull() || !DG.isSingleDecl()) + return; + + Decl *decl = DG.getSingleDecl(); + if (!decl || decl->isInvalidDecl()) + return; + + // Only variable declarations are permitted. + VarDecl *var = dyn_cast<VarDecl>(decl); + if (!var) { + Diag(decl->getLocation(), diag::err_non_variable_decl_in_for); + decl->setInvalidDecl(); + return; + } // suppress any potential 'unused variable' warning. var->setUsed(); @@ -350,7 +367,7 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, // Recover from an error by just forgetting about it. } } - + LHSVal = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false, getLangOpts().CPlusPlus11).take(); if (RHSVal) @@ -1421,9 +1438,10 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, VarDecl *VD = dyn_cast<VarDecl>(*DI); if (VD && VD->isLocalVarDecl() && !VD->hasLocalStorage()) VD = 0; - if (VD == 0) - Diag((*DI)->getLocation(), diag::err_non_variable_decl_in_for); - // FIXME: mark decl erroneous! + if (VD == 0) { + Diag((*DI)->getLocation(), diag::err_non_local_variable_decl_in_for); + (*DI)->setInvalidDecl(); + } } } } @@ -1557,14 +1575,41 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, return StmtError(Diag((*DS->decl_begin())->getLocation(), diag::err_toomany_element_decls)); - VarDecl *D = cast<VarDecl>(DS->getSingleDecl()); + VarDecl *D = dyn_cast<VarDecl>(DS->getSingleDecl()); + if (!D || D->isInvalidDecl()) + return StmtError(); + FirstType = D->getType(); // C99 6.8.5p3: The declaration part of a 'for' statement shall only // declare identifiers for objects having storage class 'auto' or // 'register'. if (!D->hasLocalStorage()) return StmtError(Diag(D->getLocation(), - diag::err_non_variable_decl_in_for)); + diag::err_non_local_variable_decl_in_for)); + + // If the type contained 'auto', deduce the 'auto' to 'id'. + if (FirstType->getContainedAutoType()) { + OpaqueValueExpr OpaqueId(D->getLocation(), Context.getObjCIdType(), + VK_RValue); + Expr *DeducedInit = &OpaqueId; + if (DeduceAutoType(D->getTypeSourceInfo(), DeducedInit, FirstType) == + DAR_Failed) + DiagnoseAutoDeductionFailure(D, DeducedInit); + if (FirstType.isNull()) { + D->setInvalidDecl(); + return StmtError(); + } + + D->setType(FirstType); + + if (ActiveTemplateInstantiations.empty()) { + SourceLocation Loc = + D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); + Diag(Loc, diag::warn_auto_var_is_id) + << D->getDeclName(); + } + } + } else { Expr *FirstE = cast<Expr>(First); if (!FirstE->isTypeDependent() && !FirstE->isLValue()) @@ -1596,20 +1641,19 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, /// Finish building a variable declaration for a for-range statement. /// \return true if an error occurs. static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, - SourceLocation Loc, int diag) { + SourceLocation Loc, int DiagID) { // Deduce the type for the iterator variable now rather than leaving it to // AddInitializerToDecl, so we can produce a more suitable diagnostic. - TypeSourceInfo *InitTSI = 0; + QualType InitType; if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) || - SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI) == + SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitType) == Sema::DAR_Failed) - SemaRef.Diag(Loc, diag) << Init->getType(); - if (!InitTSI) { + SemaRef.Diag(Loc, DiagID) << Init->getType(); + if (InitType.isNull()) { Decl->setInvalidDecl(); return true; } - Decl->setTypeSourceInfo(InitTSI); - Decl->setType(InitTSI->getType()); + Decl->setType(InitType); // In ARC, infer lifetime. // FIXME: ARC may want to turn this into 'const __unsafe_unretained' if @@ -1660,7 +1704,7 @@ VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc, IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, - TInfo, SC_Auto, SC_None); + TInfo, SC_None); Decl->setImplicit(); return Decl; } @@ -1874,7 +1918,15 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, StmtResult BeginEndDecl = BeginEnd; ExprResult NotEqExpr = Cond, IncrExpr = Inc; - if (!BeginEndDecl.get() && !RangeVarType->isDependentType()) { + if (RangeVarType->isDependentType()) { + // The range is implicitly used as a placeholder when it is dependent. + RangeVar->setUsed(); + + // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill + // them in properly when we instantiate the loop. + if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) + LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy)); + } else if (!BeginEndDecl.get()) { SourceLocation RangeLoc = RangeVar->getLocation(); const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType(); @@ -1929,6 +1981,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, RangeLoc)); else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(UnqAT)) + // FIXME: Need to build an OpaqueValueExpr for this rather than + // recomputing it! BoundExpr = VAT->getSizeExpr(); else { // Can't be a DependentSizedArrayType or an IncompleteArrayType since @@ -2059,9 +2113,6 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, if (LoopVar->isInvalidDecl()) NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); } - } else { - // The range is implicitly used as a placeholder when it is dependent. - RangeVar->setUsed(); } // Don't bother to actually allocate the result if we're just trying to @@ -2258,7 +2309,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, InitializationKind Kind = InitializationKind::CreateCopy(Value->getLocStart(), Value->getLocStart()); - InitializationSequence Seq(*this, Entity, Kind, &InitExpr, 1); + InitializationSequence Seq(*this, Entity, Kind, InitExpr); // [...] If overload resolution fails, or if the type of the first // parameter of the selected constructor is not an rvalue reference @@ -2291,7 +2342,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, // Complete type-checking the initialization of the return type // using the constructor we found. - Res = Seq.Perform(*this, Entity, Kind, MultiExprArg(&Value, 1)); + Res = Seq.Perform(*this, Entity, Kind, Value); } } } @@ -2354,6 +2405,10 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr); return StmtError(); } + } else if (CapturedRegionScopeInfo *CurRegion = + dyn_cast<CapturedRegionScopeInfo>(CurCap)) { + Diag(ReturnLoc, diag::err_return_in_captured_stmt) << CurRegion->getRegionName(); + return StmtError(); } else { LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CurCap); if (LSI->CallOperator->getType()->getAs<FunctionType>()->getNoReturnAttr()){ @@ -2427,12 +2482,80 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { return Owned(Result); } +/// Deduce the return type for a function from a returned expression, per +/// C++1y [dcl.spec.auto]p6. +bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, + SourceLocation ReturnLoc, + Expr *&RetExpr, + AutoType *AT) { + TypeLoc OrigResultType = FD->getTypeSourceInfo()->getTypeLoc(). + IgnoreParens().castAs<FunctionProtoTypeLoc>().getResultLoc(); + QualType Deduced; + + if (RetExpr) { + // If the deduction is for a return statement and the initializer is + // a braced-init-list, the program is ill-formed. + if (isa<InitListExpr>(RetExpr)) { + Diag(RetExpr->getExprLoc(), diag::err_auto_fn_return_init_list); + return true; + } + + // Otherwise, [...] deduce a value for U using the rules of template + // argument deduction. + DeduceAutoResult DAR = DeduceAutoType(OrigResultType, RetExpr, Deduced); + + if (DAR == DAR_Failed && !FD->isInvalidDecl()) + Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure) + << OrigResultType.getType() << RetExpr->getType(); + + if (DAR != DAR_Succeeded) + return true; + } else { + // In the case of a return with no operand, the initializer is considered + // to be void(). + // + // Deduction here can only succeed if the return type is exactly 'cv auto' + // or 'decltype(auto)', so just check for that case directly. + if (!OrigResultType.getType()->getAs<AutoType>()) { + Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto) + << OrigResultType.getType(); + return true; + } + // We always deduce U = void in this case. + Deduced = SubstAutoType(OrigResultType.getType(), Context.VoidTy); + if (Deduced.isNull()) + return true; + } + + // If a function with a declared return type that contains a placeholder type + // has multiple return statements, the return type is deduced for each return + // statement. [...] if the type deduced is not the same in each deduction, + // the program is ill-formed. + if (AT->isDeduced() && !FD->isInvalidDecl()) { + AutoType *NewAT = Deduced->getContainedAutoType(); + if (!Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) { + Diag(ReturnLoc, diag::err_auto_fn_different_deductions) + << (AT->isDecltypeAuto() ? 1 : 0) + << NewAT->getDeducedType() << AT->getDeducedType(); + return true; + } + } else if (!FD->isInvalidDecl()) { + // Update all declarations of the function to have the deduced return type. + Context.adjustDeducedFunctionResultType(FD, Deduced); + } + + return false; +} + StmtResult Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // Check for unexpanded parameter packs. if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) return StmtError(); + // FIXME: Unify this and C++1y auto function handling. In particular, we + // should allow 'return { 1, 2, 3 };' in a lambda to deduce + // 'std::initializer_list<int>'. if (isa<CapturingScopeInfo>(getCurFunction())) return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp); @@ -2455,6 +2578,23 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } else // If we don't have a function/method context, bail. return StmtError(); + // FIXME: Add a flag to the ScopeInfo to indicate whether we're performing + // deduction. + bool HasDependentReturnType = FnRetType->isDependentType(); + if (getLangOpts().CPlusPlus1y) { + if (AutoType *AT = FnRetType->getContainedAutoType()) { + FunctionDecl *FD = cast<FunctionDecl>(CurContext); + if (CurContext->isDependentContext()) + HasDependentReturnType = true; + else if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { + FD->setInvalidDecl(); + return StmtError(); + } else { + FnRetType = FD->getResultType(); + } + } + } + ReturnStmt *Result = 0; if (FnRetType->isVoidType()) { if (RetValExp) { @@ -2520,7 +2660,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); - } else if (!RetValExp && !FnRetType->isDependentType()) { + } else if (!RetValExp && !HasDependentReturnType) { unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4 // C99 6.8.6.4p1 (ext_ since GCC warns) if (getLangOpts().C99) DiagID = diag::ext_return_missing_expr; @@ -2531,25 +2671,12 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/; Result = new (Context) ReturnStmt(ReturnLoc); } else { - assert(RetValExp || FnRetType->isDependentType()); + assert(RetValExp || HasDependentReturnType); const VarDecl *NRVOCandidate = 0; - if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { + if (!HasDependentReturnType && !RetValExp->isTypeDependent()) { // we have a non-void function with an expression, continue checking - if (!RelatedRetType.isNull()) { - // If we have a related result type, perform an extra conversion here. - // FIXME: The diagnostics here don't really describe what is happening. - InitializedEntity Entity = - InitializedEntity::InitializeTemporary(RelatedRetType); - - ExprResult Res = PerformCopyInitialization(Entity, SourceLocation(), - RetValExp); - if (Res.isInvalid()) { - // FIXME: Cleanup temporaries here, anyway? - return StmtError(); - } - RetValExp = Res.takeAs<Expr>(); - } + QualType RetType = (RelatedRetType.isNull() ? FnRetType : RelatedRetType); // 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 @@ -2559,18 +2686,33 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // the C version of which boils down to CheckSingleAssignmentConstraints. NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, - FnRetType, + RetType, NRVOCandidate != 0); ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, - FnRetType, RetValExp); + RetType, RetValExp); if (Res.isInvalid()) { - // FIXME: Cleanup temporaries here, anyway? + // FIXME: Clean up temporaries here anyway? return StmtError(); } - RetValExp = Res.takeAs<Expr>(); - if (RetValExp) - CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + + // If we have a related result type, we need to implicitly + // convert back to the formal result type. We can't pretend to + // initialize the result again --- we might end double-retaining + // --- so instead we initialize a notional temporary; this can + // lead to less-than-great diagnostics, but this stage is much + // less likely to fail than the previous stage. + if (!RelatedRetType.isNull()) { + Entity = InitializedEntity::InitializeTemporary(FnRetType); + Res = PerformCopyInitialization(Entity, ReturnLoc, RetValExp); + if (Res.isInvalid()) { + // FIXME: Clean up temporaries here anyway? + return StmtError(); + } + RetValExp = Res.takeAs<Expr>(); + } + + CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } if (RetValExp) { @@ -2863,3 +3005,124 @@ StmtResult Sema::ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, GetNameFromUnqualifiedId(Name), Nested); } + +RecordDecl* +Sema::CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc, + unsigned NumParams) { + DeclContext *DC = CurContext; + while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext())) + DC = DC->getParent(); + + RecordDecl *RD = 0; + if (getLangOpts().CPlusPlus) + RD = CXXRecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/0); + else + RD = RecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/0); + + DC->addDecl(RD); + RD->setImplicit(); + RD->startDefinition(); + + CD = CapturedDecl::Create(Context, CurContext, NumParams); + DC->addDecl(CD); + + // Build the context parameter + assert(NumParams > 0 && "CapturedStmt requires context parameter"); + DC = CapturedDecl::castToDeclContext(CD); + IdentifierInfo *VarName = &Context.Idents.get("__context"); + QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD)); + ImplicitParamDecl *Param + = ImplicitParamDecl::Create(Context, DC, Loc, VarName, ParamType); + DC->addDecl(Param); + + CD->setContextParam(Param); + + return RD; +} + +static void buildCapturedStmtCaptureList( + SmallVectorImpl<CapturedStmt::Capture> &Captures, + SmallVectorImpl<Expr *> &CaptureInits, + ArrayRef<CapturingScopeInfo::Capture> Candidates) { + + typedef ArrayRef<CapturingScopeInfo::Capture>::const_iterator CaptureIter; + for (CaptureIter Cap = Candidates.begin(); Cap != Candidates.end(); ++Cap) { + + if (Cap->isThisCapture()) { + Captures.push_back(CapturedStmt::Capture(Cap->getLocation(), + CapturedStmt::VCK_This)); + CaptureInits.push_back(Cap->getCopyExpr()); + continue; + } + + assert(Cap->isReferenceCapture() && + "non-reference capture not yet implemented"); + + Captures.push_back(CapturedStmt::Capture(Cap->getLocation(), + CapturedStmt::VCK_ByRef, + Cap->getVariable())); + CaptureInits.push_back(Cap->getCopyExpr()); + } +} + +void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, + CapturedRegionKind Kind, + unsigned NumParams) { + CapturedDecl *CD = 0; + RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc, NumParams); + + // Enter the capturing scope for this captured region. + PushCapturedRegionScope(CurScope, CD, RD, Kind); + + if (CurScope) + PushDeclContext(CurScope, CD); + else + CurContext = CD; + + PushExpressionEvaluationContext(PotentiallyEvaluated); +} + +void Sema::ActOnCapturedRegionError() { + DiscardCleanupsInEvaluationContext(); + PopExpressionEvaluationContext(); + + CapturedRegionScopeInfo *RSI = getCurCapturedRegion(); + RecordDecl *Record = RSI->TheRecordDecl; + Record->setInvalidDecl(); + + SmallVector<Decl*, 4> Fields; + for (RecordDecl::field_iterator I = Record->field_begin(), + E = Record->field_end(); I != E; ++I) + Fields.push_back(*I); + ActOnFields(/*Scope=*/0, Record->getLocation(), Record, Fields, + SourceLocation(), SourceLocation(), /*AttributeList=*/0); + + PopDeclContext(); + PopFunctionScopeInfo(); +} + +StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) { + CapturedRegionScopeInfo *RSI = getCurCapturedRegion(); + + SmallVector<CapturedStmt::Capture, 4> Captures; + SmallVector<Expr *, 4> CaptureInits; + buildCapturedStmtCaptureList(Captures, CaptureInits, RSI->Captures); + + CapturedDecl *CD = RSI->TheCapturedDecl; + RecordDecl *RD = RSI->TheRecordDecl; + + CapturedStmt *Res = CapturedStmt::Create(getASTContext(), S, + RSI->CapRegionKind, Captures, + CaptureInits, CD, RD); + + CD->setBody(Res->getCapturedStmt()); + RD->completeDefinition(); + + DiscardCleanupsInEvaluationContext(); + PopExpressionEvaluationContext(); + + PopDeclContext(); + PopFunctionScopeInfo(); + + return Owned(Res); +} diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index 3e9606e467..fce95bebd1 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -22,18 +22,6 @@ #include "clang/Sema/ScopeInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCObjectFileInfo.h" -#include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/MC/MCTargetAsmParser.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" using namespace clang; using namespace sema; @@ -124,11 +112,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, // Check that the output exprs are valid lvalues. Expr *OutputExpr = Exprs[i]; - if (CheckAsmLValue(OutputExpr, *this)) { + if (CheckAsmLValue(OutputExpr, *this)) return StmtError(Diag(OutputExpr->getLocStart(), - diag::err_asm_invalid_lvalue_in_output) - << OutputExpr->getSourceRange()); - } + diag::err_asm_invalid_lvalue_in_output) + << OutputExpr->getSourceRange()); + + if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(), + diag::err_dereference_incomplete_type)) + return StmtError(); OutputConstraintInfos.push_back(Info); } @@ -181,9 +172,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, InputConstraintInfos.push_back(Info); const Type *Ty = Exprs[i]->getType().getTypePtr(); - if (Ty->isDependentType() || Ty->isIncompleteType()) + if (Ty->isDependentType()) continue; + if (!Ty->isVoidType() || !Info.allowsMemory()) + if (RequireCompleteType(InputExpr->getLocStart(), Exprs[i]->getType(), + diag::err_dereference_incomplete_type)) + return StmtError(); + unsigned Size = Context.getTypeSize(Ty); if (!Context.getTargetInfo().validateInputSize(Literal->getString(), Size)) @@ -373,160 +369,60 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, return Owned(NS); } -// getSpelling - Get the spelling of the AsmTok token. -static StringRef getSpelling(Sema &SemaRef, Token AsmTok) { - StringRef Asm; - SmallString<512> TokenBuf; - TokenBuf.resize(512); - bool StringInvalid = false; - Asm = SemaRef.PP.getSpelling(AsmTok, TokenBuf, &StringInvalid); - assert (!StringInvalid && "Expected valid string!"); - return Asm; -} +ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &Id, + InlineAsmIdentifierInfo &Info, + bool IsUnevaluatedContext) { + Info.clear(); -// Build the inline assembly string. Returns true on error. -static bool buildMSAsmString(Sema &SemaRef, - SourceLocation AsmLoc, - ArrayRef<Token> AsmToks, - SmallVectorImpl<unsigned> &TokOffsets, - std::string &AsmString) { - assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); - - SmallString<512> Asm; - for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { - bool isNewAsm = ((i == 0) || - AsmToks[i].isAtStartOfLine() || - AsmToks[i].is(tok::kw_asm)); - if (isNewAsm) { - if (i != 0) - Asm += "\n\t"; - - if (AsmToks[i].is(tok::kw_asm)) { - i++; // Skip __asm - if (i == e) { - SemaRef.Diag(AsmLoc, diag::err_asm_empty); - return true; - } + if (IsUnevaluatedContext) + PushExpressionEvaluationContext(UnevaluatedAbstract, + ReuseLambdaContextDecl); - } - } + ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id, + /*trailing lparen*/ false, + /*is & operand*/ false); - if (i && AsmToks[i].hasLeadingSpace() && !isNewAsm) - Asm += ' '; + if (IsUnevaluatedContext) + PopExpressionEvaluationContext(); - StringRef Spelling = getSpelling(SemaRef, AsmToks[i]); - Asm += Spelling; - TokOffsets.push_back(Asm.size()); - } - AsmString = Asm.str(); - return false; -} + if (!Result.isUsable()) return Result; -namespace { - -class MCAsmParserSemaCallbackImpl : public llvm::MCAsmParserSemaCallback { - Sema &SemaRef; - SourceLocation AsmLoc; - ArrayRef<Token> AsmToks; - ArrayRef<unsigned> TokOffsets; - -public: - MCAsmParserSemaCallbackImpl(Sema &Ref, SourceLocation Loc, - ArrayRef<Token> Toks, - ArrayRef<unsigned> Offsets) - : SemaRef(Ref), AsmLoc(Loc), AsmToks(Toks), TokOffsets(Offsets) { } - ~MCAsmParserSemaCallbackImpl() {} - - void *LookupInlineAsmIdentifier(StringRef Name, void *SrcLoc, - unsigned &Length, unsigned &Size, - unsigned &Type, bool &IsVarDecl){ - SourceLocation Loc = SourceLocation::getFromPtrEncoding(SrcLoc); - - NamedDecl *OpDecl = SemaRef.LookupInlineAsmIdentifier(Name, Loc, Length, - Size, Type, - IsVarDecl); - return static_cast<void *>(OpDecl); - } + Result = CheckPlaceholderExpr(Result.take()); + if (!Result.isUsable()) return Result; - bool LookupInlineAsmField(StringRef Base, StringRef Member, - unsigned &Offset) { - return SemaRef.LookupInlineAsmField(Base, Member, Offset, AsmLoc); - } + QualType T = Result.get()->getType(); - static void MSAsmDiagHandlerCallback(const llvm::SMDiagnostic &D, - void *Context) { - ((MCAsmParserSemaCallbackImpl*)Context)->MSAsmDiagHandler(D); + // For now, reject dependent types. + if (T->isDependentType()) { + Diag(Id.getLocStart(), diag::err_asm_incomplete_type) << T; + return ExprError(); } - void MSAsmDiagHandler(const llvm::SMDiagnostic &D) { - // Compute an offset into the inline asm buffer. - // FIXME: This isn't right if .macro is involved (but hopefully, no - // real-world code does that). - const llvm::SourceMgr &LSM = *D.getSourceMgr(); - const llvm::MemoryBuffer *LBuf = - LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); - unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); - - // Figure out which token that offset points into. - const unsigned *OffsetPtr = - std::lower_bound(TokOffsets.begin(), TokOffsets.end(), Offset); - unsigned TokIndex = OffsetPtr - TokOffsets.begin(); - - // If we come up with an answer which seems sane, use it; otherwise, - // just point at the __asm keyword. - // FIXME: Assert the answer is sane once we handle .macro correctly. - SourceLocation Loc = AsmLoc; - if (TokIndex < AsmToks.size()) { - const Token *Tok = &AsmToks[TokIndex]; - Loc = Tok->getLocation(); - Loc = Loc.getLocWithOffset(Offset - (*OffsetPtr - Tok->getLength())); - } - SemaRef.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage(); - } -}; - -} -NamedDecl *Sema::LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc, - unsigned &Length, unsigned &Size, - unsigned &Type, bool &IsVarDecl) { - Length = 1; - Size = 0; - Type = 0; - IsVarDecl = false; - LookupResult Result(*this, &Context.Idents.get(Name), Loc, - Sema::LookupOrdinaryName); - - if (!LookupName(Result, getCurScope())) { - // If we don't find anything, return null; the AsmParser will assume - // it is a label of some sort. - return 0; + // Any sort of function type is fine. + if (T->isFunctionType()) { + return Result; } - if (!Result.isSingleResult()) { - // FIXME: Diagnose result. - return 0; + // Otherwise, it needs to be a complete type. + if (RequireCompleteExprType(Result.get(), diag::err_asm_incomplete_type)) { + return ExprError(); } - NamedDecl *ND = Result.getFoundDecl(); - if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) { - if (VarDecl *Var = dyn_cast<VarDecl>(ND)) { - Type = Context.getTypeInfo(Var->getType()).first; - QualType Ty = Var->getType(); - if (Ty->isArrayType()) { - const ArrayType *ATy = Context.getAsArrayType(Ty); - Length = Type / Context.getTypeInfo(ATy->getElementType()).first; - Type /= Length; // Type is in terms of a single element. - } - Type /= 8; // Type is in terms of bits, but we want bytes. - Size = Length * Type; - IsVarDecl = true; - } - return ND; + // Compute the type size (and array length if applicable?). + Info.Type = Info.Size = Context.getTypeSizeInChars(T).getQuantity(); + if (T->isArrayType()) { + const ArrayType *ATy = Context.getAsArrayType(T); + Info.Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity(); + Info.Length = Info.Size / Info.Type; } - // FIXME: Handle other kinds of results? (FieldDecl, etc.) - // FIXME: Diagnose if we find something we can't handle, like a typedef. - return 0; + // We can work with the expression as long as it's not an r-value. + if (!Result.get()->isRValue()) + Info.IsVarDecl = true; + + return Result; } bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, @@ -541,13 +437,12 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, if (!BaseResult.isSingleResult()) return true; - NamedDecl *FoundDecl = BaseResult.getFoundDecl(); const RecordType *RT = 0; - if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl)) { + NamedDecl *FoundDecl = BaseResult.getFoundDecl(); + if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl)) RT = VD->getType()->getAs<RecordType>(); - } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(FoundDecl)) { + else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(FoundDecl)) RT = TD->getUnderlyingType()->getAs<RecordType>(); - } if (!RT) return true; @@ -574,124 +469,18 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, } StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, - ArrayRef<Token> AsmToks,SourceLocation EndLoc) { - SmallVector<IdentifierInfo*, 4> Names; - SmallVector<StringRef, 4> ConstraintRefs; - SmallVector<Expr*, 4> Exprs; - SmallVector<StringRef, 4> ClobberRefs; - - llvm::Triple TheTriple = Context.getTargetInfo().getTriple(); - llvm::Triple::ArchType ArchTy = TheTriple.getArch(); - bool UnsupportedArch = ArchTy != llvm::Triple::x86 && - ArchTy != llvm::Triple::x86_64; - if (UnsupportedArch) - Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName(); - - // Empty asm statements don't need to instantiate the AsmParser, etc. - if (UnsupportedArch || AsmToks.empty()) { - StringRef EmptyAsmStr; - MSAsmStmt *NS = - new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true, - /*IsVolatile*/ true, AsmToks, /*NumOutputs*/ 0, - /*NumInputs*/ 0, Names, ConstraintRefs, Exprs, - EmptyAsmStr, ClobberRefs, EndLoc); - return Owned(NS); - } - - std::string AsmString; - SmallVector<unsigned, 8> TokOffsets; - if (buildMSAsmString(*this, AsmLoc, AsmToks, TokOffsets, AsmString)) - return StmtError(); - - // Get the target specific parser. - std::string Error; - const std::string &TT = TheTriple.getTriple(); - const llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error)); - - OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT)); - OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); - OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); - OwningPtr<llvm::MCSubtargetInfo> - STI(TheTarget->createMCSubtargetInfo(TT, "", "")); - - llvm::SourceMgr SrcMgr; - llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); - llvm::MemoryBuffer *Buffer = - llvm::MemoryBuffer::getMemBuffer(AsmString, "<inline asm>"); - - // Tell SrcMgr about this buffer, which is what the parser will pick up. - SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); - - OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx)); - OwningPtr<llvm::MCAsmParser> - Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); - OwningPtr<llvm::MCTargetAsmParser> - TargetParser(TheTarget->createMCAsmParser(*STI, *Parser)); - - // Get the instruction descriptor. - const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); - llvm::MCInstPrinter *IP = - TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI); - - // Change to the Intel dialect. - Parser->setAssemblerDialect(1); - Parser->setTargetParser(*TargetParser.get()); - Parser->setParsingInlineAsm(true); - TargetParser->setParsingInlineAsm(true); - - MCAsmParserSemaCallbackImpl MCAPSI(*this, AsmLoc, AsmToks, TokOffsets); - TargetParser->setSemaCallback(&MCAPSI); - SrcMgr.setDiagHandler(MCAsmParserSemaCallbackImpl::MSAsmDiagHandlerCallback, - &MCAPSI); - - unsigned NumOutputs; - unsigned NumInputs; - std::string AsmStringIR; - SmallVector<std::pair<void *, bool>, 4> OpDecls; - SmallVector<std::string, 4> Constraints; - SmallVector<std::string, 4> Clobbers; - if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, - NumOutputs, NumInputs, OpDecls, Constraints, - Clobbers, MII, IP, MCAPSI)) - return StmtError(); - - // Build the vector of clobber StringRefs. - unsigned NumClobbers = Clobbers.size(); - ClobberRefs.resize(NumClobbers); - for (unsigned i = 0; i != NumClobbers; ++i) - ClobberRefs[i] = StringRef(Clobbers[i]); - - // Recast the void pointers and build the vector of constraint StringRefs. - unsigned NumExprs = NumOutputs + NumInputs; - Names.resize(NumExprs); - ConstraintRefs.resize(NumExprs); - Exprs.resize(NumExprs); - for (unsigned i = 0, e = NumExprs; i != e; ++i) { - NamedDecl *OpDecl = static_cast<NamedDecl *>(OpDecls[i].first); - if (!OpDecl) - return StmtError(); - - DeclarationNameInfo NameInfo(OpDecl->getDeclName(), AsmLoc); - ExprResult OpExpr = BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo, - OpDecl); - if (OpExpr.isInvalid()) - return StmtError(); - - // Need address of variable. - if (OpDecls[i].second) - OpExpr = BuildUnaryOp(getCurScope(), AsmLoc, clang::UO_AddrOf, - OpExpr.take()); - - Names[i] = OpDecl->getIdentifier(); - ConstraintRefs[i] = StringRef(Constraints[i]); - Exprs[i] = OpExpr.take(); - } - - bool IsSimple = NumExprs > 0; + ArrayRef<Token> AsmToks, + StringRef AsmString, + unsigned NumOutputs, unsigned NumInputs, + ArrayRef<StringRef> Constraints, + ArrayRef<StringRef> Clobbers, + ArrayRef<Expr*> Exprs, + SourceLocation EndLoc) { + bool IsSimple = (NumOutputs != 0 || NumInputs != 0); MSAsmStmt *NS = new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, /*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs, - Names, ConstraintRefs, Exprs, AsmStringIR, - ClobberRefs, EndLoc); + Constraints, Exprs, AsmString, + Clobbers, EndLoc); return Owned(NS); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index adf25ce3ae..b9695cc1e1 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3842,8 +3842,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, } // A template argument must have static storage duration. - // FIXME: Ensure this works for thread_local as well as __thread. - if (Var->isThreadSpecified()) { + if (Var->getTLSKind()) { S.Diag(Arg->getLocStart(), diag::err_template_arg_thread_local) << Arg->getSourceRange(); S.Diag(Var->getLocation(), diag::note_template_arg_refers_here); @@ -6057,8 +6056,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, TemplArgs, /*InsertPos=*/0, SpecInfo->getTemplateSpecializationKind(), ExplicitTemplateArgs); - FD->setStorageClass(Specialization->getStorageClass()); - + // The "previous declaration" for this function template specialization is // the prior function template specialization. Previous.clear(); @@ -6462,6 +6460,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Set source locations for keywords. Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); + Specialization->setRBraceLoc(SourceLocation()); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index f3bbe8a0f1..8efc7a0263 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -52,7 +52,11 @@ namespace clang { TDF_SkipNonDependent = 0x08, /// \brief Whether we are performing template argument deduction for /// parameters and arguments in a top-level template argument - TDF_TopLevelParameterTypeList = 0x10 + TDF_TopLevelParameterTypeList = 0x10, + /// \brief Within template argument deduction from overload resolution per + /// C++ [over.over] allow matching function types that are compatible in + /// terms of noreturn and default calling convention adjustments. + TDF_InOverloadResolution = 0x20 }; } @@ -867,6 +871,32 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType, == ParamQs.getCVRQualifiers()); } +/// \brief Compare types for equality with respect to possibly compatible +/// function types (noreturn adjustment, implicit calling conventions). If any +/// of parameter and argument is not a function, just perform type comparison. +/// +/// \param Param the template parameter type. +/// +/// \param Arg the argument type. +bool Sema::isSameOrCompatibleFunctionType(CanQualType Param, + CanQualType Arg) { + const FunctionType *ParamFunction = Param->getAs<FunctionType>(), + *ArgFunction = Arg->getAs<FunctionType>(); + + // Just compare if not functions. + if (!ParamFunction || !ArgFunction) + return Param == Arg; + + // Noreturn adjustment. + QualType AdjustedParam; + if (IsNoReturnConversion(Param, Arg, AdjustedParam)) + return Arg == Context.getCanonicalType(AdjustedParam); + + // FIXME: Compatible calling conventions. + + return Param == Arg; +} + /// \brief Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// @@ -1103,6 +1133,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, return Sema::TDK_Success; // Check the cv-qualifiers on the parameter and argument types. + CanQualType CanParam = S.Context.getCanonicalType(Param); + CanQualType CanArg = S.Context.getCanonicalType(Arg); if (!(TDF & TDF_IgnoreQualifiers)) { if (TDF & TDF_ParamWithReferenceType) { if (hasInconsistentOrSupersetQualifiersOf(Param, Arg)) @@ -1114,14 +1146,25 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // If the parameter type is not dependent, there is nothing to deduce. if (!Param->isDependentType()) { - if (!(TDF & TDF_SkipNonDependent) && Param != Arg) - return Sema::TDK_NonDeducedMismatch; - + if (!(TDF & TDF_SkipNonDependent)) { + bool NonDeduced = (TDF & TDF_InOverloadResolution)? + !S.isSameOrCompatibleFunctionType(CanParam, CanArg) : + Param != Arg; + if (NonDeduced) { + return Sema::TDK_NonDeducedMismatch; + } + } return Sema::TDK_Success; } - } else if (!Param->isDependentType() && - Param.getUnqualifiedType() == Arg.getUnqualifiedType()) { - return Sema::TDK_Success; + } else if (!Param->isDependentType()) { + CanQualType ParamUnqualType = CanParam.getUnqualifiedType(), + ArgUnqualType = CanArg.getUnqualifiedType(); + bool Success = (TDF & TDF_InOverloadResolution)? + S.isSameOrCompatibleFunctionType(ParamUnqualType, + ArgUnqualType) : + ParamUnqualType == ArgUnqualType; + if (Success) + return Sema::TDK_Success; } switch (Param->getTypeClass()) { @@ -2761,21 +2804,25 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, /// Gets the type of a function for template-argument-deducton /// purposes when it's considered as part of an overload set. -static QualType GetTypeOfFunction(ASTContext &Context, - const OverloadExpr::FindResult &R, +static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R, FunctionDecl *Fn) { + // We may need to deduce the return type of the function now. + if (S.getLangOpts().CPlusPlus1y && Fn->getResultType()->isUndeducedType() && + S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/false)) + return QualType(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) if (Method->isInstance()) { // An instance method that's referenced in a form that doesn't // look like a member pointer is just invalid. if (!R.HasFormOfMemberPointer) return QualType(); - return Context.getMemberPointerType(Fn->getType(), - Context.getTypeDeclType(Method->getParent()).getTypePtr()); + return S.Context.getMemberPointerType(Fn->getType(), + S.Context.getTypeDeclType(Method->getParent()).getTypePtr()); } if (!R.IsAddressOfOperand) return Fn->getType(); - return Context.getPointerType(Fn->getType()); + return S.Context.getPointerType(Fn->getType()); } /// Apply the deduction rules for overload sets. @@ -2809,7 +2856,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, // But we can still look for an explicit specialization. if (FunctionDecl *ExplicitSpec = S.ResolveSingleFunctionTemplateSpecialization(Ovl)) - return GetTypeOfFunction(S.Context, R, ExplicitSpec); + return GetTypeOfFunction(S, R, ExplicitSpec); } return QualType(); @@ -2842,7 +2889,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, } FunctionDecl *Fn = cast<FunctionDecl>(D); - QualType ArgType = GetTypeOfFunction(S.Context, R, Fn); + QualType ArgType = GetTypeOfFunction(S, R, Fn); if (ArgType.isNull()) continue; // Function-to-pointer conversion. @@ -3316,7 +3363,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, - TemplateDeductionInfo &Info) { + TemplateDeductionInfo &Info, + bool InOverloadResolution) { if (FunctionTemplate->isInvalidDecl()) return TDK_Invalid; @@ -3347,12 +3395,23 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, Deduced.resize(TemplateParams->size()); + // If the function has a deduced return type, substitute it for a dependent + // type so that we treat it as a non-deduced context in what follows. + bool HasUndeducedReturnType = false; + if (getLangOpts().CPlusPlus1y && InOverloadResolution && + Function->getResultType()->isUndeducedType()) { + FunctionType = SubstAutoType(FunctionType, Context.DependentTy); + HasUndeducedReturnType = true; + } + if (!ArgFunctionType.isNull()) { + unsigned TDF = TDF_TopLevelParameterTypeList; + if (InOverloadResolution) TDF |= TDF_InOverloadResolution; // Deduce template arguments from the function type. if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, - FunctionType, ArgFunctionType, Info, - Deduced, TDF_TopLevelParameterTypeList)) + FunctionType, ArgFunctionType, + Info, Deduced, TDF)) return Result; } @@ -3362,12 +3421,26 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, Specialization, Info)) return Result; - // If the requested function type does not match the actual type of the - // specialization, template argument deduction fails. - if (!ArgFunctionType.isNull() && - !Context.hasSameType(ArgFunctionType, Specialization->getType())) + // If the function has a deduced return type, deduce it now, so we can check + // that the deduced function type matches the requested type. + if (HasUndeducedReturnType && + Specialization->getResultType()->isUndeducedType() && + DeduceReturnType(Specialization, Info.getLocation(), false)) return TDK_MiscellaneousDeductionFailure; + // If the requested function type does not match the actual type of the + // specialization with respect to arguments of compatible pointer to function + // types, template argument deduction fails. + if (!ArgFunctionType.isNull()) { + if (InOverloadResolution && !isSameOrCompatibleFunctionType( + Context.getCanonicalType(Specialization->getType()), + Context.getCanonicalType(ArgFunctionType))) + return TDK_MiscellaneousDeductionFailure; + else if(!InOverloadResolution && + !Context.hasSameType(Specialization->getType(), ArgFunctionType)) + return TDK_MiscellaneousDeductionFailure; + } + return TDK_Success; } @@ -3499,9 +3572,11 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, FunctionDecl *&Specialization, - TemplateDeductionInfo &Info) { + TemplateDeductionInfo &Info, + bool InOverloadResolution) { return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, - QualType(), Specialization, Info); + QualType(), Specialization, Info, + InOverloadResolution); } namespace { @@ -3522,13 +3597,19 @@ namespace { // auto &&lref = lvalue; // must transform into "rvalue reference to T" not "rvalue reference to // auto type deduced as T" in order for [temp.deduct.call]p3 to apply. - if (isa<TemplateTypeParmType>(Replacement)) { + if (!Replacement.isNull() && isa<TemplateTypeParmType>(Replacement)) { QualType Result = Replacement; - TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result); + TemplateTypeParmTypeLoc NewTL = + TLB.push<TemplateTypeParmTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } else { - QualType Result = RebuildAutoType(Replacement); + bool Dependent = + !Replacement.isNull() && Replacement->isDependentType(); + QualType Result = + SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement, + TL.getTypePtr()->isDecltypeAuto(), + Dependent); AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; @@ -3539,69 +3620,63 @@ namespace { // Lambdas never need to be transformed. return E; } - }; - /// Determine whether the specified type (which contains an 'auto' type - /// specifier) is dependent. This is not trivial, because the 'auto' specifier - /// itself claims to be type-dependent. - bool isDependentAutoType(QualType Ty) { - while (1) { - QualType Pointee = Ty->getPointeeType(); - if (!Pointee.isNull()) { - Ty = Pointee; - } else if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()){ - if (MPT->getClass()->isDependentType()) - return true; - Ty = MPT->getPointeeType(); - } else if (const FunctionProtoType *FPT = Ty->getAs<FunctionProtoType>()){ - for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(), - E = FPT->arg_type_end(); - I != E; ++I) - if ((*I)->isDependentType()) - return true; - Ty = FPT->getResultType(); - } else if (Ty->isDependentSizedArrayType()) { - return true; - } else if (const ArrayType *AT = Ty->getAsArrayTypeUnsafe()) { - Ty = AT->getElementType(); - } else if (Ty->getAs<DependentSizedExtVectorType>()) { - return true; - } else if (const VectorType *VT = Ty->getAs<VectorType>()) { - Ty = VT->getElementType(); - } else { - break; - } + QualType Apply(TypeLoc TL) { + // Create some scratch storage for the transformed type locations. + // FIXME: We're just going to throw this information away. Don't build it. + TypeLocBuilder TLB; + TLB.reserve(TL.getFullDataSize()); + return TransformType(TLB, TL); } - assert(Ty->getAs<AutoType>() && "didn't find 'auto' in auto type"); - return false; - } + }; +} + +Sema::DeduceAutoResult +Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result) { + return DeduceAutoType(Type->getTypeLoc(), Init, Result); } -/// \brief Deduce the type for an auto type-specifier (C++0x [dcl.spec.auto]p6) +/// \brief Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6) /// /// \param Type the type pattern using the auto type-specifier. -/// /// \param Init the initializer for the variable whose type is to be deduced. -/// /// \param Result if type deduction was successful, this will be set to the -/// deduced type. This may still contain undeduced autos if the type is -/// dependent. This will be set to null if deduction succeeded, but auto -/// substitution failed; the appropriate diagnostic will already have been -/// produced in that case. +/// deduced type. Sema::DeduceAutoResult -Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, - TypeSourceInfo *&Result) { +Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { if (Init->getType()->isNonOverloadPlaceholderType()) { - ExprResult result = CheckPlaceholderExpr(Init); - if (result.isInvalid()) return DAR_FailedAlreadyDiagnosed; - Init = result.take(); + ExprResult NonPlaceholder = CheckPlaceholderExpr(Init); + if (NonPlaceholder.isInvalid()) + return DAR_FailedAlreadyDiagnosed; + Init = NonPlaceholder.take(); } - if (Init->isTypeDependent() || isDependentAutoType(Type->getType())) { - Result = Type; + if (Init->isTypeDependent() || Type.getType()->isDependentType()) { + Result = SubstituteAutoTransform(*this, Context.DependentTy).Apply(Type); + assert(!Result.isNull() && "substituting DependentTy can't fail"); return DAR_Succeeded; } + // If this is a 'decltype(auto)' specifier, do the decltype dance. + // Since 'decltype(auto)' can only occur at the top of the type, we + // don't need to go digging for it. + if (const AutoType *AT = Type.getType()->getAs<AutoType>()) { + if (AT->isDecltypeAuto()) { + if (isa<InitListExpr>(Init)) { + Diag(Init->getLocStart(), diag::err_decltype_auto_initializer_list); + return DAR_FailedAlreadyDiagnosed; + } + + QualType Deduced = BuildDecltypeType(Init, Init->getLocStart()); + // FIXME: Support a non-canonical deduced type for 'auto'. + Deduced = Context.getCanonicalType(Deduced); + Result = SubstituteAutoTransform(*this, Deduced).Apply(Type); + if (Result.isNull()) + return DAR_FailedAlreadyDiagnosed; + return DAR_Succeeded; + } + } + SourceLocation Loc = Init->getExprLoc(); LocalInstantiationScope InstScope(*this); @@ -3615,10 +3690,9 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, FixedSizeTemplateParameterList<1> TemplateParams(Loc, Loc, &TemplParamPtr, Loc); - TypeSourceInfo *FuncParamInfo = - SubstituteAutoTransform(*this, TemplArg).TransformType(Type); - assert(FuncParamInfo && "substituting template parameter for 'auto' failed"); - QualType FuncParam = FuncParamInfo->getType(); + QualType FuncParam = SubstituteAutoTransform(*this, TemplArg).Apply(Type); + assert(!FuncParam.isNull() && + "substituting template parameter for 'auto' failed"); // Deduce type of TemplParam in Func(Init) SmallVector<DeducedTemplateArgument, 1> Deduced; @@ -3659,21 +3733,27 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, return DAR_FailedAlreadyDiagnosed; } - Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type); + Result = SubstituteAutoTransform(*this, DeducedType).Apply(Type); + if (Result.isNull()) + return DAR_FailedAlreadyDiagnosed; // Check that the deduced argument type is compatible with the original // argument type per C++ [temp.deduct.call]p4. - if (!InitList && Result && - CheckOriginalCallArgDeduction(*this, + if (!InitList && !Result.isNull() && + CheckOriginalCallArgDeduction(*this, Sema::OriginalCallArg(FuncParam,0,InitType), - Result->getType())) { - Result = 0; + Result)) { + Result = QualType(); return DAR_Failed; } return DAR_Succeeded; } +QualType Sema::SubstAutoType(QualType Type, QualType Deduced) { + return SubstituteAutoTransform(*this, Deduced).TransformType(Type); +} + void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) { if (isa<InitListExpr>(Init)) Diag(VDecl->getLocation(), @@ -3685,6 +3765,22 @@ void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) { << Init->getSourceRange(); } +bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, + bool Diagnose) { + assert(FD->getResultType()->isUndeducedType()); + + if (FD->getTemplateInstantiationPattern()) + InstantiateFunctionDefinition(Loc, FD); + + bool StillUndeduced = FD->getResultType()->isUndeducedType(); + if (StillUndeduced && Diagnose && !FD->isInvalidDecl()) { + Diag(Loc, diag::err_auto_fn_used_before_defined) << FD; + Diag(FD->getLocation(), diag::note_callee_decl) << FD; + } + + return StillUndeduced; +} + static void MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, bool OnlyDeduced, @@ -4053,7 +4149,7 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { /// template argument deduction. UnresolvedSetIterator Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, - UnresolvedSetIterator SpecEnd, + UnresolvedSetIterator SpecEnd, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments, SourceLocation Loc, @@ -4110,11 +4206,10 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, } // Diagnose the ambiguity. - if (Complain) + if (Complain) { Diag(Loc, AmbigDiag); - if (Complain) - // FIXME: Can we order the candidates in some sane way? + // FIXME: Can we order the candidates in some sane way? for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) { PartialDiagnostic PD = CandidateDiag; PD << getTemplateArgumentBindingsText( @@ -4125,6 +4220,7 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, TargetType); Diag((*I)->getLocation(), PD); } + } return SpecEnd; } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 255df80d66..7ef04e964d 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1682,8 +1682,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, OldParm->getLocation(), OldParm->getIdentifier(), NewDI->getType(), NewDI, - OldParm->getStorageClass(), - OldParm->getStorageClassAsWritten()); + OldParm->getStorageClass()); if (!NewParm) return 0; @@ -2702,11 +2701,10 @@ void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) { llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; if (Stored.isNull()) Stored = Inst; - else if (Stored.is<Decl *>()) { + else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) + Pack->push_back(Inst); + else assert(Stored.get<Decl *>() == Inst && "Already instantiated this local"); - Stored = Inst; - } else - LocalDecls[D].get<DeclArgumentPack *>()->push_back(Inst); } void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index d7ab7fd842..d1428c51a4 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -338,9 +338,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { D->getInnerLocStart(), D->getLocation(), D->getIdentifier(), DI->getType(), DI, - D->getStorageClass(), - D->getStorageClassAsWritten()); - Var->setThreadSpecified(D->isThreadSpecified()); + D->getStorageClass()); + Var->setTSCSpec(D->getTSCSpec()); Var->setInitStyle(D->getInitStyle()); Var->setCXXForRangeDecl(D->isCXXForRangeDecl()); Var->setConstexpr(D->isConstexpr()); @@ -526,6 +525,53 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { return Field; } +Decl *TemplateDeclInstantiator::VisitMSPropertyDecl(MSPropertyDecl *D) { + bool Invalid = false; + TypeSourceInfo *DI = D->getTypeSourceInfo(); + + if (DI->getType()->isVariablyModifiedType()) { + SemaRef.Diag(D->getLocation(), diag::err_property_is_variably_modified) + << D->getName(); + Invalid = true; + } else if (DI->getType()->isInstantiationDependentType()) { + DI = SemaRef.SubstType(DI, TemplateArgs, + D->getLocation(), D->getDeclName()); + if (!DI) { + DI = D->getTypeSourceInfo(); + Invalid = true; + } else if (DI->getType()->isFunctionType()) { + // C++ [temp.arg.type]p3: + // If a declaration acquires a function type through a type + // dependent on a template-parameter and this causes a + // declaration that does not use the syntactic form of a + // function declarator to have function type, the program is + // ill-formed. + SemaRef.Diag(D->getLocation(), diag::err_field_instantiates_to_function) + << DI->getType(); + Invalid = true; + } + } else { + SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType()); + } + + MSPropertyDecl *Property = new (SemaRef.Context) + MSPropertyDecl(Owner, D->getLocation(), + D->getDeclName(), DI->getType(), DI, + D->getLocStart(), + D->getGetterId(), D->getSetterId()); + + SemaRef.InstantiateAttrs(TemplateArgs, D, Property, LateAttrs, + StartingScope); + + if (Invalid) + Property->setInvalidDecl(); + + Property->setAccess(D->getAccess()); + Owner->addDecl(Property); + + return Property; +} + Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) { NamedDecl **NamedChain = new (SemaRef.Context)NamedDecl*[D->getChainingSize()]; @@ -755,7 +801,7 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition( // FIXME: Fixup LBraceLoc SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), Enum->getRBraceLoc(), Enum, - Enumerators.data(), Enumerators.size(), + Enumerators, 0, 0); } @@ -1106,12 +1152,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // this declaration. FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); if (FunctionTemplate && !TemplateParams) { - std::pair<const TemplateArgument *, unsigned> Innermost - = TemplateArgs.getInnermost(); + ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost(); void *InsertPos = 0; FunctionDecl *SpecFunc - = FunctionTemplate->findSpecialization(Innermost.first, Innermost.second, + = FunctionTemplate->findSpecialization(Innermost.begin(), Innermost.size(), InsertPos); // If we already have a function template specialization, return it. @@ -1163,7 +1208,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), D->getNameInfo(), T, TInfo, - D->getStorageClass(), D->getStorageClassAsWritten(), + D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(), D->hasWrittenPrototype(), D->isConstexpr()); @@ -1236,12 +1281,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } } else if (FunctionTemplate) { // Record this function template specialization. - std::pair<const TemplateArgument *, unsigned> Innermost - = TemplateArgs.getInnermost(); + ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost(); Function->setFunctionTemplateSpecialization(FunctionTemplate, TemplateArgumentList::CreateCopy(SemaRef.Context, - Innermost.first, - Innermost.second), + Innermost.begin(), + Innermost.size()), /*InsertPos=*/0); } else if (isFriend) { // Note, we need this connection even if the friend doesn't have a body. @@ -1414,12 +1458,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // We are creating a function template specialization from a function // template. Check whether there is already a function template // specialization for this particular set of template arguments. - std::pair<const TemplateArgument *, unsigned> Innermost - = TemplateArgs.getInnermost(); + ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost(); void *InsertPos = 0; FunctionDecl *SpecFunc - = FunctionTemplate->findSpecialization(Innermost.first, Innermost.second, + = FunctionTemplate->findSpecialization(Innermost.begin(), + Innermost.size(), InsertPos); // If we already have a function template specialization, return it. @@ -1514,6 +1558,36 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Constructor->isExplicit(), Constructor->isInlineSpecified(), false, Constructor->isConstexpr()); + + // Claim that the instantiation of a constructor or constructor template + // inherits the same constructor that the template does. + if (CXXConstructorDecl *Inh = const_cast<CXXConstructorDecl *>( + Constructor->getInheritedConstructor())) { + // If we're instantiating a specialization of a function template, our + // "inherited constructor" will actually itself be a function template. + // Instantiate a declaration of it, too. + if (FunctionTemplate) { + assert(!TemplateParams && Inh->getDescribedFunctionTemplate() && + !Inh->getParent()->isDependentContext() && + "inheriting constructor template in dependent context?"); + Sema::InstantiatingTemplate Inst(SemaRef, Constructor->getLocation(), + Inh); + if (Inst) + return 0; + Sema::ContextRAII SavedContext(SemaRef, Inh->getDeclContext()); + LocalInstantiationScope LocalScope(SemaRef); + + // Use the same template arguments that we deduced for the inheriting + // constructor. There's no way they could be deduced differently. + MultiLevelTemplateArgumentList InheritedArgs; + InheritedArgs.addOuterTemplateArguments(TemplateArgs.getInnermost()); + Inh = cast_or_null<CXXConstructorDecl>( + SemaRef.SubstDecl(Inh, Inh->getDeclContext(), InheritedArgs)); + if (!Inh) + return 0; + } + cast<CXXConstructorDecl>(Method)->setInheritedConstructor(Inh); + } } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -1527,11 +1601,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Conversion->isConstexpr(), Conversion->getLocEnd()); } else { + StorageClass SC = D->isStatic() ? SC_Static : SC_None; Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, - D->isStatic(), - D->getStorageClassAsWritten(), - D->isInlineSpecified(), + SC, D->isInlineSpecified(), D->isConstexpr(), D->getLocEnd()); } @@ -1567,12 +1640,11 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setDescribedFunctionTemplate(FunctionTemplate); } else if (FunctionTemplate) { // Record this function template specialization. - std::pair<const TemplateArgument *, unsigned> Innermost - = TemplateArgs.getInnermost(); + ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost(); Method->setFunctionTemplateSpecialization(FunctionTemplate, TemplateArgumentList::CreateCopy(SemaRef.Context, - Innermost.first, - Innermost.second), + Innermost.begin(), + Innermost.size()), /*InsertPos=*/0); } else if (!isFriend) { // Record that this is an instantiation of a member function. @@ -2183,6 +2255,23 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( return NewFD; } +Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( + OMPThreadPrivateDecl *D) { + SmallVector<DeclRefExpr *, 5> Vars; + for (ArrayRef<DeclRefExpr *>::iterator I = D->varlist_begin(), + E = D->varlist_end(); + I != E; ++I) { + Expr *Var = SemaRef.SubstExpr(*I, TemplateArgs).take(); + assert(isa<DeclRefExpr>(Var) && "threadprivate arg is not a DeclRefExpr"); + Vars.push_back(cast<DeclRefExpr>(Var)); + } + + OMPThreadPrivateDecl *TD = + SemaRef.CheckOMPThreadPrivateDecl(D->getLocation(), Vars); + + return TD; +} + Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs) { TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs); @@ -2673,15 +2762,16 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *ExceptionSpecTemplate = Tmpl; if (EPI.ExceptionSpecType == EST_Uninstantiated) ExceptionSpecTemplate = EPI.ExceptionSpecTemplate; - assert(EPI.ExceptionSpecType != EST_Unevaluated && - "instantiating implicitly-declared special member"); + ExceptionSpecificationType NewEST = EST_Uninstantiated; + if (EPI.ExceptionSpecType == EST_Unevaluated) + NewEST = EST_Unevaluated; // Mark the function has having an uninstantiated exception specification. const FunctionProtoType *NewProto = New->getType()->getAs<FunctionProtoType>(); assert(NewProto && "Template instantiation without function prototype?"); EPI = NewProto->getExtProtoInfo(); - EPI.ExceptionSpecType = EST_Uninstantiated; + EPI.ExceptionSpecType = NewEST; EPI.ExceptionSpecDecl = New; EPI.ExceptionSpecTemplate = ExceptionSpecTemplate; New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(), @@ -2718,7 +2808,6 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, if (Tmpl->isVirtualAsWritten()) New->setVirtualAsWritten(true); - // FIXME: attributes // FIXME: New needs a pointer to Tmpl return false; } @@ -2805,13 +2894,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, return; } - // C++0x [temp.explicit]p9: - // Except for inline functions, other explicit instantiation declarations - // have the effect of suppressing the implicit instantiation of the entity - // to which they refer. + // C++1y [temp.explicit]p10: + // Except for inline functions, declarations with types deduced from their + // initializer or return value, and class template specializations, other + // explicit instantiation declarations have the effect of suppressing the + // implicit instantiation of the entity to which they refer. if (Function->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDeclaration && - !PatternDecl->isInlined()) + !PatternDecl->isInlined() && + !PatternDecl->getResultType()->isUndeducedType()) return; if (PatternDecl->isInlined()) diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index c0ad2be6d4..db885aeec7 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -727,6 +727,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_interface: case TST_class: case TST_auto: + case TST_decltype_auto: case TST_unknown_anytype: case TST_image1d_t: case TST_image1d_array_t: diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index e9ccbecaba..0959f7d66a 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -31,6 +31,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Template.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -792,9 +793,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // "At least one type specifier shall be given in the declaration // specifiers in each declaration, and in the specifier-qualifier list in // each struct declaration and type name." - // FIXME: Does Microsoft really have the implicit int extension in C++? - if (S.getLangOpts().CPlusPlus && - !S.getLangOpts().MicrosoftExt) { + if (S.getLangOpts().CPlusPlus) { S.Diag(DeclLoc, diag::err_missing_type_specifier) << DS.getSourceRange(); @@ -993,11 +992,14 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; - case DeclSpec::TST_auto: { + case DeclSpec::TST_auto: // TypeQuals handled by caller. - Result = Context.getAutoType(QualType()); + Result = Context.getAutoType(QualType(), /*decltype(auto)*/false); + break; + + case DeclSpec::TST_decltype_auto: + Result = Context.getAutoType(QualType(), /*decltype(auto)*/true); break; - } case DeclSpec::TST_unknown_anytype: Result = Context.UnknownAnyTy; @@ -1085,52 +1087,22 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // Apply const/volatile/restrict qualifiers to T. 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." C++ also allows - // restrict-qualified references. - if (TypeQuals & DeclSpec::TQ_restrict) { - if (Result->isAnyPointerType() || Result->isReferenceType()) { - QualType EltTy; - if (Result->isObjCObjectPointerType()) - EltTy = Result; - else - EltTy = Result->isPointerType() ? - Result->getAs<PointerType>()->getPointeeType() : - Result->getAs<ReferenceType>()->getPointeeType(); - - // If we have a pointer or reference, the pointee must have an object - // incomplete type. - if (!EltTy->isIncompleteOrObjectType()) { - S.Diag(DS.getRestrictSpecLoc(), - diag::err_typecheck_invalid_restrict_invalid_pointee) - << EltTy << DS.getSourceRange(); - TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. - } - } else { - S.Diag(DS.getRestrictSpecLoc(), - diag::err_typecheck_invalid_restrict_not_pointer) - << Result << DS.getSourceRange(); - TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. - } - } - // Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification // of a function type includes any type qualifiers, the behavior is // undefined." if (Result->isFunctionType() && TypeQuals) { - // Get some location to point at, either the C or V location. - SourceLocation Loc; if (TypeQuals & DeclSpec::TQ_const) - Loc = DS.getConstSpecLoc(); + S.Diag(DS.getConstSpecLoc(), diag::warn_typecheck_function_qualifiers) + << Result << DS.getSourceRange(); else if (TypeQuals & DeclSpec::TQ_volatile) - Loc = DS.getVolatileSpecLoc(); + S.Diag(DS.getVolatileSpecLoc(), diag::warn_typecheck_function_qualifiers) + << Result << DS.getSourceRange(); else { - assert((TypeQuals & DeclSpec::TQ_restrict) && - "Has CVR quals but not C, V, or R?"); - Loc = DS.getRestrictSpecLoc(); + assert((TypeQuals & (DeclSpec::TQ_restrict | DeclSpec::TQ_atomic)) && + "Has CVRA quals but not C, V, R, or A?"); + // No diagnostic; we'll diagnose 'restrict' or '_Atomic' applied to a + // function type later, in BuildQualifiedType. } - S.Diag(Loc, diag::warn_typecheck_function_qualifiers) - << Result << DS.getSourceRange(); } // C++ [dcl.ref]p1: @@ -1143,6 +1115,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { TypeQuals && Result->isReferenceType()) { TypeQuals &= ~DeclSpec::TQ_const; TypeQuals &= ~DeclSpec::TQ_volatile; + TypeQuals &= ~DeclSpec::TQ_atomic; } // C90 6.5.3 constraints: "The same type qualifier shall not appear more @@ -1160,12 +1133,17 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { << "volatile"; } - // C90 doesn't have restrict, so it doesn't force us to produce a warning - // in this case. + // C90 doesn't have restrict nor _Atomic, so it doesn't force us to + // produce a warning in this case. } - Qualifiers Quals = Qualifiers::fromCVRMask(TypeQuals); - Result = Context.getQualifiedType(Result, Quals); + QualType Qualified = S.BuildQualifiedType(Result, DeclLoc, TypeQuals, &DS); + + // If adding qualifiers fails, just use the unqualified type. + if (Qualified.isNull()) + declarator.setInvalidType(true); + else + Result = Qualified; } return Result; @@ -1179,37 +1157,36 @@ static std::string getPrintableNameForEntity(DeclarationName Entity) { } QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, - Qualifiers Qs) { + Qualifiers Qs, const DeclSpec *DS) { // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." if (Qs.hasRestrict()) { unsigned DiagID = 0; QualType ProblemTy; - const Type *Ty = T->getCanonicalTypeInternal().getTypePtr(); - if (const ReferenceType *RTy = dyn_cast<ReferenceType>(Ty)) { - if (!RTy->getPointeeType()->isIncompleteOrObjectType()) { - DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee; - ProblemTy = T->getAs<ReferenceType>()->getPointeeType(); - } - } else if (const PointerType *PTy = dyn_cast<PointerType>(Ty)) { - if (!PTy->getPointeeType()->isIncompleteOrObjectType()) { - DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee; - ProblemTy = T->getAs<PointerType>()->getPointeeType(); - } - } else if (const MemberPointerType *PTy = dyn_cast<MemberPointerType>(Ty)) { - if (!PTy->getPointeeType()->isIncompleteOrObjectType()) { + if (T->isAnyPointerType() || T->isReferenceType() || + T->isMemberPointerType()) { + QualType EltTy; + if (T->isObjCObjectPointerType()) + EltTy = T; + else if (const MemberPointerType *PTy = T->getAs<MemberPointerType>()) + EltTy = PTy->getPointeeType(); + else + EltTy = T->getPointeeType(); + + // If we have a pointer or reference, the pointee must have an object + // incomplete type. + if (!EltTy->isIncompleteOrObjectType()) { DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee; - ProblemTy = T->getAs<PointerType>()->getPointeeType(); + ProblemTy = EltTy; } - } else if (!Ty->isDependentType()) { - // FIXME: this deserves a proper diagnostic - DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee; + } else if (!T->isDependentType()) { + DiagID = diag::err_typecheck_invalid_restrict_not_pointer; ProblemTy = T; } if (DiagID) { - Diag(Loc, DiagID) << ProblemTy; + Diag(DS ? DS->getRestrictSpecLoc() : Loc, DiagID) << ProblemTy; Qs.removeRestrict(); } } @@ -1217,6 +1194,39 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, return Context.getQualifiedType(T, Qs); } +QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, + unsigned CVRA, const DeclSpec *DS) { + // Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic. + unsigned CVR = CVRA & ~DeclSpec::TQ_atomic; + + // C11 6.7.3/5: + // If the same qualifier appears more than once in the same + // specifier-qualifier-list, either directly or via one or more typedefs, + // the behavior is the same as if it appeared only once. + // + // It's not specified what happens when the _Atomic qualifier is applied to + // a type specified with the _Atomic specifier, but we assume that this + // should be treated as if the _Atomic qualifier appeared multiple times. + if (CVRA & DeclSpec::TQ_atomic && !T->isAtomicType()) { + // C11 6.7.3/5: + // If other qualifiers appear along with the _Atomic qualifier in a + // specifier-qualifier-list, the resulting type is the so-qualified + // atomic type. + // + // Don't need to worry about array types here, since _Atomic can't be + // applied to such types. + SplitQualType Split = T.getSplitUnqualifiedType(); + T = BuildAtomicType(QualType(Split.Ty, 0), + DS ? DS->getAtomicSpecLoc() : Loc); + if (T.isNull()) + return T; + Split.Quals.addCVRQualifiers(CVR); + return BuildQualifiedType(T, Loc, Split.Quals); + } + + return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR), DS); +} + /// \brief Build a paren type including \p T. QualType Sema::BuildParenType(QualType T) { return Context.getParenType(T); @@ -1448,12 +1458,6 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return QualType(); } - if (T->getContainedAutoType()) { - Diag(Loc, diag::err_illegal_decl_array_of_auto) - << getPrintableNameForEntity(Entity) << T; - return QualType(); - } - if (const RecordType *EltTy = T->getAs<RecordType>()) { // If the element type is a struct or union that contains a variadic // array, accept it as a GNU extension: C99 6.7.2.1p2. @@ -1563,6 +1567,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, if (!getLangOpts().C99) { if (T->isVariableArrayType()) { // Prohibit the use of non-POD types in VLAs. + // FIXME: C++1y allows this. QualType BaseT = Context.getBaseElementType(T); if (!T->isDependentType() && !BaseT.isPODType(Context) && @@ -1578,7 +1583,9 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } // Just extwarn about VLAs. else - Diag(Loc, diag::ext_vla); + Diag(Loc, getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_array_of_runtime_bound + : diag::ext_vla); } else if (ASM != ArrayType::Normal || Quals != 0) Diag(Loc, getLangOpts().CPlusPlus? diag::err_c99_array_usage_cxx @@ -1719,13 +1726,28 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, // according to the class type, which means that we really need a // complete type if possible, which means we need to instantiate templates. // - // For now, just require a complete type, which will instantiate - // templates. This will also error if the type is just forward-declared, - // which is a bug, but it's a bug that saves us from dealing with some - // complexities at the moment. - if (Context.getTargetInfo().getCXXABI().isMicrosoft() && - RequireCompleteType(Loc, Class, diag::err_incomplete_type)) - return QualType(); + // If template instantiation fails or the type is just incomplete, we have to + // add an extra slot to the member pointer. Yes, this does cause problems + // when passing pointers between TUs that disagree about the size. + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + CXXRecordDecl *RD = Class->getAsCXXRecordDecl(); + if (RD && !RD->hasAttr<MSInheritanceAttr>()) { + // Lock in the inheritance model on the first use of a member pointer. + // Otherwise we may disagree about the size at different points in the TU. + // FIXME: MSVC picks a model on the first use that needs to know the size, + // rather than on the first mention of the type, e.g. typedefs. + if (RequireCompleteType(Loc, Class, 0) && !RD->isBeingDefined()) { + // We know it doesn't have an attribute and it's incomplete, so use the + // unspecified inheritance model. If we're in the record body, we can + // figure out the inheritance model. + for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(), + E = RD->redecls_end(); I != E; ++I) { + I->addAttr(::new (Context) UnspecifiedInheritanceAttr( + RD->getSourceRange(), Context)); + } + } + } + } return Context.getMemberPointerType(T, Class.getTypePtr()); } @@ -1872,50 +1894,118 @@ static void inferARCWriteback(TypeProcessingState &state, // TODO: mark whether we did this inference? } -static void DiagnoseIgnoredQualifiers(unsigned Quals, - SourceLocation ConstQualLoc, - SourceLocation VolatileQualLoc, - SourceLocation RestrictQualLoc, - Sema& S) { - std::string QualStr; +static void diagnoseIgnoredQualifiers( + Sema &S, unsigned Quals, + SourceLocation FallbackLoc, + SourceLocation ConstQualLoc = SourceLocation(), + SourceLocation VolatileQualLoc = SourceLocation(), + SourceLocation RestrictQualLoc = SourceLocation(), + SourceLocation AtomicQualLoc = SourceLocation()) { + if (!Quals) + return; + + const SourceManager &SM = S.getSourceManager(); + + struct Qual { + unsigned Mask; + const char *Name; + SourceLocation Loc; + } const QualKinds[4] = { + { DeclSpec::TQ_const, "const", ConstQualLoc }, + { DeclSpec::TQ_volatile, "volatile", VolatileQualLoc }, + { DeclSpec::TQ_restrict, "restrict", RestrictQualLoc }, + { DeclSpec::TQ_atomic, "_Atomic", AtomicQualLoc } + }; + + llvm::SmallString<32> QualStr; unsigned NumQuals = 0; SourceLocation Loc; + FixItHint FixIts[4]; + + // Build a string naming the redundant qualifiers. + for (unsigned I = 0; I != 4; ++I) { + if (Quals & QualKinds[I].Mask) { + if (!QualStr.empty()) QualStr += ' '; + QualStr += QualKinds[I].Name; + + // If we have a location for the qualifier, offer a fixit. + SourceLocation QualLoc = QualKinds[I].Loc; + if (!QualLoc.isInvalid()) { + FixIts[NumQuals] = FixItHint::CreateRemoval(QualLoc); + if (Loc.isInvalid() || SM.isBeforeInTranslationUnit(QualLoc, Loc)) + Loc = QualLoc; + } - FixItHint ConstFixIt; - FixItHint VolatileFixIt; - FixItHint RestrictFixIt; + ++NumQuals; + } + } - const SourceManager &SM = S.getSourceManager(); + S.Diag(Loc.isInvalid() ? FallbackLoc : Loc, diag::warn_qual_return_type) + << QualStr << NumQuals << FixIts[0] << FixIts[1] << FixIts[2] << FixIts[3]; +} + +// Diagnose pointless type qualifiers on the return type of a function. +static void diagnoseIgnoredFunctionQualifiers(Sema &S, QualType RetTy, + Declarator &D, + unsigned FunctionChunkIndex) { + if (D.getTypeObject(FunctionChunkIndex).Fun.hasTrailingReturnType()) { + // FIXME: TypeSourceInfo doesn't preserve location information for + // qualifiers. + diagnoseIgnoredQualifiers(S, RetTy.getLocalCVRQualifiers(), + D.getIdentifierLoc()); + return; + } - // FIXME: The locations here are set kind of arbitrarily. It'd be nicer to - // find a range and grow it to encompass all the qualifiers, regardless of - // the order in which they textually appear. - if (Quals & Qualifiers::Const) { - ConstFixIt = FixItHint::CreateRemoval(ConstQualLoc); - QualStr = "const"; - ++NumQuals; - if (!Loc.isValid() || SM.isBeforeInTranslationUnit(ConstQualLoc, Loc)) - Loc = ConstQualLoc; - } - if (Quals & Qualifiers::Volatile) { - VolatileFixIt = FixItHint::CreateRemoval(VolatileQualLoc); - QualStr += (NumQuals == 0 ? "volatile" : " volatile"); - ++NumQuals; - if (!Loc.isValid() || SM.isBeforeInTranslationUnit(VolatileQualLoc, Loc)) - Loc = VolatileQualLoc; - } - if (Quals & Qualifiers::Restrict) { - RestrictFixIt = FixItHint::CreateRemoval(RestrictQualLoc); - QualStr += (NumQuals == 0 ? "restrict" : " restrict"); - ++NumQuals; - if (!Loc.isValid() || SM.isBeforeInTranslationUnit(RestrictQualLoc, Loc)) - Loc = RestrictQualLoc; - } - - assert(NumQuals > 0 && "No known qualifiers?"); - - S.Diag(Loc, diag::warn_qual_return_type) - << QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt; + for (unsigned OuterChunkIndex = FunctionChunkIndex + 1, + End = D.getNumTypeObjects(); + OuterChunkIndex != End; ++OuterChunkIndex) { + DeclaratorChunk &OuterChunk = D.getTypeObject(OuterChunkIndex); + switch (OuterChunk.Kind) { + case DeclaratorChunk::Paren: + continue; + + case DeclaratorChunk::Pointer: { + DeclaratorChunk::PointerTypeInfo &PTI = OuterChunk.Ptr; + diagnoseIgnoredQualifiers( + S, PTI.TypeQuals, + SourceLocation(), + SourceLocation::getFromRawEncoding(PTI.ConstQualLoc), + SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc), + SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc), + SourceLocation::getFromRawEncoding(PTI.AtomicQualLoc)); + return; + } + + case DeclaratorChunk::Function: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::Array: + case DeclaratorChunk::MemberPointer: + // FIXME: We can't currently provide an accurate source location and a + // fix-it hint for these. + unsigned AtomicQual = RetTy->isAtomicType() ? DeclSpec::TQ_atomic : 0; + diagnoseIgnoredQualifiers(S, RetTy.getCVRQualifiers() | AtomicQual, + D.getIdentifierLoc()); + return; + } + + llvm_unreachable("unknown declarator chunk kind"); + } + + // If the qualifiers come from a conversion function type, don't diagnose + // them -- they're not necessarily redundant, since such a conversion + // operator can be explicitly called as "x.operator const int()". + if (D.getName().getKind() == UnqualifiedId::IK_ConversionFunctionId) + return; + + // Just parens all the way out to the decl specifiers. Diagnose any qualifiers + // which are present there. + diagnoseIgnoredQualifiers(S, D.getDeclSpec().getTypeQualifiers(), + D.getIdentifierLoc(), + D.getDeclSpec().getConstSpecLoc(), + D.getDeclSpec().getVolatileSpecLoc(), + D.getDeclSpec().getRestrictSpecLoc(), + D.getDeclSpec().getAtomicSpecLoc()); } static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, @@ -1928,6 +2018,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, // The TagDecl owned by the DeclSpec. TagDecl *OwnedTagDecl = 0; + bool ContainsPlaceholderType = false; + switch (D.getName().getKind()) { case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_OperatorFunctionId: @@ -1935,6 +2027,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: T = ConvertDeclSpecToType(state); + ContainsPlaceholderType = D.getDeclSpec().containsPlaceholderType(); if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) { OwnedTagDecl = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); @@ -1958,6 +2051,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, // converts to. T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId, &ReturnTypeInfo); + ContainsPlaceholderType = T->getContainedAutoType(); break; } @@ -1968,7 +2062,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, // In C++11, a function declarator using 'auto' must have a trailing return // type (this is checked later) and we can skip this. In other languages // using auto, we need to check regardless. - if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && + if (ContainsPlaceholderType && (!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) { int Error = -1; @@ -2011,10 +2105,15 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, Error = 10; // Type alias break; case Declarator::TrailingReturnContext: - Error = 11; // Function return type + if (!SemaRef.getLangOpts().CPlusPlus1y) + Error = 11; // Function return type + break; + case Declarator::ConversionIdContext: + if (!SemaRef.getLangOpts().CPlusPlus1y) + Error = 12; // conversion-type-id break; case Declarator::TypeNameContext: - Error = 12; // Generic + Error = 13; // Generic break; case Declarator::FileContext: case Declarator::BlockContext: @@ -2050,15 +2149,19 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, } } + SourceRange AutoRange = D.getDeclSpec().getTypeSpecTypeLoc(); + if (D.getName().getKind() == UnqualifiedId::IK_ConversionFunctionId) + AutoRange = D.getName().getSourceRange(); + if (Error != -1) { - SemaRef.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), - diag::err_auto_not_allowed) - << Error; + SemaRef.Diag(AutoRange.getBegin(), diag::err_auto_not_allowed) + << Error << AutoRange; T = SemaRef.Context.IntTy; D.setInvalidType(true); } else - SemaRef.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), - diag::warn_cxx98_compat_auto_type_specifier); + SemaRef.Diag(AutoRange.getBegin(), + diag::warn_cxx98_compat_auto_type_specifier) + << AutoRange; } if (SemaRef.getLangOpts().CPlusPlus && @@ -2090,6 +2193,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, D.setInvalidType(true); break; case Declarator::TypeNameContext: + case Declarator::ConversionIdContext: case Declarator::TemplateParamContext: case Declarator::CXXNewContext: case Declarator::CXXCatchContext: @@ -2209,7 +2313,7 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D, if (!D.isFunctionDeclarator() || D.getFunctionDefinitionKind() != FDK_Declaration || !S.CurContext->isFunctionOrMethod() || - D.getDeclSpec().getStorageClassSpecAsWritten() + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_unspecified) return; @@ -2307,6 +2411,46 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, (T->castAs<FunctionProtoType>()->getTypeQuals() != 0 || T->castAs<FunctionProtoType>()->getRefQualifier() != RQ_None); + // If T is 'decltype(auto)', the only declarators we can have are parens + // and at most one function declarator if this is a function declaration. + if (const AutoType *AT = T->getAs<AutoType>()) { + if (AT->isDecltypeAuto()) { + for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { + unsigned Index = E - I - 1; + DeclaratorChunk &DeclChunk = D.getTypeObject(Index); + unsigned DiagId = diag::err_decltype_auto_compound_type; + unsigned DiagKind = 0; + switch (DeclChunk.Kind) { + case DeclaratorChunk::Paren: + continue; + case DeclaratorChunk::Function: { + unsigned FnIndex; + if (D.isFunctionDeclarationContext() && + D.isFunctionDeclarator(FnIndex) && FnIndex == Index) + continue; + DiagId = diag::err_decltype_auto_function_declarator_not_declaration; + break; + } + case DeclaratorChunk::Pointer: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + DiagKind = 0; + break; + case DeclaratorChunk::Reference: + DiagKind = 1; + break; + case DeclaratorChunk::Array: + DiagKind = 2; + break; + } + + S.Diag(DeclChunk.Loc, DiagId) << DiagKind; + D.setInvalidType(true); + break; + } + } + } + // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). @@ -2435,6 +2579,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } + if (const AutoType *AT = T->getContainedAutoType()) { + // We've already diagnosed this for decltype(auto). + if (!AT->isDecltypeAuto()) + S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto) + << getPrintableNameForEntity(Name) << T; + T = QualType(); + break; + } + T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, SourceRange(DeclType.Loc, DeclType.EndLoc), Name); break; @@ -2452,7 +2605,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // trailing-return-type is only required if we're declaring a function, // and not, for instance, a pointer to a function. if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && - !FTI.hasTrailingReturnType() && chunkIndex == 0) { + !FTI.hasTrailingReturnType() && chunkIndex == 0 && + !S.getLangOpts().CPlusPlus1y) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_missing_trailing_return); T = Context.IntTy; @@ -2465,7 +2619,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); } else if (D.getContext() != Declarator::LambdaExprContext && - (T.hasQualifiers() || !isa<AutoType>(T))) { + (T.hasQualifiers() || !isa<AutoType>(T) || + cast<AutoType>(T)->isDecltypeAuto())) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); @@ -2512,31 +2667,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // cv-qualifiers on return types are pointless except when the type is a // class type in C++. - if (isa<PointerType>(T) && T.getLocalCVRQualifiers() && - (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId) && - (!LangOpts.CPlusPlus || !T->isDependentType())) { - assert(chunkIndex + 1 < e && "No DeclaratorChunk for the return type?"); - DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1); - assert(ReturnTypeChunk.Kind == DeclaratorChunk::Pointer); - - DeclaratorChunk::PointerTypeInfo &PTI = ReturnTypeChunk.Ptr; - - DiagnoseIgnoredQualifiers(PTI.TypeQuals, - SourceLocation::getFromRawEncoding(PTI.ConstQualLoc), - SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc), - SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc), - S); - - } else if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() && - (!LangOpts.CPlusPlus || - (!T->isDependentType() && !T->isRecordType()))) { - - DiagnoseIgnoredQualifiers(D.getDeclSpec().getTypeQualifiers(), - D.getDeclSpec().getConstSpecLoc(), - D.getDeclSpec().getVolatileSpecLoc(), - D.getDeclSpec().getRestrictSpecLoc(), - S); - } + if ((T.getCVRQualifiers() || T->isAtomicType()) && + !(S.getLangOpts().CPlusPlus && + (T->isDependentType() || T->isRecordType()))) + diagnoseIgnoredFunctionQualifiers(S, T, D, chunkIndex); // Objective-C ARC ownership qualifiers are ignored on the function // return type (by type canonicalization). Complain if this attribute @@ -2973,6 +3107,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case Declarator::ObjCCatchContext: case Declarator::BlockLiteralContext: case Declarator::LambdaExprContext: + case Declarator::ConversionIdContext: case Declarator::TrailingReturnContext: case Declarator::TemplateTypeArgContext: // FIXME: We may want to allow parameter packs in block-literal contexts @@ -3339,13 +3474,22 @@ namespace { TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); } void VisitAtomicTypeLoc(AtomicTypeLoc TL) { - TL.setKWLoc(DS.getTypeSpecTypeLoc()); - TL.setParensRange(DS.getTypeofParensRange()); + // An AtomicTypeLoc can come from either an _Atomic(...) type specifier + // or an _Atomic qualifier. + if (DS.getTypeSpecType() == DeclSpec::TST_atomic) { + TL.setKWLoc(DS.getTypeSpecTypeLoc()); + TL.setParensRange(DS.getTypeofParensRange()); - TypeSourceInfo *TInfo = 0; - Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); - assert(TInfo); - TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc()); + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); + assert(TInfo); + TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc()); + } else { + TL.setKWLoc(DS.getAtomicSpecLoc()); + // No parens, to indicate this was spelled as an _Atomic qualifier. + TL.setParensRange(SourceRange()); + Visit(TL.getValueLoc()); + } } void VisitTypeLoc(TypeLoc TL) { @@ -3468,6 +3612,29 @@ namespace { }; } +static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) { + SourceLocation Loc; + switch (Chunk.Kind) { + case DeclaratorChunk::Function: + case DeclaratorChunk::Array: + case DeclaratorChunk::Paren: + llvm_unreachable("cannot be _Atomic qualified"); + + case DeclaratorChunk::Pointer: + Loc = SourceLocation::getFromRawEncoding(Chunk.Ptr.AtomicQualLoc); + break; + + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::MemberPointer: + // FIXME: Provide a source location for the _Atomic keyword. + break; + } + + ATL.setKWLoc(Loc); + ATL.setParensRange(SourceRange()); +} + /// \brief Create and instantiate a TypeSourceInfo with type source information. /// /// \param T QualType referring to the type as written in source code. @@ -3489,6 +3656,13 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + // An AtomicTypeLoc might be produced by an atomic qualifier in this + // declarator chunk. + if (AtomicTypeLoc ATL = CurrTL.getAs<AtomicTypeLoc>()) { + fillAtomicQualLoc(ATL, D.getTypeObject(i)); + CurrTL = ATL.getValueLoc().getUnqualifiedLoc(); + } + while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) { fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs()); CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); @@ -3671,7 +3845,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, QualType &type) { bool NonObjCPointer = false; - if (!type->isDependentType()) { + if (!type->isDependentType() && !type->isUndeducedType()) { if (const PointerType *ptr = type->getAs<PointerType>()) { QualType pointee = ptr->getPointeeType(); if (pointee->isObjCRetainableType() || pointee->isPointerType()) @@ -4696,7 +4870,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, QualType ElemType = Context.getBaseElementType(T); RequireCompleteType(Loc, ElemType, 0); - if (T->isLiteralType()) + if (T->isLiteralType(Context)) return false; if (Diagnoser.Suppressed) @@ -4738,7 +4912,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, } else if (RD->hasNonLiteralTypeFieldsOrBases()) { for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { - if (!I->getType()->isLiteralType()) { + if (!I->getType()->isLiteralType(Context)) { Diag(I->getLocStart(), diag::note_non_literal_base_class) << RD << I->getType() << I->getSourceRange(); @@ -4747,7 +4921,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, } for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I) { - if (!I->getType()->isLiteralType() || + if (!I->getType()->isLiteralType(Context) || I->getType().isVolatileQualified()) { Diag(I->getLocation(), diag::note_non_literal_field) << RD << *I << I->getType() diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 1dde87d2e6..89e23ef460 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -754,17 +754,20 @@ public: UnaryTransformType::UTTKind UKind, SourceLocation Loc); - /// \brief Build a new C++0x decltype type. + /// \brief Build a new C++11 decltype type. /// /// By default, performs semantic analysis when building the decltype type. /// Subclasses may override this routine to provide different behavior. QualType RebuildDecltypeType(Expr *Underlying, SourceLocation Loc); - /// \brief Build a new C++0x auto type. + /// \brief Build a new C++11 auto type. /// /// By default, builds a new AutoType with the given deduced type. - QualType RebuildAutoType(QualType Deduced) { - return SemaRef.Context.getAutoType(Deduced); + QualType RebuildAutoType(QualType Deduced, bool IsDecltypeAuto) { + // Note, IsDependent is always false here: we implicitly convert an 'auto' + // which has been deduced to a dependent type into an undeduced 'auto', so + // that we'll retry deduction after the transformation. + return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto); } /// \brief Build a new template specialization type. @@ -1187,8 +1190,16 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, - ArrayRef<Token> AsmToks, SourceLocation EndLoc) { - return getSema().ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, EndLoc); + ArrayRef<Token> AsmToks, + StringRef AsmString, + unsigned NumOutputs, unsigned NumInputs, + ArrayRef<StringRef> Constraints, + ArrayRef<StringRef> Clobbers, + ArrayRef<Expr*> Exprs, + SourceLocation EndLoc) { + return getSema().ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmString, + NumOutputs, NumInputs, + Constraints, Clobbers, Exprs, EndLoc); } /// \brief Build a new Objective-C \@try statement. @@ -1338,6 +1349,23 @@ public: Expr *Cond, Expr *Inc, Stmt *LoopVar, SourceLocation RParenLoc) { + // If we've just learned that the range is actually an Objective-C + // collection, treat this as an Objective-C fast enumeration loop. + if (DeclStmt *RangeStmt = dyn_cast<DeclStmt>(Range)) { + if (RangeStmt->isSingleDecl()) { + if (VarDecl *RangeVar = dyn_cast<VarDecl>(RangeStmt->getSingleDecl())) { + if (RangeVar->isInvalidDecl()) + return StmtError(); + + Expr *RangeExpr = RangeVar->getInit(); + if (!RangeExpr->isTypeDependent() && + RangeExpr->getType()->isObjCObjectPointerType()) + return getSema().ActOnObjCForCollectionStmt(ForLoc, LoopVar, RangeExpr, + RParenLoc); + } + } + } + return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd, Cond, Inc, LoopVar, RParenLoc, Sema::BFRK_Rebuild); @@ -1966,6 +1994,17 @@ public: Param)); } + /// \brief Build a new C++11 default-initialization expression. + /// + /// By default, builds a new default field initialization expression, which + /// does not require any semantic analysis. Subclasses may override this + /// routine to provide different behavior. + ExprResult RebuildCXXDefaultInitExpr(SourceLocation Loc, + FieldDecl *Field) { + return getSema().Owned(CXXDefaultInitExpr::Create(getSema().Context, Loc, + Field)); + } + /// \brief Build a new C++ zero-initialization expression. /// /// By default, performs semantic analysis to build the new expression. @@ -1974,7 +2013,7 @@ public: SourceLocation LParenLoc, SourceLocation RParenLoc) { return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, - MultiExprArg(), RParenLoc); + None, RParenLoc); } /// \brief Build a new C++ "new" expression. @@ -2389,13 +2428,14 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildObjCIsaExpr(Expr *BaseArg, SourceLocation IsaLoc, + SourceLocation OpLoc, bool IsArrow) { CXXScopeSpec SS; ExprResult Base = getSema().Owned(BaseArg); LookupResult R(getSema(), &getSema().Context.Idents.get("isa"), IsaLoc, Sema::LookupMemberName); ExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow, - /*FIME:*/IsaLoc, + OpLoc, SS, 0, false); if (Result.isInvalid() || Base.isInvalid()) return ExprError(); @@ -2404,7 +2444,7 @@ public: return Result; return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(), - /*FIXME:*/IsaLoc, IsArrow, + OpLoc, IsArrow, SS, SourceLocation(), /*FirstQualifierInScope=*/0, R, @@ -2608,13 +2648,13 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init, // Revert value-initialization back to empty parens. if (CXXScalarValueInitExpr *VIE = dyn_cast<CXXScalarValueInitExpr>(Init)) { SourceRange Parens = VIE->getSourceRange(); - return getDerived().RebuildParenListExpr(Parens.getBegin(), MultiExprArg(), + return getDerived().RebuildParenListExpr(Parens.getBegin(), None, Parens.getEnd()); } // FIXME: We shouldn't build ImplicitValueInitExprs for direct-initialization. if (isa<ImplicitValueInitExpr>(Init)) - return getDerived().RebuildParenListExpr(SourceLocation(), MultiExprArg(), + return getDerived().RebuildParenListExpr(SourceLocation(), None, SourceLocation()); // Revert initialization by constructor back to a parenthesized or braced list @@ -3381,7 +3421,7 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, Qs.removeObjCLifetime(); Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs); - Result = SemaRef.Context.getAutoType(Deduced); + Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto()); TLB.TypeWasModifiedSafely(Result); } else { // Otherwise, complain about the addition of a qualifier to an @@ -3396,7 +3436,9 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, } if (!Quals.empty()) { Result = SemaRef.BuildQualifiedType(Result, T.getBeginLoc(), Quals); - TLB.push<QualifiedTypeLoc>(Result); + // BuildQualifiedType might not add qualifiers if they are invalid. + if (Result.hasLocalQualifiers()) + TLB.push<QualifiedTypeLoc>(Result); // No location information to preserve. } @@ -3991,7 +4033,6 @@ ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam( NewDI->getType(), NewDI, OldParm->getStorageClass(), - OldParm->getStorageClassAsWritten(), /* DefArg */ NULL); newParm->setScopeInfo(OldParm->getFunctionScopeDepth(), OldParm->getFunctionScopeIndex() + indexAdjustment); @@ -4473,8 +4514,9 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB, } QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced) { - Result = getDerived().RebuildAutoType(NewDeduced); + if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || + T->isDependentType()) { + Result = getDerived().RebuildAutoType(NewDeduced, T->isDecltypeAuto()); if (Result.isNull()) return QualType(); } @@ -5615,8 +5657,30 @@ TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) { ArrayRef<Token> AsmToks = llvm::makeArrayRef(S->getAsmToks(), S->getNumAsmToks()); + bool HadError = false, HadChange = false; + + ArrayRef<Expr*> SrcExprs = S->getAllExprs(); + SmallVector<Expr*, 8> TransformedExprs; + TransformedExprs.reserve(SrcExprs.size()); + for (unsigned i = 0, e = SrcExprs.size(); i != e; ++i) { + ExprResult Result = getDerived().TransformExpr(SrcExprs[i]); + if (!Result.isUsable()) { + HadError = true; + } else { + HadChange |= (Result.get() != SrcExprs[i]); + TransformedExprs.push_back(Result.take()); + } + } + + if (HadError) return StmtError(); + if (!HadChange && !getDerived().AlwaysRebuild()) + return Owned(S); + return getDerived().RebuildMSAsmStmt(S->getAsmLoc(), S->getLBraceLoc(), - AsmToks, S->getEndLoc()); + AsmToks, S->getAsmString(), + S->getNumOutputs(), S->getNumInputs(), + S->getAllConstraints(), S->getClobbers(), + TransformedExprs, S->getEndLoc()); } template<typename Derived> @@ -5917,12 +5981,15 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { BeginEnd.get() != S->getBeginEndStmt() || Cond.get() != S->getCond() || Inc.get() != S->getInc() || - LoopVar.get() != S->getLoopVarStmt()) + LoopVar.get() != S->getLoopVarStmt()) { NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), S->getColonLoc(), Range.get(), BeginEnd.get(), Cond.get(), Inc.get(), LoopVar.get(), S->getRParenLoc()); + if (NewStmt.isInvalid()) + return StmtError(); + } StmtResult Body = getDerived().TransformStmt(S->getBody()); if (Body.isInvalid()) @@ -5930,12 +5997,15 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { // Body has changed but we didn't rebuild the for-range statement. Rebuild // it now so we have a new statement to attach the body to. - if (Body.get() != S->getBody() && NewStmt.get() == S) + if (Body.get() != S->getBody() && NewStmt.get() == S) { NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), S->getColonLoc(), Range.get(), BeginEnd.get(), Cond.get(), Inc.get(), LoopVar.get(), S->getRParenLoc()); + if (NewStmt.isInvalid()) + return StmtError(); + } if (NewStmt.get() == S) return SemaRef.Owned(S); @@ -6013,6 +6083,32 @@ TreeTransform<Derived>::TransformMSDependentExistsStmt( } template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformMSPropertyRefExpr(MSPropertyRefExpr *E) { + NestedNameSpecifierLoc QualifierLoc; + if (E->getQualifierLoc()) { + QualifierLoc + = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); + if (!QualifierLoc) + return ExprError(); + } + + MSPropertyDecl *PD = cast_or_null<MSPropertyDecl>( + getDerived().TransformDecl(E->getMemberLoc(), E->getPropertyDecl())); + if (!PD) + return ExprError(); + + ExprResult Base = getDerived().TransformExpr(E->getBaseExpr()); + if (Base.isInvalid()) + return ExprError(); + + return new (SemaRef.getASTContext()) + MSPropertyRefExpr(Base.get(), PD, E->isArrow(), + SemaRef.getASTContext().PseudoObjectTy, VK_LValue, + QualifierLoc, E->getMemberLoc()); +} + +template<typename Derived> StmtResult TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) { StmtResult TryBlock; // = getDerived().TransformCompoundStmt(S->getTryBlock()); @@ -6157,6 +6253,8 @@ TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformUserDefinedLiteral(UserDefinedLiteral *E) { + if (FunctionDecl *FD = E->getDirectCallee()) + SemaRef.MarkFunctionReferenced(E->getLocStart(), FD); return SemaRef.MaybeBindToTemporary(E); } @@ -7218,6 +7316,21 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + FieldDecl *Field + = cast_or_null<FieldDecl>(getDerived().TransformDecl(E->getLocStart(), + E->getField())); + if (!Field) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && Field == E->getField()) + return SemaRef.Owned(E); + + return getDerived().RebuildCXXDefaultInitExpr(E->getExprLoc(), Field); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformCXXScalarValueInitExpr( CXXScalarValueInitExpr *E) { TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo()); @@ -8590,16 +8703,11 @@ TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>:: TransformObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) { - ExprResult result = getDerived().TransformExpr(E->getSubExpr()); - if (result.isInvalid()) return ExprError(); - Expr *subExpr = result.take(); - - if (!getDerived().AlwaysRebuild() && - subExpr == E->getSubExpr()) - return SemaRef.Owned(E); - - return SemaRef.Owned(new(SemaRef.Context) - ObjCIndirectCopyRestoreExpr(subExpr, E->getType(), E->shouldCopy())); + // This is a kind of implicit conversion, and it needs to get dropped + // and recomputed for the same general reasons that ImplicitCastExprs + // do, as well a more specific one: this expression is only valid when + // it appears *immediately* as an argument expression. + return getDerived().TransformExpr(E->getSubExpr()); } template<typename Derived> @@ -8786,6 +8894,7 @@ TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) { return SemaRef.Owned(E); return getDerived().RebuildObjCIsaExpr(Base.get(), E->getIsaMemberLoc(), + E->getOpLoc(), E->isArrow()); } @@ -9337,6 +9446,23 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base, /*TemplateArgs*/ 0); } +template<typename Derived> +StmtResult +TreeTransform<Derived>::TransformCapturedStmt(CapturedStmt *S) { + SourceLocation Loc = S->getLocStart(); + unsigned NumParams = S->getCapturedDecl()->getNumParams(); + getSema().ActOnCapturedRegionStart(Loc, /*CurScope*/0, + S->getCapturedRegionKind(), NumParams); + StmtResult Body = getDerived().TransformStmt(S->getCapturedStmt()); + + if (Body.isInvalid()) { + getSema().ActOnCapturedRegionError(); + return StmtError(); + } + + return getSema().ActOnCapturedRegionEnd(Body.take()); +} + } // end namespace clang #endif // LLVM_CLANG_SEMA_TREETRANSFORM_H diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 3319cc3641..24b268f36d 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -119,6 +119,7 @@ serialization::getDefinitiveDeclContext(const DeclContext *DC) { case Decl::CXXConversion: case Decl::ObjCMethod: case Decl::Block: + case Decl::Captured: // Objective C categories, category implementations, and class // implementations can only be defined in one place. case Decl::ObjCCategory: @@ -180,6 +181,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::UnresolvedUsingValue: case Decl::IndirectField: case Decl::Field: + case Decl::MSProperty: case Decl::ObjCIvar: case Decl::ObjCAtDefsField: case Decl::ImplicitParam: @@ -202,8 +204,10 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::FriendTemplate: case Decl::StaticAssert: case Decl::Block: + case Decl::Captured: case Decl::ClassScopeFunctionSpecialization: case Decl::Import: + case Decl::OMPThreadPrivate: return false; } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 93ae6f1c44..22caeb8656 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -257,7 +257,8 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, const PreprocessorOptions &ExistingPPOpts, DiagnosticsEngine *Diags, FileManager &FileMgr, - std::string &SuggestedPredefines) { + std::string &SuggestedPredefines, + const LangOptions &LangOpts) { // Check macro definitions. MacroDefinitionsMap ASTFileMacros; collectMacroDefinitions(PPOpts, ASTFileMacros); @@ -323,6 +324,15 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, return true; } + // Detailed record is important since it is used for the module cache hash. + if (LangOpts.Modules && + PPOpts.DetailedRecord != ExistingPPOpts.DetailedRecord) { + if (Diags) { + Diags->Report(diag::err_pch_pp_detailed_record) << PPOpts.DetailedRecord; + } + return true; + } + // Compute the #include and #include_macros lines we need. for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) { StringRef File = ExistingPPOpts.Includes[I]; @@ -363,7 +373,8 @@ bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, return checkPreprocessorOptions(PPOpts, ExistingPPOpts, Complain? &Reader.Diags : 0, PP.getFileManager(), - SuggestedPredefines); + SuggestedPredefines, + PP.getLangOpts()); } void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI, @@ -428,8 +439,12 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d, data_type Result; Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d)); - unsigned NumInstanceMethods = ReadUnalignedLE16(d); - unsigned NumFactoryMethods = ReadUnalignedLE16(d); + unsigned NumInstanceMethodsAndBits = ReadUnalignedLE16(d); + unsigned NumFactoryMethodsAndBits = ReadUnalignedLE16(d); + Result.InstanceBits = NumInstanceMethodsAndBits & 0x3; + Result.FactoryBits = NumFactoryMethodsAndBits & 0x3; + unsigned NumInstanceMethods = NumInstanceMethodsAndBits >> 2; + unsigned NumFactoryMethods = NumFactoryMethodsAndBits >> 2; // Load instance methods for (unsigned I = 0; I != NumInstanceMethods; ++I) { @@ -516,6 +531,8 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, Bits >>= 1; bool ExtensionToken = Bits & 0x01; Bits >>= 1; + bool hasSubmoduleMacros = Bits & 0x01; + Bits >>= 1; bool hadMacroDefinition = Bits & 0x01; Bits >>= 1; @@ -554,13 +571,26 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, // If this identifier is a macro, deserialize the macro // definition. if (hadMacroDefinition) { - SmallVector<MacroID, 4> MacroIDs; - while (uint32_t LocalID = ReadUnalignedLE32(d)) { - MacroIDs.push_back(Reader.getGlobalMacroID(F, LocalID)); + uint32_t MacroDirectivesOffset = ReadUnalignedLE32(d); + DataLen -= 4; + SmallVector<uint32_t, 8> LocalMacroIDs; + if (hasSubmoduleMacros) { + while (uint32_t LocalMacroID = ReadUnalignedLE32(d)) { + DataLen -= 4; + LocalMacroIDs.push_back(LocalMacroID); + } DataLen -= 4; } - DataLen -= 4; - Reader.setIdentifierIsMacro(II, MacroIDs); + + if (F.Kind == MK_Module) { + for (SmallVectorImpl<uint32_t>::iterator + I = LocalMacroIDs.begin(), E = LocalMacroIDs.end(); I != E; ++I) { + MacroID MacID = Reader.getGlobalMacroID(F, *I); + Reader.addPendingMacroFromModule(II, &F, MacID, F.DirectImportLoc); + } + } else { + Reader.addPendingMacroFromPCH(II, &F, MacroDirectivesOffset); + } } Reader.SetIdentifierInfo(ID, II); @@ -1073,8 +1103,20 @@ bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID) { } } -void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, - MacroDirective *Hint) { +Token ASTReader::ReadToken(ModuleFile &F, const RecordData &Record, + unsigned &Idx) { + Token Tok; + Tok.startToken(); + Tok.setLocation(ReadSourceLocation(F, Record, Idx)); + Tok.setLength(Record[Idx++]); + if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++])) + Tok.setIdentifierInfo(II); + Tok.setKind((tok::TokenKind)Record[Idx++]); + Tok.setFlag((Token::TokenFlags)Record[Idx++]); + return Tok; +} + +MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { BitstreamCursor &Stream = F.MacroCursor; // Keep track of where we are in the stream, then jump back there @@ -1086,24 +1128,6 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, SmallVector<IdentifierInfo*, 16> MacroArgs; MacroInfo *Macro = 0; - // RAII object to add the loaded macro information once we're done - // adding tokens. - struct AddLoadedMacroInfoRAII { - Preprocessor &PP; - MacroDirective *Hint; - MacroDirective *MD; - IdentifierInfo *II; - - AddLoadedMacroInfoRAII(Preprocessor &PP, MacroDirective *Hint) - : PP(PP), Hint(Hint), MD(), II() { } - ~AddLoadedMacroInfoRAII( ) { - if (MD) { - // Finally, install the macro. - PP.addLoadedMacroInfo(II, MD, Hint); - } - } - } AddLoadedMacroInfo(PP, Hint); - while (true) { // Advance to the next record, but if we get to the end of the block, don't // pop it (removing all the abbreviations from the cursor) since we want to @@ -1115,9 +1139,9 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: Error("malformed block record in AST file"); - return; + return Macro; case llvm::BitstreamEntry::EndBlock: - return; + return Macro; case llvm::BitstreamEntry::Record: // The interesting case. break; @@ -1128,47 +1152,24 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, PreprocessorRecordTypes RecType = (PreprocessorRecordTypes)Stream.readRecord(Entry.ID, Record); switch (RecType) { + case PP_MACRO_DIRECTIVE_HISTORY: + return Macro; + case PP_MACRO_OBJECT_LIKE: case PP_MACRO_FUNCTION_LIKE: { // If we already have a macro, that means that we've hit the end // of the definition of the macro we were looking for. We're // done. if (Macro) - return; + return Macro; - IdentifierInfo *II = getLocalIdentifier(F, Record[0]); - if (II == 0) { - Error("macro must have a name in AST file"); - return; - } - - unsigned GlobalID = getGlobalMacroID(F, Record[1]); - - // If this macro has already been loaded, don't do so again. - if (MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS]) - return; - - SubmoduleID GlobalSubmoduleID = getGlobalSubmoduleID(F, Record[2]); - unsigned NextIndex = 3; + unsigned NextIndex = 1; // Skip identifier ID. + SubmoduleID SubModID = getGlobalSubmoduleID(F, Record[NextIndex++]); SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex); - MacroInfo *MI = PP.AllocateMacroInfo(Loc); - // FIXME: Location should be import location in case of module. - MacroDirective *MD = PP.AllocateMacroDirective(MI, Loc, - /*isImported=*/true); + MacroInfo *MI = PP.AllocateDeserializedMacroInfo(Loc, SubModID); MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex)); - - // Record this macro. - MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS] = MD; - - SourceLocation UndefLoc = ReadSourceLocation(F, Record, NextIndex); - if (UndefLoc.isValid()) - MD->setUndefLoc(UndefLoc); - MI->setIsUsed(Record[NextIndex++]); - bool IsPublic = Record[NextIndex++]; - MD->setVisibility(IsPublic, ReadSourceLocation(F, Record, NextIndex)); - if (RecType == PP_MACRO_FUNCTION_LIKE) { // Decode function-like macro info. bool isC99VarArgs = Record[NextIndex++]; @@ -1188,61 +1189,6 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, PP.getPreprocessorAllocator()); } - if (DeserializationListener) - DeserializationListener->MacroRead(GlobalID, MD); - - // If an update record marked this as undefined, do so now. - // FIXME: Only if the submodule this update came from is visible? - MacroUpdatesMap::iterator Update = MacroUpdates.find(GlobalID); - if (Update != MacroUpdates.end()) { - if (MD->getUndefLoc().isInvalid()) { - for (unsigned I = 0, N = Update->second.size(); I != N; ++I) { - bool Hidden = false; - if (unsigned SubmoduleID = Update->second[I].first) { - if (Module *Owner = getSubmodule(SubmoduleID)) { - if (Owner->NameVisibility == Module::Hidden) { - // Note that this #undef is hidden. - Hidden = true; - - // Record this hiding for later. - HiddenNamesMap[Owner].push_back( - HiddenName(II, MD, Update->second[I].second.UndefLoc)); - } - } - } - - if (!Hidden) { - MD->setUndefLoc(Update->second[I].second.UndefLoc); - if (PPMutationListener *Listener = PP.getPPMutationListener()) - Listener->UndefinedMacro(MD); - break; - } - } - } - MacroUpdates.erase(Update); - } - - // Determine whether this macro definition is visible. - bool Hidden = !MD->isPublic(); - if (!Hidden && GlobalSubmoduleID) { - if (Module *Owner = getSubmodule(GlobalSubmoduleID)) { - if (Owner->NameVisibility == Module::Hidden) { - // The owning module is not visible, and this macro definition - // should not be, either. - Hidden = true; - - // Note that this macro definition was hidden because its owning - // module is not yet visible. - HiddenNamesMap[Owner].push_back(HiddenName(II, MD)); - } - } - } - MD->setHidden(Hidden); - - // Make sure we install the macro once we're done. - AddLoadedMacroInfo.MD = MD; - AddLoadedMacroInfo.II = II; - // Remember that we saw this macro last so that we add the tokens that // form its body to it. Macro = MI; @@ -1270,14 +1216,8 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, // erroneous, just pretend we didn't see this. if (Macro == 0) break; - Token Tok; - Tok.startToken(); - Tok.setLocation(ReadSourceLocation(F, Record[0])); - Tok.setLength(Record[1]); - if (IdentifierInfo *II = getLocalIdentifier(F, Record[2])) - Tok.setIdentifierInfo(II); - Tok.setKind((tok::TokenKind)Record[3]); - Tok.setFlag((Token::TokenFlags)Record[4]); + unsigned Idx = 0; + Token Tok = ReadToken(F, Record, Idx); Macro->AddTokenToBody(Tok); break; } @@ -1337,7 +1277,7 @@ HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) { } HeaderFileInfoTrait::data_type -HeaderFileInfoTrait::ReadData(internal_key_ref, const unsigned char *d, +HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, unsigned DataLen) { const unsigned char *End = d + DataLen; using namespace clang::io; @@ -1358,6 +1298,21 @@ HeaderFileInfoTrait::ReadData(internal_key_ref, const unsigned char *d, HFI.Framework = HS->getUniqueFrameworkName(FrameworkName); } + if (d != End) { + uint32_t LocalSMID = ReadUnalignedLE32(d); + if (LocalSMID) { + // This header is part of a module. Associate it with the module to enable + // implicit module import. + SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID); + Module *Mod = Reader.getSubmodule(GlobalSMID); + HFI.isModuleHeader = true; + FileManager &FileMgr = Reader.getFileManager(); + ModuleMap &ModMap = + Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + ModMap.addHeader(Mod, FileMgr.getFile(key.Filename), /*Excluded=*/false); + } + } + assert(End == d && "Wrong data length in HeaderFileInfo deserialization"); (void)End; @@ -1366,10 +1321,19 @@ HeaderFileInfoTrait::ReadData(internal_key_ref, const unsigned char *d, return HFI; } -void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ArrayRef<MacroID> IDs){ - II->setHadMacroDefinition(true); +void ASTReader::addPendingMacroFromModule(IdentifierInfo *II, + ModuleFile *M, + GlobalMacroID GMacID, + SourceLocation ImportLoc) { + assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard"); + PendingMacroIDs[II].push_back(PendingMacroInfo(M, GMacID, ImportLoc)); +} + +void ASTReader::addPendingMacroFromPCH(IdentifierInfo *II, + ModuleFile *M, + uint64_t MacroDirectivesOffset) { assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard"); - PendingMacroIDs[II].append(IDs.begin(), IDs.end()); + PendingMacroIDs[II].push_back(PendingMacroInfo(M, MacroDirectivesOffset)); } void ASTReader::ReadDefinedMacros() { @@ -1511,6 +1475,160 @@ void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) { IdentifierGeneration[II] = CurrentGeneration; } +void ASTReader::resolvePendingMacro(IdentifierInfo *II, + const PendingMacroInfo &PMInfo) { + assert(II); + + if (PMInfo.M->Kind != MK_Module) { + installPCHMacroDirectives(II, *PMInfo.M, + PMInfo.PCHMacroData.MacroDirectivesOffset); + return; + } + + // Module Macro. + + GlobalMacroID GMacID = PMInfo.ModuleMacroData.GMacID; + SourceLocation ImportLoc = + SourceLocation::getFromRawEncoding(PMInfo.ModuleMacroData.ImportLoc); + + assert(GMacID); + // If this macro has already been loaded, don't do so again. + if (MacrosLoaded[GMacID - NUM_PREDEF_MACRO_IDS]) + return; + + MacroInfo *MI = getMacro(GMacID); + SubmoduleID SubModID = MI->getOwningModuleID(); + MacroDirective *MD = PP.AllocateDefMacroDirective(MI, ImportLoc, + /*isImported=*/true); + + // Determine whether this macro definition is visible. + bool Hidden = false; + Module *Owner = 0; + if (SubModID) { + if ((Owner = getSubmodule(SubModID))) { + if (Owner->NameVisibility == Module::Hidden) { + // The owning module is not visible, and this macro definition + // should not be, either. + Hidden = true; + + // Note that this macro definition was hidden because its owning + // module is not yet visible. + HiddenNamesMap[Owner].push_back(HiddenName(II, MD)); + } + } + } + + if (!Hidden) + installImportedMacro(II, MD, Owner); +} + +void ASTReader::installPCHMacroDirectives(IdentifierInfo *II, + ModuleFile &M, uint64_t Offset) { + assert(M.Kind != MK_Module); + + BitstreamCursor &Cursor = M.MacroCursor; + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(Offset); + + llvm::BitstreamEntry Entry = + Cursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd); + if (Entry.Kind != llvm::BitstreamEntry::Record) { + Error("malformed block record in AST file"); + return; + } + + RecordData Record; + PreprocessorRecordTypes RecType = + (PreprocessorRecordTypes)Cursor.readRecord(Entry.ID, Record); + if (RecType != PP_MACRO_DIRECTIVE_HISTORY) { + Error("malformed block record in AST file"); + return; + } + + // Deserialize the macro directives history in reverse source-order. + MacroDirective *Latest = 0, *Earliest = 0; + unsigned Idx = 0, N = Record.size(); + while (Idx < N) { + MacroDirective *MD = 0; + SourceLocation Loc = ReadSourceLocation(M, Record, Idx); + MacroDirective::Kind K = (MacroDirective::Kind)Record[Idx++]; + switch (K) { + case MacroDirective::MD_Define: { + GlobalMacroID GMacID = getGlobalMacroID(M, Record[Idx++]); + MacroInfo *MI = getMacro(GMacID); + bool isImported = Record[Idx++]; + bool isAmbiguous = Record[Idx++]; + DefMacroDirective *DefMD = + PP.AllocateDefMacroDirective(MI, Loc, isImported); + DefMD->setAmbiguous(isAmbiguous); + MD = DefMD; + break; + } + case MacroDirective::MD_Undefine: + MD = PP.AllocateUndefMacroDirective(Loc); + break; + case MacroDirective::MD_Visibility: { + bool isPublic = Record[Idx++]; + MD = PP.AllocateVisibilityMacroDirective(Loc, isPublic); + break; + } + } + + if (!Latest) + Latest = MD; + if (Earliest) + Earliest->setPrevious(MD); + Earliest = MD; + } + + PP.setLoadedMacroDirective(II, Latest); +} + +/// \brief For the given macro definitions, check if they are both in system +/// modules. +static bool areDefinedInSystemModules(MacroInfo *PrevMI, MacroInfo *NewMI, + Module *NewOwner, ASTReader &Reader) { + assert(PrevMI && NewMI); + if (!NewOwner) + return false; + Module *PrevOwner = 0; + if (SubmoduleID PrevModID = PrevMI->getOwningModuleID()) + PrevOwner = Reader.getSubmodule(PrevModID); + if (!PrevOwner) + return false; + if (PrevOwner == NewOwner) + return false; + return PrevOwner->IsSystem && NewOwner->IsSystem; +} + +void ASTReader::installImportedMacro(IdentifierInfo *II, MacroDirective *MD, + Module *Owner) { + assert(II && MD); + + DefMacroDirective *DefMD = cast<DefMacroDirective>(MD); + MacroDirective *Prev = PP.getMacroDirective(II); + if (Prev) { + MacroDirective::DefInfo PrevDef = Prev->getDefinition(); + MacroInfo *PrevMI = PrevDef.getMacroInfo(); + MacroInfo *NewMI = DefMD->getInfo(); + if (NewMI != PrevMI && !PrevMI->isIdenticalTo(*NewMI, PP, + /*Syntactically=*/true)) { + // Before marking the macros as ambiguous, check if this is a case where + // both macros are in system headers. If so, we trust that the system + // did not get it wrong. This also handles cases where Clang's own + // headers have a different spelling of certain system macros: + // #define LONG_MAX __LONG_MAX__ (clang's limits.h) + // #define LONG_MAX 0x7fffffffffffffffL (system's limits.h) + if (!areDefinedInSystemModules(PrevMI, NewMI, Owner, *this)) { + PrevDef.getDirective()->setAmbiguous(true); + DefMD->setAmbiguous(true); + } + } + } + + PP.appendMacroDirective(II, MD); +} + InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { // If this ID is bogus, just return an empty input file. if (ID == 0 || ID > F.InputFilesLoaded.size()) @@ -1601,8 +1719,10 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { || StoredTime != File->getModificationTime() #endif )) { - if (Complain) + if (Complain) { Error(diag::err_fe_pch_file_modified, Filename, F.FileName); + } + IsOutOfDate = true; } @@ -1759,6 +1879,8 @@ ASTReader::ReadControlBlock(ModuleFile &F, // location info are setup. SourceLocation ImportLoc = SourceLocation::getFromRawEncoding(Record[Idx++]); + off_t StoredSize = (off_t)Record[Idx++]; + time_t StoredModTime = (time_t)Record[Idx++]; unsigned Length = Record[Idx++]; SmallString<128> ImportedFile(Record.begin() + Idx, Record.begin() + Idx + Length); @@ -1766,9 +1888,11 @@ ASTReader::ReadControlBlock(ModuleFile &F, // Load the AST file. switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded, + StoredSize, StoredModTime, ClientLoadCapabilities)) { case Failure: return Failure; // If we have to ignore the dependency, we'll have to ignore this too. + case Missing: case OutOfDate: return OutOfDate; case VersionMismatch: return VersionMismatch; case ConfigurationMismatch: return ConfigurationMismatch; @@ -1875,8 +1999,14 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { Error("error at end of module block in AST file"); return true; case llvm::BitstreamEntry::EndBlock: { + // Outside of C++, we do not store a lookup map for the translation unit. + // Instead, mark it as needing a lookup map to be built if this module + // contains any declarations lexically within it (which it always does!). + // This usually has no cost, since we very rarely need the lookup map for + // the translation unit outside C++. DeclContext *DC = Context.getTranslationUnitDecl(); - if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage()) + if (DC->hasExternalLexicalStorage() && + !getContext().getLangOpts().CPlusPlus) DC->setMustBuildLookupTable(); return false; @@ -2608,18 +2738,8 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { break; } - case MACRO_UPDATES: { - for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { - MacroID ID = getGlobalMacroID(F, Record[I++]); - if (I == N) - break; - - SourceLocation UndefLoc = ReadSourceLocation(F, Record, I); - SubmoduleID SubmoduleID = getGlobalSubmoduleID(F, Record[I++]);; - MacroUpdate Update; - Update.UndefLoc = UndefLoc; - MacroUpdates[ID].push_back(std::make_pair(SubmoduleID, Update)); - } + case MACRO_TABLE: { + // FIXME: Not used yet. break; } } @@ -2638,7 +2758,7 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { ObjCMethodList &Start = Method->isInstanceMethod()? Known->second.first : Known->second.second; bool Found = false; - for (ObjCMethodList *List = &Start; List; List = List->Next) { + for (ObjCMethodList *List = &Start; List; List = List->getNext()) { if (!Found) { if (List->Method == Method) { Found = true; @@ -2648,14 +2768,14 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { } } - if (List->Next) - List->Method = List->Next->Method; + if (List->getNext()) + List->Method = List->getNext()->Method; else List->Method = Method; } } -void ASTReader::makeNamesVisible(const HiddenNames &Names) { +void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) { for (unsigned I = 0, N = Names.size(); I != N; ++I) { switch (Names[I].getKind()) { case HiddenName::Declaration: { @@ -2672,21 +2792,7 @@ void ASTReader::makeNamesVisible(const HiddenNames &Names) { } case HiddenName::MacroVisibility: { std::pair<IdentifierInfo *, MacroDirective *> Macro = Names[I].getMacro(); - Macro.second->setHidden(!Macro.second->isPublic()); - if (Macro.second->isDefined()) { - PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); - } - break; - } - - case HiddenName::MacroUndef: { - std::pair<IdentifierInfo *, MacroDirective *> Macro = Names[I].getMacro(); - if (Macro.second->isDefined()) { - Macro.second->setUndefLoc(Names[I].getMacroUndefLoc()); - if (PPMutationListener *Listener = PP.getPPMutationListener()) - Listener->UndefinedMacro(Macro.second); - PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); - } + installImportedMacro(Macro.first, Macro.second, Owner); break; } } @@ -2695,7 +2801,8 @@ void ASTReader::makeNamesVisible(const HiddenNames &Names) { void ASTReader::makeModuleVisible(Module *Mod, Module::NameVisibilityKind NameVisibility, - SourceLocation ImportLoc) { + SourceLocation ImportLoc, + bool Complain) { llvm::SmallPtrSet<Module *, 4> Visited; SmallVector<Module *, 4> Stack; Stack.push_back(Mod); @@ -2721,7 +2828,7 @@ void ASTReader::makeModuleVisible(Module *Mod, // mark them as visible. HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod); if (Hidden != HiddenNamesMap.end()) { - makeNamesVisible(Hidden->second); + makeNamesVisible(Hidden->second, Hidden->first); HiddenNamesMap.erase(Hidden); } @@ -2743,6 +2850,20 @@ void ASTReader::makeModuleVisible(Module *Mod, if (Visited.insert(Exported)) Stack.push_back(Exported); } + + // Detect any conflicts. + if (Complain) { + assert(ImportLoc.isValid() && "Missing import location"); + for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) { + if (Mod->Conflicts[I].Other->NameVisibility >= NameVisibility) { + Diag(ImportLoc, diag::warn_module_conflict) + << Mod->getFullModuleName() + << Mod->Conflicts[I].Other->getFullModuleName() + << Mod->Conflicts[I].Message; + // FIXME: Need note where the other module was imported. + } + } + } } } @@ -2759,7 +2880,7 @@ bool ASTReader::loadGlobalIndex() { StringRef ModuleCachePath = getPreprocessor().getHeaderSearchInfo().getModuleCachePath(); std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode> Result - = GlobalModuleIndex::readIndex(FileMgr, ModuleCachePath); + = GlobalModuleIndex::readIndex(ModuleCachePath); if (!Result.first) return true; @@ -2784,13 +2905,18 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, SmallVector<ImportedModule, 4> Loaded; switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc, /*ImportedBy=*/0, Loaded, + 0, 0, ClientLoadCapabilities)) { case Failure: + case Missing: case OutOfDate: case VersionMismatch: case ConfigurationMismatch: case HadErrors: - ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end()); + ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(), + Context.getLangOpts().Modules + ? &PP.getHeaderSearchInfo().getModuleMap() + : 0); // If we find that any modules are unusable, the global index is going // to be out-of-date. Just remove it. @@ -2831,11 +2957,16 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, } } - // Setup the import locations. + // Setup the import locations and notify the module manager that we've + // committed to these module files. for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(), MEnd = Loaded.end(); M != MEnd; ++M) { ModuleFile &F = *M->Mod; + + ModuleMgr.moduleFileAccepted(&F); + + // Set the import location. F.DirectImportLoc = ImportLoc; if (!M->ImportedBy) F.ImportLoc = M->ImportLoc; @@ -2853,22 +2984,34 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, Id->second->setOutOfDate(true); // Resolve any unresolved module exports. - for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) { - UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I]; + for (unsigned I = 0, N = UnresolvedModuleRefs.size(); I != N; ++I) { + UnresolvedModuleRef &Unresolved = UnresolvedModuleRefs[I]; SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID); Module *ResolvedMod = getSubmodule(GlobalID); - - if (Unresolved.IsImport) { + + switch (Unresolved.Kind) { + case UnresolvedModuleRef::Conflict: + if (ResolvedMod) { + Module::Conflict Conflict; + Conflict.Other = ResolvedMod; + Conflict.Message = Unresolved.String.str(); + Unresolved.Mod->Conflicts.push_back(Conflict); + } + continue; + + case UnresolvedModuleRef::Import: if (ResolvedMod) Unresolved.Mod->Imports.push_back(ResolvedMod); continue; - } - if (ResolvedMod || Unresolved.IsWildcard) - Unresolved.Mod->Exports.push_back( - Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard)); + case UnresolvedModuleRef::Export: + if (ResolvedMod || Unresolved.IsWildcard) + Unresolved.Mod->Exports.push_back( + Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard)); + continue; + } } - UnresolvedModuleImportExports.clear(); + UnresolvedModuleRefs.clear(); InitializeContext(); @@ -2908,27 +3051,54 @@ ASTReader::ReadASTCore(StringRef FileName, SourceLocation ImportLoc, ModuleFile *ImportedBy, SmallVectorImpl<ImportedModule> &Loaded, + off_t ExpectedSize, time_t ExpectedModTime, unsigned ClientLoadCapabilities) { ModuleFile *M; - bool NewModule; std::string ErrorStr; - llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportLoc, - ImportedBy, CurrentGeneration, - ErrorStr); - - if (!M) { - // We couldn't load the module. - std::string Msg = "Unable to load module \"" + FileName.str() + "\": " - + ErrorStr; - Error(Msg); - return Failure; - } + ModuleManager::AddModuleResult AddResult + = ModuleMgr.addModule(FileName, Type, ImportLoc, ImportedBy, + CurrentGeneration, ExpectedSize, ExpectedModTime, + M, ErrorStr); - if (!NewModule) { - // We've already loaded this module. + switch (AddResult) { + case ModuleManager::AlreadyLoaded: return Success; + + case ModuleManager::NewlyLoaded: + // Load module file below. + break; + + case ModuleManager::Missing: + // The module file was missing; if the client handle handle, that, return + // it. + if (ClientLoadCapabilities & ARR_Missing) + return Missing; + + // Otherwise, return an error. + { + std::string Msg = "Unable to load module \"" + FileName.str() + "\": " + + ErrorStr; + Error(Msg); + } + return Failure; + + case ModuleManager::OutOfDate: + // We couldn't load the module file because it is out-of-date. If the + // client can handle out-of-date, return it. + if (ClientLoadCapabilities & ARR_OutOfDate) + return OutOfDate; + + // Otherwise, return an error. + { + std::string Msg = "Unable to load module \"" + FileName.str() + "\": " + + ErrorStr; + Error(Msg); + } + return Failure; } + assert(M && "Missing module file"); + // FIXME: This seems rather a hack. Should CurrentDir be part of the // module? if (FileName != "-") { @@ -2982,6 +3152,7 @@ ASTReader::ReadASTCore(StringRef FileName, break; case Failure: return Failure; + case Missing: return Missing; case OutOfDate: return OutOfDate; case VersionMismatch: return VersionMismatch; case ConfigurationMismatch: return ConfigurationMismatch; @@ -3142,7 +3313,8 @@ void ASTReader::InitializeContext() { for (unsigned I = 0, N = ImportedModules.size(); I != N; ++I) { if (Module *Imported = getSubmodule(ImportedModules[I])) makeModuleVisible(Imported, Module::AllVisible, - /*ImportLoc=*/SourceLocation()); + /*ImportLoc=*/SourceLocation(), + /*Complain=*/false); } ImportedModules.clear(); } @@ -3151,15 +3323,15 @@ void ASTReader::finalizeForWriting() { for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(), HiddenEnd = HiddenNamesMap.end(); Hidden != HiddenEnd; ++Hidden) { - makeNamesVisible(Hidden->second); + makeNamesVisible(Hidden->second, Hidden->first); } HiddenNamesMap.clear(); } -/// SkipCursorToControlBlock - Given a cursor at the start of an AST file, scan -/// ahead and drop the cursor into the start of the CONTROL_BLOCK, returning -/// false on success and true on failure. -static bool SkipCursorToControlBlock(BitstreamCursor &Cursor) { +/// \brief Given a cursor at the start of an AST file, scan ahead and drop the +/// cursor into the start of the given block ID, returning false on success and +/// true on failure. +static bool SkipCursorToBlock(BitstreamCursor &Cursor, unsigned BlockID) { while (1) { llvm::BitstreamEntry Entry = Cursor.advance(); switch (Entry.Kind) { @@ -3173,8 +3345,8 @@ static bool SkipCursorToControlBlock(BitstreamCursor &Cursor) { break; case llvm::BitstreamEntry::SubBlock: - if (Entry.ID == CONTROL_BLOCK_ID) { - if (Cursor.EnterSubBlock(CONTROL_BLOCK_ID)) + if (Entry.ID == BlockID) { + if (Cursor.EnterSubBlock(BlockID)) return true; // Found it! return false; @@ -3218,7 +3390,7 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName, } // Scan for the CONTROL_BLOCK_ID block. - if (SkipCursorToControlBlock(Stream)) { + if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID)) { Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; return std::string(); } @@ -3273,7 +3445,7 @@ namespace { bool Complain, std::string &SuggestedPredefines) { return checkPreprocessorOptions(ExistingPPOpts, PPOpts, 0, FileMgr, - SuggestedPredefines); + SuggestedPredefines, ExistingLangOpts); } }; } @@ -3305,8 +3477,29 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, } // Scan for the CONTROL_BLOCK_ID block. - if (SkipCursorToControlBlock(Stream)) + if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID)) return true; + + bool NeedsInputFiles = Listener.needsInputFileVisitation(); + BitstreamCursor InputFilesCursor; + if (NeedsInputFiles) { + InputFilesCursor = Stream; + if (SkipCursorToBlock(InputFilesCursor, INPUT_FILES_BLOCK_ID)) + return true; + + // Read the abbreviations + while (true) { + uint64_t Offset = InputFilesCursor.GetCurrentBitNo(); + unsigned Code = InputFilesCursor.ReadCode(); + + // We expect all abbrevs to be at the start of the block. + if (Code != llvm::bitc::DEFINE_ABBREV) { + InputFilesCursor.JumpToBit(Offset); + break; + } + InputFilesCursor.ReadAbbrevRecord(); + } + } // Scan for ORIGINAL_FILE inside the control block. RecordData Record; @@ -3326,10 +3519,9 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, if (Record[0] != VERSION_MAJOR) return true; - const std::string &CurBranch = getClangFullRepositoryVersion(); - if (StringRef(CurBranch) != Blob) + if (Listener.ReadFullVersionInformation(Blob)) return true; - + break; } case LANGUAGE_OPTIONS: @@ -3365,6 +3557,35 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, break; } + case INPUT_FILE_OFFSETS: { + if (!NeedsInputFiles) + break; + + unsigned NumInputFiles = Record[0]; + unsigned NumUserFiles = Record[1]; + const uint32_t *InputFileOffs = (const uint32_t *)Blob.data(); + for (unsigned I = 0; I != NumInputFiles; ++I) { + // Go find this input file. + bool isSystemFile = I >= NumUserFiles; + BitstreamCursor &Cursor = InputFilesCursor; + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(InputFileOffs[I]); + + unsigned Code = Cursor.ReadCode(); + RecordData Record; + StringRef Blob; + bool shouldContinue = false; + switch ((InputFileRecordTypes)Cursor.readRecord(Code, Record, &Blob)) { + case INPUT_FILE: + shouldContinue = Listener.visitInputFile(Blob, isSystemFile); + break; + } + if (!shouldContinue) + break; + } + break; + } + default: // No other validation to perform. break; @@ -3421,7 +3642,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { return true; } - if (Record.size() < 7) { + if (Record.size() < 8) { Error("malformed module definition"); return true; } @@ -3435,7 +3656,8 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { bool InferSubmodules = Record[5]; bool InferExplicitSubmodules = Record[6]; bool InferExportWildcard = Record[7]; - + bool ConfigMacrosExhaustive = Record[8]; + Module *ParentModule = 0; if (Parent) ParentModule = getSubmodule(Parent); @@ -3452,30 +3674,38 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { return true; } - if (const FileEntry *CurFile = CurrentModule->getASTFile()) { - if (CurFile != F.File) { - if (!Diags.isDiagnosticInFlight()) { - Diag(diag::err_module_file_conflict) - << CurrentModule->getTopLevelModuleName() - << CurFile->getName() - << F.File->getName(); + if (!ParentModule) { + if (const FileEntry *CurFile = CurrentModule->getASTFile()) { + if (CurFile != F.File) { + if (!Diags.isDiagnosticInFlight()) { + Diag(diag::err_module_file_conflict) + << CurrentModule->getTopLevelModuleName() + << CurFile->getName() + << F.File->getName(); + } + return true; } - return true; } + + CurrentModule->setASTFile(F.File); } - CurrentModule->setASTFile(F.File); + CurrentModule->IsFromModuleFile = true; CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; CurrentModule->InferSubmodules = InferSubmodules; CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules; CurrentModule->InferExportWildcard = InferExportWildcard; + CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive; if (DeserializationListener) DeserializationListener->ModuleRead(GlobalID, CurrentModule); SubmodulesLoaded[GlobalIndex] = CurrentModule; - // Clear out link libraries; the module file has them. + // Clear out data that will be replaced by what is the module file. CurrentModule->LinkLibraries.clear(); + CurrentModule->ConfigMacros.clear(); + CurrentModule->UnresolvedConflicts.clear(); + CurrentModule->Conflicts.clear(); break; } @@ -3508,13 +3738,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { if (!CurrentModule) break; - // FIXME: Be more lazy about this! - if (const FileEntry *File = PP.getFileManager().getFile(Blob)) { - if (std::find(CurrentModule->Headers.begin(), - CurrentModule->Headers.end(), - File) == CurrentModule->Headers.end()) - ModMap.addHeader(CurrentModule, File, false); - } + // We lazily associate headers with their modules via the HeaderInfoTable. + // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead + // of complete filenames or remove it entirely. break; } @@ -3527,13 +3753,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { if (!CurrentModule) break; - // FIXME: Be more lazy about this! - if (const FileEntry *File = PP.getFileManager().getFile(Blob)) { - if (std::find(CurrentModule->Headers.begin(), - CurrentModule->Headers.end(), - File) == CurrentModule->Headers.end()) - ModMap.addHeader(CurrentModule, File, true); - } + // We lazily associate headers with their modules via the HeaderInfoTable. + // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead + // of complete filenames or remove it entirely. break; } @@ -3546,9 +3768,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { if (!CurrentModule) break; - // FIXME: Be more lazy about this! - if (const FileEntry *File = PP.getFileManager().getFile(Blob)) - CurrentModule->TopHeaders.insert(File); + CurrentModule->addTopHeaderFilename(Blob); break; } @@ -3609,13 +3829,13 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { break; for (unsigned Idx = 0; Idx != Record.size(); ++Idx) { - UnresolvedModuleImportExport Unresolved; + UnresolvedModuleRef Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[Idx]; - Unresolved.IsImport = true; + Unresolved.Kind = UnresolvedModuleRef::Import; Unresolved.IsWildcard = false; - UnresolvedModuleImportExports.push_back(Unresolved); + UnresolvedModuleRefs.push_back(Unresolved); } break; } @@ -3630,13 +3850,13 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { break; for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) { - UnresolvedModuleImportExport Unresolved; + UnresolvedModuleRef Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[Idx]; - Unresolved.IsImport = false; + Unresolved.Kind = UnresolvedModuleRef::Export; Unresolved.IsWildcard = Record[Idx + 1]; - UnresolvedModuleImportExports.push_back(Unresolved); + UnresolvedModuleRefs.push_back(Unresolved); } // Once we've loaded the set of exports, there's no reason to keep @@ -3670,6 +3890,38 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { CurrentModule->LinkLibraries.push_back( Module::LinkLibrary(Blob, Record[0])); break; + + case SUBMODULE_CONFIG_MACRO: + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + CurrentModule->ConfigMacros.push_back(Blob.str()); + break; + + case SUBMODULE_CONFLICT: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + UnresolvedModuleRef Unresolved; + Unresolved.File = &F; + Unresolved.Mod = CurrentModule; + Unresolved.ID = Record[0]; + Unresolved.Kind = UnresolvedModuleRef::Conflict; + Unresolved.IsWildcard = false; + Unresolved.String = Blob; + UnresolvedModuleRefs.push_back(Unresolved); + break; + } } } } @@ -3709,6 +3961,7 @@ bool ASTReader::ParseLanguageOptions(const RecordData &Record, LangOpts.CommentOpts.BlockCommandNames.push_back( ReadString(Record, Idx)); } + LangOpts.CommentOpts.ParseAllComments = Record[Idx++]; return Listener.ReadLanguageOptions(LangOpts, Complain); } @@ -3819,6 +4072,7 @@ bool ASTReader::ParsePreprocessorOptions(const RecordData &Record, } PPOpts.UsePredefines = Record[Idx++]; + PPOpts.DetailedRecord = Record[Idx++]; PPOpts.ImplicitPCHInclude = ReadString(Record, Idx); PPOpts.ImplicitPTHInclude = ReadString(Record, Idx); PPOpts.ObjCXXARCStandardLibrary = @@ -4441,8 +4695,12 @@ QualType ASTReader::readTypeRecord(unsigned Index) { return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind); } - case TYPE_AUTO: - return Context.getAutoType(readType(*Loc.F, Record, Idx)); + case TYPE_AUTO: { + QualType Deduced = readType(*Loc.F, Record, Idx); + bool IsDecltypeAuto = Record[Idx++]; + bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; + return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent); + } case TYPE_RECORD: { if (Record.size() != 2) { @@ -5671,7 +5929,7 @@ void ASTReader::PrintStats() { unsigned NumMacrosLoaded = MacrosLoaded.size() - std::count(MacrosLoaded.begin(), MacrosLoaded.end(), - (MacroDirective *)0); + (MacroInfo *)0); unsigned NumSelectorsLoaded = SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(), SelectorsLoaded.end(), @@ -5817,8 +6075,8 @@ void ASTReader::InitializeSema(Sema &S) { // Makes sure any declarations that were deserialized "too early" // still get added to the identifier's declaration chains. for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) { - NamedDecl *ND = cast<NamedDecl>(PreloadedDecls[I]->getMostRecentDecl()); - SemaObj->pushExternalDeclIntoScope(ND, PreloadedDecls[I]->getDeclName()); + pushExternalDeclIntoScope(PreloadedDecls[I], + PreloadedDecls[I]->getDeclName()); } PreloadedDecls.clear(); @@ -5924,7 +6182,10 @@ StringRef ASTIdentifierIterator::Next() { return Result; } -IdentifierIterator *ASTReader::getIdentifiers() const { +IdentifierIterator *ASTReader::getIdentifiers() { + if (!loadGlobalIndex()) + return GlobalIndex->createIdentifierIterator(); + return new ASTIdentifierIterator(*this); } @@ -5933,13 +6194,16 @@ namespace clang { namespace serialization { ASTReader &Reader; Selector Sel; unsigned PriorGeneration; + unsigned InstanceBits; + unsigned FactoryBits; SmallVector<ObjCMethodDecl *, 4> InstanceMethods; SmallVector<ObjCMethodDecl *, 4> FactoryMethods; public: ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel, unsigned PriorGeneration) - : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration) { } + : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration), + InstanceBits(0), FactoryBits(0) { } static bool visit(ModuleFile &M, void *UserData) { ReadMethodPoolVisitor *This @@ -5972,6 +6236,8 @@ namespace clang { namespace serialization { This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); + This->InstanceBits = Data.InstanceBits; + This->FactoryBits = Data.FactoryBits; return true; } @@ -5984,6 +6250,9 @@ namespace clang { namespace serialization { ArrayRef<ObjCMethodDecl *> getFactoryMethods() const { return FactoryMethods; } + + unsigned getInstanceBits() const { return InstanceBits; } + unsigned getFactoryBits() const { return FactoryBits; } }; } } // end namespace clang::serialization @@ -6021,6 +6290,8 @@ void ASTReader::ReadMethodPool(Selector Sel) { addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first); addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second); + Pos->second.first.setBits(Visitor.getInstanceBits()); + Pos->second.second.setBits(Visitor.getFactoryBits()); } void ASTReader::ReadKnownNamespaces( @@ -6219,8 +6490,7 @@ ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II, // Introduce this declaration into the translation-unit scope // and add it to the declaration chain for this identifier, so // that (unqualified) name lookup will find it. - NamedDecl *ND = cast<NamedDecl>(D->getMostRecentDecl()); - SemaObj->pushExternalDeclIntoScope(ND, II); + pushExternalDeclIntoScope(D, II); } else { // Queue this declaration so that it will be added to the // translation unit scope and identifier's declaration chain @@ -6280,7 +6550,7 @@ IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) { return LocalID + I->second; } -MacroDirective *ASTReader::getMacro(MacroID ID, MacroDirective *Hint) { +MacroInfo *ASTReader::getMacro(MacroID ID) { if (ID == 0) return 0; @@ -6296,7 +6566,11 @@ MacroDirective *ASTReader::getMacro(MacroID ID, MacroDirective *Hint) { assert(I != GlobalMacroMap.end() && "Corrupted global macro map"); ModuleFile *M = I->second; unsigned Index = ID - M->BaseMacroID; - ReadMacroRecord(*M, M->MacroOffsets[Index], Hint); + MacrosLoaded[ID] = ReadMacroRecord(*M, M->MacroOffsets[Index]); + + if (DeserializationListener) + DeserializationListener->MacroRead(ID + NUM_PREDEF_MACRO_IDS, + MacrosLoaded[ID]); } return MacrosLoaded[ID]; @@ -6963,9 +7237,9 @@ void ASTReader::ReadComments() { (RawComment::CommentKind) Record[Idx++]; bool IsTrailingComment = Record[Idx++]; bool IsAlmostTrailingComment = Record[Idx++]; - Comments.push_back(new (Context) RawComment(SR, Kind, - IsTrailingComment, - IsAlmostTrailingComment)); + Comments.push_back(new (Context) RawComment( + SR, Kind, IsTrailingComment, IsAlmostTrailingComment, + Context.getLangOpts().CommentOpts.ParseAllComments)); break; } } @@ -7003,19 +7277,28 @@ void ASTReader::finishPendingActions() { TLD != TLDEnd; ++TLD) { IdentifierInfo *II = TLD->first; for (unsigned I = 0, N = TLD->second.size(); I != N; ++I) { - NamedDecl *ND = cast<NamedDecl>(TLD->second[I]->getMostRecentDecl()); - SemaObj->pushExternalDeclIntoScope(ND, II); + pushExternalDeclIntoScope(cast<NamedDecl>(TLD->second[I]), II); } } // Load any pending macro definitions. for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) { - // FIXME: std::move here - SmallVector<MacroID, 2> GlobalIDs = PendingMacroIDs.begin()[I].second; - MacroDirective *Hint = 0; + IdentifierInfo *II = PendingMacroIDs.begin()[I].first; + SmallVector<PendingMacroInfo, 2> GlobalIDs; + GlobalIDs.swap(PendingMacroIDs.begin()[I].second); + // Initialize the macro history from chained-PCHs ahead of module imports. + for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; + ++IDIdx) { + const PendingMacroInfo &Info = GlobalIDs[IDIdx]; + if (Info.M->Kind != MK_Module) + resolvePendingMacro(II, Info); + } + // Handle module imports. for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; ++IDIdx) { - Hint = getMacro(GlobalIDs[IDIdx], Hint); + const PendingMacroInfo &Info = GlobalIDs[IDIdx]; + if (Info.M->Kind == MK_Module) + resolvePendingMacro(II, Info); } } PendingMacroIDs.clear(); @@ -7134,6 +7417,21 @@ void ASTReader::FinishedDeserializing() { } } +void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { + D = cast<NamedDecl>(D->getMostRecentDecl()); + + if (SemaObj->IdResolver.tryAddTopLevelDecl(D, Name) && SemaObj->TUScope) { + SemaObj->TUScope->AddDecl(D); + } else if (SemaObj->TUScope) { + // Adding the decl to IdResolver may have failed because it was already in + // (even though it was not added in scope). If it is already in, make sure + // it gets in the scope as well. + if (std::find(SemaObj->IdResolver.begin(Name), + SemaObj->IdResolver.end(), D) != SemaObj->IdResolver.end()) + SemaObj->TUScope->AddDecl(D); + } +} + ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot, bool DisableValidation, bool AllowASTWithCompilerErrors, bool UseGlobalIndex) diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 504c2e6588..f7fa818e9b 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -244,6 +244,7 @@ namespace clang { void VisitCXXDestructorDecl(CXXDestructorDecl *D); void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *FD); + void VisitMSPropertyDecl(MSPropertyDecl *FD); void VisitIndirectFieldDecl(IndirectFieldDecl *FD); void VisitVarDecl(VarDecl *VD); void VisitImplicitParamDecl(ImplicitParamDecl *PD); @@ -265,6 +266,7 @@ namespace clang { void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitBlockDecl(BlockDecl *BD); + void VisitCapturedDecl(CapturedDecl *CD); void VisitEmptyDecl(EmptyDecl *D); std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC); @@ -289,6 +291,7 @@ namespace clang { void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); }; } @@ -503,9 +506,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { // FunctionDecl's body is handled last at ASTDeclReader::Visit, // after everything else is read. - + FD->SClass = (StorageClass)Record[Idx++]; - FD->SClassAsWritten = (StorageClass)Record[Idx++]; FD->IsInline = Record[Idx++]; FD->IsInlineSpecified = Record[Idx++]; FD->IsVirtualAsWritten = Record[Idx++]; @@ -847,6 +849,7 @@ void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx)); + D->SuperLoc = ReadSourceLocation(Record, Idx); D->setIvarLBraceLoc(ReadSourceLocation(Record, Idx)); D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx)); D->setHasNonZeroConstructors(Record[Idx++]); @@ -879,6 +882,12 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { } } +void ASTDeclReader::VisitMSPropertyDecl(MSPropertyDecl *PD) { + VisitDeclaratorDecl(PD); + PD->GetterId = Reader.GetIdentifierInfo(F, Record, Idx); + PD->SetterId = Reader.GetIdentifierInfo(F, Record, Idx); +} + void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { VisitValueDecl(FD); @@ -893,10 +902,9 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { void ASTDeclReader::VisitVarDecl(VarDecl *VD) { RedeclarableResult Redecl = VisitRedeclarable(VD); VisitDeclaratorDecl(VD); - + VD->VarDeclBits.SClass = (StorageClass)Record[Idx++]; - VD->VarDeclBits.SClassAsWritten = (StorageClass)Record[Idx++]; - VD->VarDeclBits.ThreadSpecified = Record[Idx++]; + VD->VarDeclBits.TSCSpec = Record[Idx++]; VD->VarDeclBits.InitStyle = Record[Idx++]; VD->VarDeclBits.ExceptionVar = Record[Idx++]; VD->VarDeclBits.NRVOVariable = Record[Idx++]; @@ -988,6 +996,13 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { captures.end(), capturesCXXThis); } +void ASTDeclReader::VisitCapturedDecl(CapturedDecl *CD) { + VisitDecl(CD); + // Body is set by VisitCapturedStmt. + for (unsigned i = 0; i < CD->NumParams; ++i) + CD->setParam(i, ReadDeclAs<ImplicitParamDecl>(Record, Idx)); +} + void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) { VisitDecl(D); D->setLanguage((LinkageSpecDecl::LanguageIDs)Record[Idx++]); @@ -1626,6 +1641,17 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, } } +void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { + VisitDecl(D); + unsigned NumVars = D->varlist_size(); + SmallVector<DeclRefExpr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(cast<DeclRefExpr>(Reader.ReadExpr(F))); + } + D->setVars(Vars); +} + //===----------------------------------------------------------------------===// // Attribute Reading //===----------------------------------------------------------------------===// @@ -2126,6 +2152,12 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_BLOCK: D = BlockDecl::CreateDeserialized(Context, ID); break; + case DECL_MS_PROPERTY: + D = MSPropertyDecl::CreateDeserialized(Context, ID); + break; + case DECL_CAPTURED: + D = CapturedDecl::CreateDeserialized(Context, ID, Record[Idx++]); + break; case DECL_CXX_BASE_SPECIFIERS: Error("attempt to read a C++ base-specifier record as a declaration"); return 0; @@ -2134,6 +2166,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { // locations. D = ImportDecl::CreateDeserialized(Context, ID, Record.back()); break; + case DECL_OMP_THREADPRIVATE: + D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record[Idx++]); + break; case DECL_EMPTY: D = EmptyDecl::CreateDeserialized(Context, ID); break; @@ -2183,10 +2218,6 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { } PendingVisibleUpdates.erase(I); } - - if (!LookupDC->hasExternalVisibleStorage() && - DC->hasExternalLexicalStorage()) - LookupDC->setMustBuildLookupTable(); } assert(Idx == Record.size()); diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h index 327da4403a..9149b18480 100644 --- a/lib/Serialization/ASTReaderInternals.h +++ b/lib/Serialization/ASTReaderInternals.h @@ -152,6 +152,8 @@ class ASTSelectorLookupTrait { public: struct data_type { SelectorID ID; + unsigned InstanceBits; + unsigned FactoryBits; SmallVector<ObjCMethodDecl *, 2> Instance; SmallVector<ObjCMethodDecl *, 2> Factory; }; diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 9c99d6e46f..e1357ba5e6 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Lex/Token.h" #include "llvm/ADT/SmallString.h" using namespace clang; using namespace clang::serialization; @@ -32,14 +33,22 @@ namespace clang { const ASTReader::RecordData &Record; unsigned &Idx; + Token ReadToken(const RecordData &R, unsigned &I) { + return Reader.ReadToken(F, R, I); + } + SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) { return Reader.ReadSourceLocation(F, R, I); } - + SourceRange ReadSourceRange(const RecordData &R, unsigned &I) { return Reader.ReadSourceRange(F, R, I); } - + + std::string ReadString(const RecordData &R, unsigned &I) { + return Reader.ReadString(R, I); + } + TypeSourceInfo *GetTypeSourceInfo(const RecordData &R, unsigned &I) { return Reader.GetTypeSourceInfo(F, R, I); } @@ -286,18 +295,25 @@ void ASTStmtReader::VisitDeclStmt(DeclStmt *S) { } } -void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) { +void ASTStmtReader::VisitAsmStmt(AsmStmt *S) { VisitStmt(S); - unsigned NumOutputs = Record[Idx++]; - unsigned NumInputs = Record[Idx++]; - unsigned NumClobbers = Record[Idx++]; + S->NumOutputs = Record[Idx++]; + S->NumInputs = Record[Idx++]; + S->NumClobbers = Record[Idx++]; S->setAsmLoc(ReadSourceLocation(Record, Idx)); - S->setRParenLoc(ReadSourceLocation(Record, Idx)); S->setVolatile(Record[Idx++]); S->setSimple(Record[Idx++]); +} +void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) { + VisitAsmStmt(S); + S->setRParenLoc(ReadSourceLocation(Record, Idx)); S->setAsmString(cast_or_null<StringLiteral>(Reader.ReadSubStmt())); + unsigned NumOutputs = S->getNumOutputs(); + unsigned NumInputs = S->getNumInputs(); + unsigned NumClobbers = S->getNumClobbers(); + // Outputs and inputs SmallVector<IdentifierInfo *, 16> Names; SmallVector<StringLiteral*, 16> Constraints; @@ -320,8 +336,75 @@ void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) { } void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) { - // FIXME: Statement reader not yet implemented for MS style inline asm. + VisitAsmStmt(S); + S->LBraceLoc = ReadSourceLocation(Record, Idx); + S->EndLoc = ReadSourceLocation(Record, Idx); + S->NumAsmToks = Record[Idx++]; + std::string AsmStr = ReadString(Record, Idx); + + // Read the tokens. + SmallVector<Token, 16> AsmToks; + AsmToks.reserve(S->NumAsmToks); + for (unsigned i = 0, e = S->NumAsmToks; i != e; ++i) { + AsmToks.push_back(ReadToken(Record, Idx)); + } + + // The calls to reserve() for the FooData vectors are mandatory to + // prevent dead StringRefs in the Foo vectors. + + // Read the clobbers. + SmallVector<std::string, 16> ClobbersData; + SmallVector<StringRef, 16> Clobbers; + ClobbersData.reserve(S->NumClobbers); + Clobbers.reserve(S->NumClobbers); + for (unsigned i = 0, e = S->NumClobbers; i != e; ++i) { + ClobbersData.push_back(ReadString(Record, Idx)); + Clobbers.push_back(ClobbersData.back()); + } + + // Read the operands. + unsigned NumOperands = S->NumOutputs + S->NumInputs; + SmallVector<Expr*, 16> Exprs; + SmallVector<std::string, 16> ConstraintsData; + SmallVector<StringRef, 16> Constraints; + Exprs.reserve(NumOperands); + ConstraintsData.reserve(NumOperands); + Constraints.reserve(NumOperands); + for (unsigned i = 0; i != NumOperands; ++i) { + Exprs.push_back(cast<Expr>(Reader.ReadSubStmt())); + ConstraintsData.push_back(ReadString(Record, Idx)); + Constraints.push_back(ConstraintsData.back()); + } + + S->initialize(Reader.getContext(), AsmStr, AsmToks, + Constraints, Exprs, Clobbers); +} + +void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) { VisitStmt(S); + S->setCapturedDecl(ReadDeclAs<CapturedDecl>(Record, Idx)); + S->setCapturedRegionKind(static_cast<CapturedRegionKind>(Record[Idx++])); + S->setCapturedRecordDecl(ReadDeclAs<RecordDecl>(Record, Idx)); + + // Capture inits + for (CapturedStmt::capture_init_iterator I = S->capture_init_begin(), + E = S->capture_init_end(); + I != E; ++I) + *I = Reader.ReadSubExpr(); + + // Body + S->setCapturedStmt(Reader.ReadSubStmt()); + S->getCapturedDecl()->setBody(S->getCapturedStmt()); + + // Captures + for (CapturedStmt::capture_iterator I = S->capture_begin(), + E = S->capture_end(); + I != E; ++I) { + I->VarAndKind.setPointer(ReadDeclAs<VarDecl>(Record, Idx)); + I->VarAndKind + .setInt(static_cast<CapturedStmt::VariableCaptureKind>(Record[Idx++])); + I->Loc = ReadSourceLocation(Record, Idx); + } } void ASTStmtReader::VisitExpr(Expr *E) { @@ -528,6 +611,7 @@ void ASTStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) { VisitExpr(E); E->setBase(Reader.ReadSubExpr()); E->setIsaMemberLoc(ReadSourceLocation(Record, Idx)); + E->setOpLoc(ReadSourceLocation(Record, Idx)); E->setArrow(Record[Idx++]); } @@ -892,6 +976,7 @@ void ASTStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { VisitExpr(E); E->setDecl(ReadDeclAs<ObjCIvarDecl>(Record, Idx)); E->setLocation(ReadSourceLocation(Record, Idx)); + E->setOpLoc(ReadSourceLocation(Record, Idx)); E->setBase(Reader.ReadSubExpr()); E->setIsArrow(Record[Idx++]); E->setIsFreeIvar(Record[Idx++]); @@ -1224,6 +1309,12 @@ void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { E->Loc = ReadSourceLocation(Record, Idx); } +void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + VisitExpr(E); + E->Field = ReadDeclAs<FieldDecl>(Record, Idx); + E->Loc = ReadSourceLocation(Record, Idx); +} + void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { VisitExpr(E); E->setTemporary(Reader.ReadCXXTemporary(F, Record, Idx)); @@ -1496,6 +1587,15 @@ void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) { //===----------------------------------------------------------------------===// // Microsoft Expressions and Statements //===----------------------------------------------------------------------===// +void ASTStmtReader::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { + VisitExpr(E); + E->IsArrow = (Record[Idx++] != 0); + E->BaseExpr = Reader.ReadSubExpr(); + E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); + E->MemberLoc = ReadSourceLocation(Record, Idx); + E->TheDecl = ReadDeclAs<MSPropertyDecl>(Record, Idx); +} + void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); E->setSourceRange(ReadSourceRange(Record, Idx)); @@ -1713,6 +1813,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) MSAsmStmt(Empty); break; + case STMT_CAPTURED: + S = CapturedStmt::CreateDeserialized(Context, + Record[ASTStmtReader::NumExprFields]); + break; + case EXPR_PREDEFINED: S = new (Context) PredefinedExpr(Empty); break; @@ -2071,6 +2176,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { case EXPR_CXX_UUIDOF_EXPR: S = new (Context) CXXUuidofExpr(Empty, true); break; + case EXPR_CXX_PROPERTY_REF_EXPR: + S = new (Context) MSPropertyRefExpr(Empty); + break; case EXPR_CXX_UUIDOF_TYPE: S = new (Context) CXXUuidofExpr(Empty, false); break; @@ -2089,6 +2197,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) CXXDefaultArgExpr(Empty); break; } + case EXPR_CXX_DEFAULT_INIT: + S = new (Context) CXXDefaultInitExpr(Empty); + break; case EXPR_CXX_BIND_TEMPORARY: S = new (Context) CXXBindTemporaryExpr(Empty); break; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 815cf12f11..b8ada04e5d 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -245,6 +245,9 @@ void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) { void ASTTypeWriter::VisitAutoType(const AutoType *T) { Writer.AddTypeRef(T->getDeducedType(), Record); + Record.push_back(T->isDecltypeAuto()); + if (T->getDeducedType().isNull()) + Record.push_back(T->isDependentType()); Code = TYPE_AUTO; } @@ -835,7 +838,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(LOCAL_REDECLARATIONS); RECORD(OBJC_CATEGORIES); RECORD(MACRO_OFFSET); - RECORD(MACRO_UPDATES); + RECORD(MACRO_TABLE); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); @@ -907,6 +910,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DECL_OBJC_PROPERTY); RECORD(DECL_OBJC_PROPERTY_IMPL); RECORD(DECL_FIELD); + RECORD(DECL_MS_PROPERTY); RECORD(DECL_VAR); RECORD(DECL_IMPLICIT_PARAM); RECORD(DECL_PARM_VAR); @@ -1034,6 +1038,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding AddSourceLocation((*M)->ImportLoc, Record); + Record.push_back((*M)->File->getSize()); + Record.push_back((*M)->File->getModificationTime()); // FIXME: This writes the absolute path for AST files we depend on. const std::string &FileName = (*M)->FileName; Record.push_back(FileName.size()); @@ -1067,6 +1073,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, I != IEnd; ++I) { AddString(*I, Record); } + Record.push_back(LangOpts.CommentOpts.ParseAllComments); Stream.EmitRecord(LANGUAGE_OPTIONS, Record); @@ -1165,6 +1172,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, AddString(PPOpts.MacroIncludes[I], Record); Record.push_back(PPOpts.UsePredefines); + // Detailed record is important since it is used for the module cache hash. + Record.push_back(PPOpts.DetailedRecord); AddString(PPOpts.ImplicitPCHInclude, Record); AddString(PPOpts.ImplicitPTHInclude, Record); Record.push_back(static_cast<unsigned>(PPOpts.ObjCXXARCStandardLibrary)); @@ -1213,11 +1222,24 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir); } - WriteInputFiles(Context.SourceMgr, isysroot); + WriteInputFiles(Context.SourceMgr, + PP.getHeaderSearchInfo().getHeaderSearchOpts(), + isysroot); Stream.ExitBlock(); } -void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) { +namespace { + /// \brief An input file. + struct InputFileEntry { + const FileEntry *File; + bool IsSystemFile; + bool BufferOverridden; + }; +} + +void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, + HeaderSearchOptions &HSOpts, + StringRef isysroot) { using namespace llvm; Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4); RecordData Record; @@ -1234,7 +1256,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) { // Get all ContentCache objects for files, sorted by whether the file is a // system one or not. System files go at the back, users files at the front. - std::deque<const SrcMgr::ContentCache *> SortedFiles; + std::deque<InputFileEntry> SortedFiles; for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) { // Get this source location entry. const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I); @@ -1247,20 +1269,38 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) { if (!Cache->OrigEntry) continue; + InputFileEntry Entry; + Entry.File = Cache->OrigEntry; + Entry.IsSystemFile = Cache->IsSystemFile; + Entry.BufferOverridden = Cache->BufferOverridden; if (Cache->IsSystemFile) - SortedFiles.push_back(Cache); + SortedFiles.push_back(Entry); else - SortedFiles.push_front(Cache); + SortedFiles.push_front(Entry); + } + + // If we have an isysroot for a Darwin SDK, include its SDKSettings.plist in + // the set of (non-system) input files. This is simple heuristic for + // detecting whether the system headers may have changed, because it is too + // expensive to stat() all of the system headers. + FileManager &FileMgr = SourceMgr.getFileManager(); + if (!HSOpts.Sysroot.empty() && !Chain) { + llvm::SmallString<128> SDKSettingsFileName(HSOpts.Sysroot); + llvm::sys::path::append(SDKSettingsFileName, "SDKSettings.plist"); + if (const FileEntry *SDKSettingsFile = FileMgr.getFile(SDKSettingsFileName)) { + InputFileEntry Entry = { SDKSettingsFile, false, false }; + SortedFiles.push_front(Entry); + } } unsigned UserFilesNum = 0; // Write out all of the input files. std::vector<uint32_t> InputFileOffsets; - for (std::deque<const SrcMgr::ContentCache *>::iterator + for (std::deque<InputFileEntry>::iterator I = SortedFiles.begin(), E = SortedFiles.end(); I != E; ++I) { - const SrcMgr::ContentCache *Cache = *I; + const InputFileEntry &Entry = *I; - uint32_t &InputFileID = InputFileIDs[Cache->OrigEntry]; + uint32_t &InputFileID = InputFileIDs[Entry.File]; if (InputFileID != 0) continue; // already recorded this file. @@ -1269,7 +1309,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) { InputFileID = InputFileOffsets.size(); - if (!Cache->IsSystemFile) + if (!Entry.IsSystemFile) ++UserFilesNum; Record.clear(); @@ -1277,19 +1317,19 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) { Record.push_back(InputFileOffsets.size()); // Emit size/modification time for this file. - Record.push_back(Cache->OrigEntry->getSize()); - Record.push_back(Cache->OrigEntry->getModificationTime()); + Record.push_back(Entry.File->getSize()); + Record.push_back(Entry.File->getModificationTime()); // Whether this file was overridden. - Record.push_back(Cache->BufferOverridden); + Record.push_back(Entry.BufferOverridden); // Turn the file name into an absolute path, if it isn't already. - const char *Filename = Cache->OrigEntry->getName(); + const char *Filename = Entry.File->getName(); SmallString<128> FilePath(Filename); // Ask the file manager to fixup the relative path for us. This will // honor the working directory. - SourceMgr.getFileManager().FixupRelativePath(FilePath); + FileMgr.FixupRelativePath(FilePath); // FIXME: This call to make_absolute shouldn't be necessary, the // call to FixupRelativePath should always return an absolute path. @@ -1300,7 +1340,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) { Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename); } - + Stream.ExitBlock(); // Create input file offsets abbreviation. @@ -1384,14 +1424,15 @@ namespace { // Trait used for the on-disk hash table of header search information. class HeaderFileInfoTrait { ASTWriter &Writer; + const HeaderSearch &HS; // Keep track of the framework names we've used during serialization. SmallVector<char, 128> FrameworkStringData; llvm::StringMap<unsigned> FrameworkNameOffset; public: - HeaderFileInfoTrait(ASTWriter &Writer) - : Writer(Writer) { } + HeaderFileInfoTrait(ASTWriter &Writer, const HeaderSearch &HS) + : Writer(Writer), HS(HS) { } struct key_type { const FileEntry *FE; @@ -1415,6 +1456,8 @@ namespace { unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8; clang::io::Emit16(Out, KeyLen); unsigned DataLen = 1 + 2 + 4 + 4; + if (Data.isModuleHeader) + DataLen += 4; clang::io::Emit8(Out, DataLen); return std::make_pair(KeyLen, DataLen); } @@ -1427,7 +1470,7 @@ namespace { Out.write(key.Filename, KeyLen); } - void EmitData(raw_ostream &Out, key_type_ref, + void EmitData(raw_ostream &Out, key_type_ref key, data_type_ref Data, unsigned DataLen) { using namespace clang::io; uint64_t Start = Out.tell(); (void)Start; @@ -1461,7 +1504,12 @@ namespace { Offset = Pos->second; } Emit32(Out, Offset); - + + if (Data.isModuleHeader) { + Module *Mod = HS.findModuleForHeader(key.FE); + Emit32(Out, Writer.getExistingSubmoduleID(Mod)); + } + assert(Out.tell() - Start == DataLen && "Wrong data length"); } @@ -1480,7 +1528,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) { if (FilesByUID.size() > HS.header_file_size()) FilesByUID.resize(HS.header_file_size()); - HeaderFileInfoTrait GeneratorTrait(*this); + HeaderFileInfoTrait GeneratorTrait(*this, HS); OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator; SmallVector<const char *, 4> SavedStrings; unsigned NumHeaderSearchEntries = 0; @@ -1746,14 +1794,67 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Preprocessor Serialization //===----------------------------------------------------------------------===// -static int compareMacroDefinitions(const void *XPtr, const void *YPtr) { - const std::pair<const IdentifierInfo *, MacroInfo *> &X = - *(const std::pair<const IdentifierInfo *, MacroInfo *>*)XPtr; - const std::pair<const IdentifierInfo *, MacroInfo *> &Y = - *(const std::pair<const IdentifierInfo *, MacroInfo *>*)YPtr; +namespace { +class ASTMacroTableTrait { +public: + typedef IdentID key_type; + typedef key_type key_type_ref; + + struct Data { + uint32_t MacroDirectivesOffset; + }; + + typedef Data data_type; + typedef const data_type &data_type_ref; + + static unsigned ComputeHash(IdentID IdID) { + return llvm::hash_value(IdID); + } + + std::pair<unsigned,unsigned> + static EmitKeyDataLength(raw_ostream& Out, + key_type_ref Key, data_type_ref Data) { + unsigned KeyLen = 4; // IdentID. + unsigned DataLen = 4; // MacroDirectivesOffset. + return std::make_pair(KeyLen, DataLen); + } + + static void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) { + clang::io::Emit32(Out, Key); + } + + static void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data, + unsigned) { + clang::io::Emit32(Out, Data.MacroDirectivesOffset); + } +}; +} // end anonymous namespace + +static int compareMacroDirectives(const void *XPtr, const void *YPtr) { + const std::pair<const IdentifierInfo *, MacroDirective *> &X = + *(const std::pair<const IdentifierInfo *, MacroDirective *>*)XPtr; + const std::pair<const IdentifierInfo *, MacroDirective *> &Y = + *(const std::pair<const IdentifierInfo *, MacroDirective *>*)YPtr; return X.first->getName().compare(Y.first->getName()); } +static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule, + const Preprocessor &PP) { + if (MacroInfo *MI = MD->getMacroInfo()) + if (MI->isBuiltinMacro()) + return true; + + if (IsModule) { + SourceLocation Loc = MD->getLocation(); + if (Loc.isInvalid()) + return true; + if (PP.getSourceManager().getFileID(Loc) == PP.getPredefinesFileID()) + return true; + } + + return false; +} + /// \brief Writes the block containing the serialized form of the /// preprocessor. /// @@ -1780,24 +1881,73 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n"); - // Loop over all the macro definitions that are live at the end of the file, + // Loop over all the macro directives that are live at the end of the file, // emitting each to the PP section. - // Construct the list of macro definitions that need to be serialized. + // Construct the list of macro directives that need to be serialized. SmallVector<std::pair<const IdentifierInfo *, MacroDirective *>, 2> - MacrosToEmit; - for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0), - E = PP.macro_end(Chain == 0); + MacroDirectives; + for (Preprocessor::macro_iterator + I = PP.macro_begin(/*IncludeExternalMacros=*/false), + E = PP.macro_end(/*IncludeExternalMacros=*/false); I != E; ++I) { - if (!IsModule || I->second->isPublic()) { - MacrosToEmit.push_back(std::make_pair(I->first, I->second)); - } + MacroDirectives.push_back(std::make_pair(I->first, I->second)); } // Sort the set of macro definitions that need to be serialized by the // name of the macro, to provide a stable ordering. - llvm::array_pod_sort(MacrosToEmit.begin(), MacrosToEmit.end(), - &compareMacroDefinitions); + llvm::array_pod_sort(MacroDirectives.begin(), MacroDirectives.end(), + &compareMacroDirectives); + + OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator; + + // Emit the macro directives as a list and associate the offset with the + // identifier they belong to. + for (unsigned I = 0, N = MacroDirectives.size(); I != N; ++I) { + const IdentifierInfo *Name = MacroDirectives[I].first; + uint64_t MacroDirectiveOffset = Stream.GetCurrentBitNo(); + MacroDirective *MD = MacroDirectives[I].second; + + // If the macro or identifier need no updates, don't write the macro history + // for this one. + // FIXME: Chain the macro history instead of re-writing it. + if (MD->isFromPCH() && + Name->isFromAST() && !Name->hasChangedSinceDeserialization()) + continue; + + // Emit the macro directives in reverse source order. + for (; MD; MD = MD->getPrevious()) { + if (MD->isHidden()) + continue; + if (shouldIgnoreMacro(MD, IsModule, PP)) + continue; + + AddSourceLocation(MD->getLocation(), Record); + Record.push_back(MD->getKind()); + if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) { + MacroID InfoID = getMacroRef(DefMD->getInfo(), Name); + Record.push_back(InfoID); + Record.push_back(DefMD->isImported()); + Record.push_back(DefMD->isAmbiguous()); + + } else if (VisibilityMacroDirective * + VisMD = dyn_cast<VisibilityMacroDirective>(MD)) { + Record.push_back(VisMD->isPublic()); + } + } + if (Record.empty()) + continue; + + Stream.EmitRecord(PP_MACRO_DIRECTIVE_HISTORY, Record); + Record.clear(); + + IdentMacroDirectivesOffsetMap[Name] = MacroDirectiveOffset; + + IdentID NameID = getIdentifierRef(Name); + ASTMacroTableTrait::Data data; + data.MacroDirectivesOffset = MacroDirectiveOffset; + Generator.insert(NameID, data); + } /// \brief Offsets of each of the macros into the bitstream, indexed by /// the local macro ID @@ -1807,98 +1957,96 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { /// defined. std::vector<uint32_t> MacroOffsets; - for (unsigned I = 0, N = MacrosToEmit.size(); I != N; ++I) { - const IdentifierInfo *Name = MacrosToEmit[I].first; + for (unsigned I = 0, N = MacroInfosToEmit.size(); I != N; ++I) { + const IdentifierInfo *Name = MacroInfosToEmit[I].Name; + MacroInfo *MI = MacroInfosToEmit[I].MI; + MacroID ID = MacroInfosToEmit[I].ID; - for (MacroDirective *MD = MacrosToEmit[I].second; MD; - MD = MD->getPrevious()) { - MacroID ID = getMacroRef(MD); - if (!ID) - continue; + if (ID < FirstMacroID) { + assert(0 && "Loaded MacroInfo entered MacroInfosToEmit ?"); + continue; + } - // Skip macros from a AST file if we're chaining. - if (Chain && MD->isImported() && !MD->hasChangedAfterLoad()) - continue; + // Record the local offset of this macro. + unsigned Index = ID - FirstMacroID; + if (Index == MacroOffsets.size()) + MacroOffsets.push_back(Stream.GetCurrentBitNo()); + else { + if (Index > MacroOffsets.size()) + MacroOffsets.resize(Index + 1); - if (ID < FirstMacroID) { - // This will have been dealt with via an update record. - assert(MacroUpdates.count(MD) > 0 && "Missing macro update"); - continue; - } + MacroOffsets[Index] = Stream.GetCurrentBitNo(); + } - // Record the local offset of this macro. - unsigned Index = ID - FirstMacroID; - if (Index == MacroOffsets.size()) - MacroOffsets.push_back(Stream.GetCurrentBitNo()); - else { - if (Index > MacroOffsets.size()) - MacroOffsets.resize(Index + 1); + AddIdentifierRef(Name, Record); + Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc())); + AddSourceLocation(MI->getDefinitionLoc(), Record); + AddSourceLocation(MI->getDefinitionEndLoc(), Record); + Record.push_back(MI->isUsed()); + unsigned Code; + if (MI->isObjectLike()) { + Code = PP_MACRO_OBJECT_LIKE; + } else { + Code = PP_MACRO_FUNCTION_LIKE; - MacroOffsets[Index] = Stream.GetCurrentBitNo(); - } + Record.push_back(MI->isC99Varargs()); + Record.push_back(MI->isGNUVarargs()); + Record.push_back(MI->hasCommaPasting()); + Record.push_back(MI->getNumArgs()); + for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end(); + I != E; ++I) + AddIdentifierRef(*I, Record); + } - AddIdentifierRef(Name, Record); - addMacroRef(MD, Record); - const MacroInfo *MI = MD->getInfo(); - Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc())); - AddSourceLocation(MI->getDefinitionLoc(), Record); - AddSourceLocation(MI->getDefinitionEndLoc(), Record); - AddSourceLocation(MD->getUndefLoc(), Record); - Record.push_back(MI->isUsed()); - Record.push_back(MD->isPublic()); - AddSourceLocation(MD->getVisibilityLocation(), Record); - unsigned Code; - if (MI->isObjectLike()) { - Code = PP_MACRO_OBJECT_LIKE; - } else { - Code = PP_MACRO_FUNCTION_LIKE; - - Record.push_back(MI->isC99Varargs()); - Record.push_back(MI->isGNUVarargs()); - Record.push_back(MI->hasCommaPasting()); - Record.push_back(MI->getNumArgs()); - for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end(); - I != E; ++I) - AddIdentifierRef(*I, Record); - } + // If we have a detailed preprocessing record, record the macro definition + // ID that corresponds to this macro. + if (PPRec) + Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]); - // If we have a detailed preprocessing record, record the macro definition - // ID that corresponds to this macro. - if (PPRec) - Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]); + Stream.EmitRecord(Code, Record); + Record.clear(); - Stream.EmitRecord(Code, Record); + // Emit the tokens array. + for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) { + // Note that we know that the preprocessor does not have any annotation + // tokens in it because they are created by the parser, and thus can't + // be in a macro definition. + const Token &Tok = MI->getReplacementToken(TokNo); + AddToken(Tok, Record); + Stream.EmitRecord(PP_TOKEN, Record); Record.clear(); - - // Emit the tokens array. - for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) { - // Note that we know that the preprocessor does not have any annotation - // tokens in it because they are created by the parser, and thus can't - // be in a macro definition. - const Token &Tok = MI->getReplacementToken(TokNo); - - Record.push_back(Tok.getLocation().getRawEncoding()); - Record.push_back(Tok.getLength()); - - // FIXME: When reading literal tokens, reconstruct the literal pointer - // if it is needed. - AddIdentifierRef(Tok.getIdentifierInfo(), Record); - // FIXME: Should translate token kind to a stable encoding. - Record.push_back(Tok.getKind()); - // FIXME: Should translate token flags to a stable encoding. - Record.push_back(Tok.getFlags()); - - Stream.EmitRecord(PP_TOKEN, Record); - Record.clear(); - } - ++NumMacros; } + ++NumMacros; } + Stream.ExitBlock(); - // Write the offsets table for macro IDs. + // Create the on-disk hash table in a buffer. + SmallString<4096> MacroTable; + uint32_t BucketOffset; + { + llvm::raw_svector_ostream Out(MacroTable); + // Make sure that no bucket is at offset 0 + clang::io::Emit32(Out, 0); + BucketOffset = Generator.Emit(Out); + } + + // Write the macro table using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(MACRO_TABLE)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned MacroTableAbbrev = Stream.EmitAbbrev(Abbrev); + + Record.push_back(MACRO_TABLE); + Record.push_back(BucketOffset); + Stream.EmitRecordWithBlob(MacroTableAbbrev, Record, MacroTable.str()); + Record.clear(); + + // Write the offsets table for macro IDs. + using namespace llvm; + Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID @@ -2020,6 +2168,18 @@ unsigned ASTWriter::getSubmoduleID(Module *Mod) { return SubmoduleIDs[Mod] = NextSubmoduleID++; } +unsigned ASTWriter::getExistingSubmoduleID(Module *Mod) const { + if (!Mod) + return 0; + + llvm::DenseMap<Module *, unsigned>::const_iterator + Known = SubmoduleIDs.find(Mod); + if (Known != SubmoduleIDs.end()) + return Known->second; + + return 0; +} + /// \brief Compute the number of modules within the given tree (including the /// given module). static unsigned getNumberOfModules(Module *Mod) { @@ -2063,6 +2223,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild... + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConfigMacrosExh... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev); @@ -2102,6 +2263,17 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned LinkLibraryAbbrev = Stream.EmitAbbrev(Abbrev); + Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFIG_MACRO)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name + unsigned ConfigMacroAbbrev = Stream.EmitAbbrev(Abbrev); + + Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFLICT)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Other module + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message + unsigned ConflictAbbrev = Stream.EmitAbbrev(Abbrev); + // Write the submodule metadata block. RecordData Record; Record.push_back(getNumberOfModules(WritingModule)); @@ -2132,6 +2304,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Record.push_back(Mod->InferSubmodules); Record.push_back(Mod->InferExplicitSubmodules); Record.push_back(Mod->InferExportWildcard); + Record.push_back(Mod->ConfigMacrosExhaustive); Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name); // Emit the requirements. @@ -2170,11 +2343,13 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record, Mod->ExcludedHeaders[I]->getName()); } - for (unsigned I = 0, N = Mod->TopHeaders.size(); I != N; ++I) { + ArrayRef<const FileEntry *> + TopHeaders = Mod->getTopHeaders(PP->getFileManager()); + for (unsigned I = 0, N = TopHeaders.size(); I != N; ++I) { Record.clear(); Record.push_back(SUBMODULE_TOPHEADER); Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record, - Mod->TopHeaders[I]->getName()); + TopHeaders[I]->getName()); } // Emit the imports. @@ -2214,6 +2389,25 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Mod->LinkLibraries[I].Library); } + // Emit the conflicts. + for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) { + Record.clear(); + Record.push_back(SUBMODULE_CONFLICT); + unsigned OtherID = getSubmoduleID(Mod->Conflicts[I].Other); + assert(OtherID && "Unknown submodule!"); + Record.push_back(OtherID); + Stream.EmitRecordWithBlob(ConflictAbbrev, Record, + Mod->Conflicts[I].Message); + } + + // Emit the configuration macros. + for (unsigned I = 0, N = Mod->ConfigMacros.size(); I != N; ++I) { + Record.clear(); + Record.push_back(SUBMODULE_CONFIG_MACRO); + Stream.EmitRecordWithBlob(ConfigMacroAbbrev, Record, + Mod->ConfigMacros[I]); + } + // Queue up the submodules of this module. for (Module::submodule_iterator Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end(); @@ -2246,8 +2440,14 @@ ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) { return getSubmoduleID(OwningMod); } -void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) { - // FIXME: Make it work properly with modules. +void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, + bool isModule) { + // Make sure set diagnostic pragmas don't affect the translation unit that + // imports the module. + // FIXME: Make diagnostic pragma sections work properly with modules. + if (isModule) + return; + llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64> DiagStateIDMap; unsigned CurrID = 0; @@ -2486,11 +2686,11 @@ public: clang::io::Emit16(Out, KeyLen); unsigned DataLen = 4 + 2 + 2; // 2 bytes for each of the method counts for (const ObjCMethodList *Method = &Methods.Instance; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) DataLen += 4; for (const ObjCMethodList *Method = &Methods.Factory; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) DataLen += 4; clang::io::Emit16(Out, DataLen); @@ -2516,24 +2716,31 @@ public: clang::io::Emit32(Out, Methods.ID); unsigned NumInstanceMethods = 0; for (const ObjCMethodList *Method = &Methods.Instance; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) ++NumInstanceMethods; unsigned NumFactoryMethods = 0; for (const ObjCMethodList *Method = &Methods.Factory; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) ++NumFactoryMethods; - clang::io::Emit16(Out, NumInstanceMethods); - clang::io::Emit16(Out, NumFactoryMethods); + unsigned InstanceBits = Methods.Instance.getBits(); + assert(InstanceBits < 4); + unsigned NumInstanceMethodsAndBits = + (NumInstanceMethods << 2) | InstanceBits; + unsigned FactoryBits = Methods.Factory.getBits(); + assert(FactoryBits < 4); + unsigned NumFactoryMethodsAndBits = (NumFactoryMethods << 2) | FactoryBits; + clang::io::Emit16(Out, NumInstanceMethodsAndBits); + clang::io::Emit16(Out, NumFactoryMethodsAndBits); for (const ObjCMethodList *Method = &Methods.Instance; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); for (const ObjCMethodList *Method = &Methods.Factory; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); @@ -2582,12 +2789,12 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { // Selector already exists. Did it change? bool changed = false; for (ObjCMethodList *M = &Data.Instance; !changed && M && M->Method; - M = M->Next) { + M = M->getNext()) { if (!M->Method->isFromASTFile()) changed = true; } for (ObjCMethodList *M = &Data.Factory; !changed && M && M->Method; - M = M->Next) { + M = M->getNext()) { if (!M->Method->isFromASTFile()) changed = true; } @@ -2695,13 +2902,97 @@ class ASTIdentifierTableTrait { if (!II->hadMacroDefinition()) return false; - if (Macro || (Macro = PP.getMacroDirectiveHistory(II))) - return !Macro->getInfo()->isBuiltinMacro() && - (!IsModule || Macro->isPublic()); + if (Macro || (Macro = PP.getMacroDirectiveHistory(II))) { + if (!IsModule) + return !shouldIgnoreMacro(Macro, IsModule, PP); + SubmoduleID ModID; + if (getFirstPublicSubmoduleMacro(Macro, ModID)) + return true; + } return false; } + DefMacroDirective *getFirstPublicSubmoduleMacro(MacroDirective *MD, + SubmoduleID &ModID) { + ModID = 0; + if (DefMacroDirective *DefMD = getPublicSubmoduleMacro(MD, ModID)) + if (!shouldIgnoreMacro(DefMD, IsModule, PP)) + return DefMD; + return 0; + } + + DefMacroDirective *getNextPublicSubmoduleMacro(DefMacroDirective *MD, + SubmoduleID &ModID) { + if (DefMacroDirective * + DefMD = getPublicSubmoduleMacro(MD->getPrevious(), ModID)) + if (!shouldIgnoreMacro(DefMD, IsModule, PP)) + return DefMD; + return 0; + } + + /// \brief Traverses the macro directives history and returns the latest + /// macro that is public and not undefined in the same submodule. + /// A macro that is defined in submodule A and undefined in submodule B, + /// will still be considered as defined/exported from submodule A. + DefMacroDirective *getPublicSubmoduleMacro(MacroDirective *MD, + SubmoduleID &ModID) { + if (!MD) + return 0; + + SubmoduleID OrigModID = ModID; + bool isUndefined = false; + Optional<bool> isPublic; + for (; MD; MD = MD->getPrevious()) { + if (MD->isHidden()) + continue; + + SubmoduleID ThisModID = getSubmoduleID(MD); + if (ThisModID == 0) { + isUndefined = false; + isPublic = Optional<bool>(); + continue; + } + if (ThisModID != ModID){ + ModID = ThisModID; + isUndefined = false; + isPublic = Optional<bool>(); + } + // We are looking for a definition in a different submodule than the one + // that we started with. If a submodule has re-definitions of the same + // macro, only the last definition will be used as the "exported" one. + if (ModID == OrigModID) + continue; + + if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) { + if (!isUndefined && (!isPublic.hasValue() || isPublic.getValue())) + return DefMD; + continue; + } + + if (isa<UndefMacroDirective>(MD)) { + isUndefined = true; + continue; + } + + VisibilityMacroDirective *VisMD = cast<VisibilityMacroDirective>(MD); + if (!isPublic.hasValue()) + isPublic = VisMD->isPublic(); + } + + return 0; + } + + SubmoduleID getSubmoduleID(MacroDirective *MD) { + if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) { + MacroInfo *MI = DefMD->getInfo(); + if (unsigned ID = MI->getOwningModuleID()) + return ID; + return Writer.inferSubmoduleIDFromLocation(MI->getDefinitionLoc()); + } + return Writer.inferSubmoduleIDFromLocation(MD->getLocation()); + } + public: typedef IdentifierInfo* key_type; typedef key_type key_type_ref; @@ -2726,12 +3017,16 @@ public: DataLen += 2; // 2 bytes for builtin ID DataLen += 2; // 2 bytes for flags if (hadMacroDefinition(II, Macro)) { - for (MacroDirective *M = Macro; M; M = M->getPrevious()) { - if (Writer.getMacroRef(M) != 0) - DataLen += 4; + DataLen += 4; // MacroDirectives offset. + if (IsModule) { + SubmoduleID ModID; + for (DefMacroDirective * + DefMD = getFirstPublicSubmoduleMacro(Macro, ModID); + DefMD; DefMD = getNextPublicSubmoduleMacro(DefMD, ModID)) { + DataLen += 4; // MacroInfo ID. + } + DataLen += 4; } - - DataLen += 4; } for (IdentifierResolver::iterator D = IdResolver.begin(II), @@ -2770,6 +3065,7 @@ public: Bits = 0; bool HadMacroDefinition = hadMacroDefinition(II, Macro); Bits = (Bits << 1) | unsigned(HadMacroDefinition); + Bits = (Bits << 1) | unsigned(IsModule); Bits = (Bits << 1) | unsigned(II->isExtensionToken()); Bits = (Bits << 1) | unsigned(II->isPoisoned()); Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier()); @@ -2777,13 +3073,19 @@ public: clang::io::Emit16(Out, Bits); if (HadMacroDefinition) { - // Write all of the macro IDs associated with this identifier. - for (MacroDirective *M = Macro; M; M = M->getPrevious()) { - if (MacroID ID = Writer.getMacroRef(M)) - clang::io::Emit32(Out, ID); + clang::io::Emit32(Out, Writer.getMacroDirectivesOffset(II)); + if (IsModule) { + // Write the IDs of macros coming from different submodules. + SubmoduleID ModID; + for (DefMacroDirective * + DefMD = getFirstPublicSubmoduleMacro(Macro, ModID); + DefMD; DefMD = getNextPublicSubmoduleMacro(DefMD, ModID)) { + MacroID InfoID = Writer.getMacroID(DefMD->getInfo()); + assert(InfoID); + clang::io::Emit32(Out, InfoID); + } + clang::io::Emit32(Out, 0); } - - clang::io::Emit32(Out, 0); } // Emit the declaration IDs in reverse order, because the @@ -2797,7 +3099,28 @@ public: for (SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(), DEnd = Decls.rend(); D != DEnd; ++D) - clang::io::Emit32(Out, Writer.getDeclID(*D)); + clang::io::Emit32(Out, Writer.getDeclID(getMostRecentLocalDecl(*D))); + } + + /// \brief Returns the most recent local decl or the given decl if there are + /// no local ones. The given decl is assumed to be the most recent one. + Decl *getMostRecentLocalDecl(Decl *Orig) { + // The only way a "from AST file" decl would be more recent from a local one + // is if it came from a module. + if (!PP.getLangOpts().Modules) + return Orig; + + // Look for a local in the decl chain. + for (Decl *D = Orig; D; D = D->getPreviousDecl()) { + if (!D->isFromASTFile()) + return D; + // If we come up a decl from a (chained-)PCH stop since we won't find a + // local one. + if (D->getOwningModuleID() == 0) + break; + } + + return Orig; } }; } // end anonymous namespace @@ -3025,8 +3348,6 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, // If not in C++, we perform name lookup for the translation unit via the // IdentifierInfo chains, don't bother to build a visible-declarations table. - // FIXME: In C++ we need the visible declarations in order to "see" the - // friend declarations, is there a way to do this without writing the table ? if (DC->isTranslationUnit() && !Context.getLangOpts().CPlusPlus) return 0; @@ -3329,6 +3650,19 @@ void ASTWriter::WriteAttributes(ArrayRef<const Attr*> Attrs, } } +void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) { + AddSourceLocation(Tok.getLocation(), Record); + Record.push_back(Tok.getLength()); + + // FIXME: When reading literal tokens, reconstruct the literal pointer + // if it is needed. + AddIdentifierRef(Tok.getIdentifierInfo(), Record); + // FIXME: Should translate token kind to a stable encoding. + Record.push_back(Tok.getKind()); + // FIXME: Should translate token flags to a stable encoding. + Record.push_back(Tok.getFlags()); +} + void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) { Record.push_back(Str.size()); Record.insert(Record.end(), Str.begin(), Str.end()); @@ -3442,6 +3776,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Module *WritingModule) { using namespace llvm; + bool isModule = WritingModule != 0; + // Make sure that the AST reader knows to finalize itself. if (Chain) Chain->finalizeForWriting(); @@ -3507,13 +3843,15 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, // Build a record containing all of the file scoped decls in this file. RecordData UnusedFileScopedDecls; - AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls, - UnusedFileScopedDecls); + if (!isModule) + AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls, + UnusedFileScopedDecls); // Build a record containing all of the delegating constructors we still need // to resolve. RecordData DelegatingCtorDecls; - AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls); + if (!isModule) + AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls); // Write the set of weak, undeclared identifiers. We always write the // entire table, since later PCH files in a PCH chain are only interested in @@ -3748,16 +4086,16 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record, Buffer.data(), Buffer.size()); } - WritePreprocessor(PP, WritingModule != 0); + WritePreprocessor(PP, isModule); WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot); WriteSelectors(SemaRef); WriteReferencedSelectorsPool(SemaRef); - WriteIdentifierTable(PP, SemaRef.IdResolver, WritingModule != 0); + WriteIdentifierTable(PP, SemaRef.IdResolver, isModule); WriteFPPragmaOptions(SemaRef.getFPOptions()); WriteOpenCLExtensions(SemaRef); WriteTypeDeclOffsets(); - WritePragmaDiagnosticMappings(Context.getDiagnostics()); + WritePragmaDiagnosticMappings(Context.getDiagnostics(), isModule); WriteCXXBaseSpecifiersOffsets(); @@ -3854,7 +4192,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, } } - WriteMacroUpdates(); WriteDeclUpdatesBlocks(); WriteDeclReplacementsBlock(); WriteRedeclarations(); @@ -3871,21 +4208,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Stream.ExitBlock(); } -void ASTWriter::WriteMacroUpdates() { - if (MacroUpdates.empty()) - return; - - RecordData Record; - for (MacroUpdatesMap::iterator I = MacroUpdates.begin(), - E = MacroUpdates.end(); - I != E; ++I) { - addMacroRef(I->first, Record); - AddSourceLocation(I->second.UndefLoc, Record); - Record.push_back(inferSubmoduleIDFromLocation(I->second.UndefLoc)); - } - Stream.EmitRecord(MACRO_UPDATES, Record); -} - /// \brief Go through the declaration update blocks and resolve declaration /// pointers into declaration IDs. void ASTWriter::ResolveDeclUpdatesBlocks() { @@ -3981,10 +4303,6 @@ void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Recor Record.push_back(getIdentifierRef(II)); } -void ASTWriter::addMacroRef(MacroDirective *MD, RecordDataImpl &Record) { - Record.push_back(getMacroRef(MD)); -} - IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) { if (II == 0) return 0; @@ -3995,19 +4313,35 @@ IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) { return ID; } -MacroID ASTWriter::getMacroRef(MacroDirective *MD) { +MacroID ASTWriter::getMacroRef(MacroInfo *MI, const IdentifierInfo *Name) { // Don't emit builtin macros like __LINE__ to the AST file unless they // have been redefined by the header (in which case they are not // isBuiltinMacro). - if (MD == 0 || MD->getInfo()->isBuiltinMacro()) + if (MI == 0 || MI->isBuiltinMacro()) return 0; - MacroID &ID = MacroIDs[MD]; - if (ID == 0) + MacroID &ID = MacroIDs[MI]; + if (ID == 0) { ID = NextMacroID++; + MacroInfoToEmitData Info = { Name, MI, ID }; + MacroInfosToEmit.push_back(Info); + } return ID; } +MacroID ASTWriter::getMacroID(MacroInfo *MI) { + if (MI == 0 || MI->isBuiltinMacro()) + return 0; + + assert(MacroIDs.find(MI) != MacroIDs.end() && "Macro not emitted!"); + return MacroIDs[MI]; +} + +uint64_t ASTWriter::getMacroDirectivesOffset(const IdentifierInfo *Name) { + assert(IdentMacroDirectivesOffsetMap[Name] && "not set!"); + return IdentMacroDirectivesOffsetMap[Name]; +} + void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) { Record.push_back(getSelectorRef(SelRef)); } @@ -4747,9 +5081,9 @@ void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) { StoredID = ID; } -void ASTWriter::MacroRead(serialization::MacroID ID, MacroDirective *MD) { +void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) { // Always keep the highest ID. See \p TypeRead() for more information. - MacroID &StoredID = MacroIDs[MD]; + MacroID &StoredID = MacroIDs[MI]; if (ID > StoredID) StoredID = ID; } @@ -4783,10 +5117,6 @@ void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) { SubmoduleIDs[Mod] = ID; } -void ASTWriter::UndefinedMacro(MacroDirective *MD) { - MacroUpdates[MD].UndefLoc = MD->getUndefLoc(); -} - void ASTWriter::CompletedTagDefinition(const TagDecl *D) { assert(D->isCompleteDefinition()); assert(!WritingAST && "Already writing the AST!"); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 6c63a149c2..67349db687 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -81,6 +81,7 @@ namespace clang { void VisitCXXDestructorDecl(CXXDestructorDecl *D); void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *D); + void VisitMSPropertyDecl(MSPropertyDecl *D); void VisitIndirectFieldDecl(IndirectFieldDecl *D); void VisitVarDecl(VarDecl *D); void VisitImplicitParamDecl(ImplicitParamDecl *D); @@ -102,6 +103,7 @@ namespace clang { void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitBlockDecl(BlockDecl *D); + void VisitCapturedDecl(CapturedDecl *D); void VisitEmptyDecl(EmptyDecl *D); void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, @@ -123,6 +125,7 @@ namespace clang { void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); }; } @@ -253,6 +256,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) { !D->isModulePrivate() && !CXXRecordDecl::classofKind(D->getKind()) && !D->getIntegerTypeSourceInfo() && + !D->getMemberSpecializationInfo() && D->getDeclName().getNameKind() == DeclarationName::Identifier) AbbrevToUse = Writer.getDeclEnumAbbrev(); @@ -317,7 +321,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { // after everything else is written. Record.push_back(D->getStorageClass()); // FIXME: stable encoding - Record.push_back(D->getStorageClassAsWritten()); Record.push_back(D->IsInline); Record.push_back(D->isInlineSpecified()); Record.push_back(D->isVirtualAsWritten()); @@ -610,6 +613,7 @@ void ASTDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); Writer.AddDeclRef(D->getSuperClass(), Record); + Writer.AddSourceLocation(D->getSuperClassLoc(), Record); Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record); Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record); Record.push_back(D->hasNonZeroConstructors()); @@ -661,6 +665,13 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { Code = serialization::DECL_FIELD; } +void ASTDeclWriter::VisitMSPropertyDecl(MSPropertyDecl *D) { + VisitDeclaratorDecl(D); + Writer.AddIdentifierRef(D->getGetterId(), Record); + Writer.AddIdentifierRef(D->getSetterId(), Record); + Code = serialization::DECL_MS_PROPERTY; +} + void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { VisitValueDecl(D); Record.push_back(D->getChainingSize()); @@ -675,9 +686,8 @@ void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { void ASTDeclWriter::VisitVarDecl(VarDecl *D) { VisitRedeclarable(D); VisitDeclaratorDecl(D); - Record.push_back(D->getStorageClass()); // FIXME: stable encoding - Record.push_back(D->getStorageClassAsWritten()); - Record.push_back(D->isThreadSpecified()); + Record.push_back(D->getStorageClass()); + Record.push_back(D->getTSCSpec()); Record.push_back(D->getInitStyle()); Record.push_back(D->isExceptionVariable()); Record.push_back(D->isNRVOVariable()); @@ -766,7 +776,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { // Check things we know are true of *every* PARM_VAR_DECL, which is more than // just us assuming it. - assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread"); + assert(!D->getTSCSpec() && "PARM_VAR_DECL can't use TLS"); assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private"); assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var"); assert(D->getPreviousDecl() == 0 && "PARM_VAR_DECL can't be redecl"); @@ -816,6 +826,15 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) { Code = serialization::DECL_BLOCK; } +void ASTDeclWriter::VisitCapturedDecl(CapturedDecl *CD) { + Record.push_back(CD->getNumParams()); + VisitDecl(CD); + // Body is stored by VisitCapturedStmt. + for (unsigned i = 0; i < CD->getNumParams(); ++i) + Writer.AddDeclRef(CD->getParam(i), Record); + Code = serialization::DECL_CAPTURED; +} + void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { VisitDecl(D); Record.push_back(D->getLanguage()); @@ -1313,6 +1332,16 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { } +void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { + Record.push_back(D->varlist_size()); + VisitDecl(D); + for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(), + E = D->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); + Code = serialization::DECL_OMP_THREADPRIVATE; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// @@ -1505,8 +1534,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // VarDecl Abv->Add(BitCodeAbbrevOp(0)); // StorageClass - Abv->Add(BitCodeAbbrevOp(0)); // StorageClassAsWritten - Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified + Abv->Add(BitCodeAbbrevOp(0)); // getTSCSpec Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable @@ -1585,8 +1613,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // VarDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClassAsWritten - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isThreadSpecified + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getTSCSpec Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index ee9735c163..5f7ac01bae 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Lex/Token.h" #include "llvm/Bitcode/BitstreamWriter.h" using namespace clang; @@ -216,15 +217,19 @@ void ASTStmtWriter::VisitDeclStmt(DeclStmt *S) { Code = serialization::STMT_DECL; } -void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) { +void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) { VisitStmt(S); Record.push_back(S->getNumOutputs()); Record.push_back(S->getNumInputs()); Record.push_back(S->getNumClobbers()); Writer.AddSourceLocation(S->getAsmLoc(), Record); - Writer.AddSourceLocation(S->getRParenLoc(), Record); Record.push_back(S->isVolatile()); Record.push_back(S->isSimple()); +} + +void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) { + VisitAsmStmt(S); + Writer.AddSourceLocation(S->getRParenLoc(), Record); Writer.AddStmt(S->getAsmString()); // Outputs @@ -249,12 +254,72 @@ void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) { } void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) { - // FIXME: Statement writer not yet implemented for MS style inline asm. - VisitStmt(S); + VisitAsmStmt(S); + Writer.AddSourceLocation(S->getLBraceLoc(), Record); + Writer.AddSourceLocation(S->getEndLoc(), Record); + Record.push_back(S->getNumAsmToks()); + Writer.AddString(S->getAsmString(), Record); + + // Tokens + for (unsigned I = 0, N = S->getNumAsmToks(); I != N; ++I) { + Writer.AddToken(S->getAsmToks()[I], Record); + } + + // Clobbers + for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) { + Writer.AddString(S->getClobber(I), Record); + } + + // Outputs + for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { + Writer.AddStmt(S->getOutputExpr(I)); + Writer.AddString(S->getOutputConstraint(I), Record); + } + + // Inputs + for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) { + Writer.AddStmt(S->getInputExpr(I)); + Writer.AddString(S->getInputConstraint(I), Record); + } Code = serialization::STMT_MSASM; } +void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) { + VisitStmt(S); + // NumCaptures + Record.push_back(std::distance(S->capture_begin(), S->capture_end())); + + // CapturedDecl and captured region kind + Writer.AddDeclRef(S->getCapturedDecl(), Record); + Record.push_back(S->getCapturedRegionKind()); + + Writer.AddDeclRef(S->getCapturedRecordDecl(), Record); + + // Capture inits + for (CapturedStmt::capture_init_iterator I = S->capture_init_begin(), + E = S->capture_init_end(); + I != E; ++I) + Writer.AddStmt(*I); + + // Body + Writer.AddStmt(S->getCapturedStmt()); + + // Captures + for (CapturedStmt::capture_iterator I = S->capture_begin(), + E = S->capture_end(); + I != E; ++I) { + if (I->capturesThis()) + Writer.AddDeclRef(0, Record); + else + Writer.AddDeclRef(I->getCapturedVar(), Record); + Record.push_back(I->getCaptureKind()); + Writer.AddSourceLocation(I->getLocation(), Record); + } + + Code = serialization::STMT_CAPTURED; +} + void ASTStmtWriter::VisitExpr(Expr *E) { VisitStmt(E); Writer.AddTypeRef(E->getType(), Record); @@ -498,6 +563,7 @@ void ASTStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) { VisitExpr(E); Writer.AddStmt(E->getBase()); Writer.AddSourceLocation(E->getIsaMemberLoc(), Record); + Writer.AddSourceLocation(E->getOpLoc(), Record); Record.push_back(E->isArrow()); Code = serialization::EXPR_OBJC_ISA; } @@ -856,6 +922,7 @@ void ASTStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { VisitExpr(E); Writer.AddDeclRef(E->getDecl(), Record); Writer.AddSourceLocation(E->getLocation(), Record); + Writer.AddSourceLocation(E->getOpLoc(), Record); Writer.AddStmt(E->getBase()); Record.push_back(E->isArrow()); Record.push_back(E->isFreeIvar()); @@ -1214,6 +1281,13 @@ void ASTStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { Code = serialization::EXPR_CXX_DEFAULT_ARG; } +void ASTStmtWriter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + VisitExpr(E); + Writer.AddDeclRef(E->getField(), Record); + Writer.AddSourceLocation(E->getExprLoc(), Record); + Code = serialization::EXPR_CXX_DEFAULT_INIT; +} + void ASTStmtWriter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { VisitExpr(E); Writer.AddCXXTemporary(E->getTemporary(), Record); @@ -1532,6 +1606,16 @@ void ASTStmtWriter::VisitAsTypeExpr(AsTypeExpr *E) { //===----------------------------------------------------------------------===// // Microsoft Expressions and Statements. //===----------------------------------------------------------------------===// +void ASTStmtWriter::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { + VisitExpr(E); + Record.push_back(E->isArrow()); + Writer.AddStmt(E->getBaseExpr()); + Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record); + Writer.AddSourceLocation(E->getMemberLoc(), Record); + Writer.AddDeclRef(E->getPropertyDecl(), Record); + Code = serialization::EXPR_CXX_PROPERTY_REF_EXPR; +} + void ASTStmtWriter::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); Writer.AddSourceRange(E->getSourceRange(), Record); diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp index 60467964dd..32c2df3b88 100644 --- a/lib/Serialization/GeneratePCH.cpp +++ b/lib/Serialization/GeneratePCH.cpp @@ -55,10 +55,6 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { Buffer.clear(); } -PPMutationListener *PCHGenerator::GetPPMutationListener() { - return &Writer; -} - ASTMutationListener *PCHGenerator::GetASTMutationListener() { return &Writer; } diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp index 7d34f85fd8..b6693e40e5 100644 --- a/lib/Serialization/GlobalModuleIndex.cpp +++ b/lib/Serialization/GlobalModuleIndex.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/OnDiskHashTable.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/GlobalModuleIndex.h" +#include "clang/Serialization/Module.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallString.h" @@ -115,29 +116,16 @@ public: typedef OnDiskChainedHashTable<IdentifierIndexReaderTrait> IdentifierIndexTable; -/// \brief Module information as it was loaded from the index file. -struct LoadedModuleInfo { - const FileEntry *File; - SmallVector<unsigned, 2> Dependencies; - SmallVector<unsigned, 2> ImportedBy; -}; - } -GlobalModuleIndex::GlobalModuleIndex(FileManager &FileMgr, - llvm::MemoryBuffer *Buffer, +GlobalModuleIndex::GlobalModuleIndex(llvm::MemoryBuffer *Buffer, llvm::BitstreamCursor Cursor) : Buffer(Buffer), IdentifierIndex(), NumIdentifierLookups(), NumIdentifierLookupHits() { - typedef llvm::DenseMap<unsigned, LoadedModuleInfo> LoadedModulesMap; - LoadedModulesMap LoadedModules; - // Read the global index. - unsigned LargestID = 0; bool InGlobalIndexBlock = false; bool Done = false; - bool AnyOutOfDate = false; while (!Done) { llvm::BitstreamEntry Entry = Cursor.advance(); @@ -185,41 +173,36 @@ GlobalModuleIndex::GlobalModuleIndex(FileManager &FileMgr, case MODULE: { unsigned Idx = 0; unsigned ID = Record[Idx++]; - if (ID > LargestID) - LargestID = ID; - - off_t Size = Record[Idx++]; - time_t ModTime = Record[Idx++]; + + // Make room for this module's information. + if (ID == Modules.size()) + Modules.push_back(ModuleInfo()); + else + Modules.resize(ID + 1); + + // Size/modification time for this module file at the time the + // global index was built. + Modules[ID].Size = Record[Idx++]; + Modules[ID].ModTime = Record[Idx++]; // File name. unsigned NameLen = Record[Idx++]; - llvm::SmallString<64> FileName(Record.begin() + Idx, - Record.begin() + Idx + NameLen); + Modules[ID].FileName.assign(Record.begin() + Idx, + Record.begin() + Idx + NameLen); Idx += NameLen; // Dependencies unsigned NumDeps = Record[Idx++]; - llvm::SmallVector<unsigned, 2> - Dependencies(Record.begin() + Idx, Record.begin() + Idx + NumDeps); - - // Find the file. If we can't find it, ignore it. - const FileEntry *File = FileMgr.getFile(FileName, /*openFile=*/false, - /*cacheFailure=*/false); - if (!File) { - AnyOutOfDate = true; - break; - } + Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(), + Record.begin() + Idx, + Record.begin() + Idx + NumDeps); + Idx += NumDeps; - // If the module file is newer than the index, ignore it. - if (File->getSize() != Size || File->getModificationTime() != ModTime) { - AnyOutOfDate = true; - break; - } + // Make sure we're at the end of the record. + assert(Idx == Record.size() && "More module info?"); - // Record this module. The dependencies will be resolved later. - LoadedModuleInfo &Info = LoadedModules[ID]; - Info.File = File; - Info.Dependencies.swap(Dependencies); + // Record this module as an unresolved module. + UnresolvedModules[llvm::sys::path::stem(Modules[ID].FileName)] = ID; break; } @@ -234,91 +217,19 @@ GlobalModuleIndex::GlobalModuleIndex(FileManager &FileMgr, break; } } - - // If there are any modules that have gone out-of-date, prune out any modules - // that depend on them. - if (AnyOutOfDate) { - // First, build back links in the module dependency graph. - SmallVector<unsigned, 4> Stack; - for (LoadedModulesMap::iterator LM = LoadedModules.begin(), - LMEnd = LoadedModules.end(); - LM != LMEnd; ++LM) { - unsigned ID = LM->first; - - // If this module is out-of-date, push it onto the stack. - if (LM->second.File == 0) - Stack.push_back(ID); - - for (unsigned I = 0, N = LM->second.Dependencies.size(); I != N; ++I) { - unsigned DepID = LM->second.Dependencies[I]; - LoadedModulesMap::iterator Known = LoadedModules.find(DepID); - if (Known == LoadedModules.end() || !Known->second.File) { - // The dependency was out-of-date, so mark us as out of date. - // This is just an optimization. - if (LM->second.File) - Stack.push_back(ID); - - LM->second.File = 0; - continue; - } - - // Record this reverse dependency. - Known->second.ImportedBy.push_back(ID); - } - } - - // Second, walk the back links from out-of-date modules to those modules - // that depend on them, making those modules out-of-date as well. - while (!Stack.empty()) { - unsigned ID = Stack.back(); - Stack.pop_back(); - - LoadedModuleInfo &Info = LoadedModules[ID]; - for (unsigned I = 0, N = Info.ImportedBy.size(); I != N; ++I) { - unsigned FromID = Info.ImportedBy[I]; - if (LoadedModules[FromID].File) { - LoadedModules[FromID].File = 0; - Stack.push_back(FromID); - } - } - } - } - - // Allocate the vector containing information about all of the modules. - Modules.resize(LargestID + 1); - for (LoadedModulesMap::iterator LM = LoadedModules.begin(), - LMEnd = LoadedModules.end(); - LM != LMEnd; ++LM) { - if (!LM->second.File) - continue; - - Modules[LM->first].File = LM->second.File; - - // Resolve dependencies. Drop any we can't resolve due to out-of-date - // module files. - for (unsigned I = 0, N = LM->second.Dependencies.size(); I != N; ++I) { - unsigned DepID = LM->second.Dependencies[I]; - LoadedModulesMap::iterator Known = LoadedModules.find(DepID); - if (Known == LoadedModules.end() || !Known->second.File) - continue; - - Modules[LM->first].Dependencies.push_back(Known->second.File); - } - } } GlobalModuleIndex::~GlobalModuleIndex() { } std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode> -GlobalModuleIndex::readIndex(FileManager &FileMgr, StringRef Path) { +GlobalModuleIndex::readIndex(StringRef Path) { // Load the index file, if it's there. llvm::SmallString<128> IndexPath; IndexPath += Path; llvm::sys::path::append(IndexPath, IndexFileName); - llvm::OwningPtr<llvm::MemoryBuffer> Buffer( - FileMgr.getBufferForFile(IndexPath)); - if (!Buffer) + llvm::OwningPtr<llvm::MemoryBuffer> Buffer; + if (llvm::MemoryBuffer::getFile(IndexPath, Buffer) != llvm::errc::success) return std::make_pair((GlobalModuleIndex *)0, EC_NotFound); /// \brief The bitstream reader from which we'll read the AST file. @@ -336,38 +247,34 @@ GlobalModuleIndex::readIndex(FileManager &FileMgr, StringRef Path) { return std::make_pair((GlobalModuleIndex *)0, EC_IOError); } - return std::make_pair(new GlobalModuleIndex(FileMgr, Buffer.take(), Cursor), - EC_None); + return std::make_pair(new GlobalModuleIndex(Buffer.take(), Cursor), EC_None); } -void GlobalModuleIndex::getKnownModules( - SmallVectorImpl<const FileEntry *> &ModuleFiles) { +void +GlobalModuleIndex::getKnownModules(SmallVectorImpl<ModuleFile *> &ModuleFiles) { ModuleFiles.clear(); for (unsigned I = 0, N = Modules.size(); I != N; ++I) { - if (Modules[I].File) - ModuleFiles.push_back(Modules[I].File); + if (ModuleFile *MF = Modules[I].File) + ModuleFiles.push_back(MF); } } void GlobalModuleIndex::getModuleDependencies( - const clang::FileEntry *ModuleFile, - SmallVectorImpl<const clang::FileEntry *> &Dependencies) { - // If the file -> index mapping is empty, populate it now. - if (ModulesByFile.empty()) { - for (unsigned I = 0, N = Modules.size(); I != N; ++I) { - if (Modules[I].File) - ModulesByFile[Modules[I].File] = I; - } - } - + ModuleFile *File, + SmallVectorImpl<ModuleFile *> &Dependencies) { // Look for information about this module file. - llvm::DenseMap<const FileEntry *, unsigned>::iterator Known - = ModulesByFile.find(ModuleFile); + llvm::DenseMap<ModuleFile *, unsigned>::iterator Known + = ModulesByFile.find(File); if (Known == ModulesByFile.end()) return; // Record dependencies. - Dependencies = Modules[Known->second].Dependencies; + Dependencies.clear(); + ArrayRef<unsigned> StoredDependencies = Modules[Known->second].Dependencies; + for (unsigned I = 0, N = StoredDependencies.size(); I != N; ++I) { + if (ModuleFile *MF = Modules[I].File) + Dependencies.push_back(MF); + } } bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) { @@ -388,17 +295,41 @@ bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) { SmallVector<unsigned, 2> ModuleIDs = *Known; for (unsigned I = 0, N = ModuleIDs.size(); I != N; ++I) { - unsigned ID = ModuleIDs[I]; - if (ID >= Modules.size() || !Modules[ID].File) - continue; - - Hits.insert(Modules[ID].File); + if (ModuleFile *MF = Modules[ModuleIDs[I]].File) + Hits.insert(MF); } ++NumIdentifierLookupHits; return true; } +bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) { + // Look for the module in the global module index based on the module name. + StringRef Name = llvm::sys::path::stem(File->FileName); + llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name); + if (Known == UnresolvedModules.end()) { + return true; + } + + // Rectify this module with the global module index. + ModuleInfo &Info = Modules[Known->second]; + + // If the size and modification time match what we expected, record this + // module file. + bool Failed = true; + if (File->File->getSize() == Info.Size && + File->File->getModificationTime() == Info.ModTime) { + Info.File = File; + ModulesByFile[File] = Known->second; + + Failed = false; + } + + // One way or another, we have resolved this module file. + UnresolvedModules.erase(Known); + return Failed; +} + void GlobalModuleIndex::printStats() { std::fprintf(stderr, "*** Global Module Index Statistics:\n"); if (NumIdentifierLookups) { @@ -629,6 +560,10 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { // Skip the import location ++Idx; + // Load stored size/modification time. + off_t StoredSize = (off_t)Record[Idx++]; + time_t StoredModTime = (time_t)Record[Idx++]; + // Retrieve the imported file name. unsigned Length = Record[Idx++]; SmallString<128> ImportedFile(Record.begin() + Idx, @@ -639,7 +574,9 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { const FileEntry *DependsOnFile = FileMgr.getFile(ImportedFile, /*openFile=*/false, /*cacheFailure=*/false); - if (!DependsOnFile) + if (!DependsOnFile || + (StoredSize != DependsOnFile->getSize()) || + (StoredModTime != DependsOnFile->getModificationTime())) return true; // Record the dependency. @@ -881,3 +818,34 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr, StringRef Path) { // We're done. return EC_None; } + +namespace { + class GlobalIndexIdentifierIterator : public IdentifierIterator { + /// \brief The current position within the identifier lookup table. + IdentifierIndexTable::key_iterator Current; + + /// \brief The end position within the identifier lookup table. + IdentifierIndexTable::key_iterator End; + + public: + explicit GlobalIndexIdentifierIterator(IdentifierIndexTable &Idx) { + Current = Idx.key_begin(); + End = Idx.key_end(); + } + + virtual StringRef Next() { + if (Current == End) + return StringRef(); + + StringRef Result = *Current; + ++Current; + return Result; + } + }; +} + +IdentifierIterator *GlobalModuleIndex::createIdentifierIterator() const { + IdentifierIndexTable &Table = + *static_cast<IdentifierIndexTable *>(IdentifierIndex); + return new GlobalIndexIdentifierIterator(Table); +} diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp index b9f4d888f3..f3d53adafa 100644 --- a/lib/Serialization/ModuleManager.cpp +++ b/lib/Serialization/ModuleManager.cpp @@ -11,9 +11,11 @@ // modules for the ASTReader. // //===----------------------------------------------------------------------===// +#include "clang/Lex/ModuleMap.h" #include "clang/Serialization/ModuleManager.h" #include "clang/Serialization/GlobalModuleIndex.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PathV2.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" @@ -27,7 +29,19 @@ using namespace serialization; ModuleFile *ModuleManager::lookup(StringRef Name) { const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false, /*cacheFailure=*/false); - return Modules[Entry]; + if (Entry) + return lookup(Entry); + + return 0; +} + +ModuleFile *ModuleManager::lookup(const FileEntry *File) { + llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known + = Modules.find(File); + if (Known == Modules.end()) + return 0; + + return Known->second; } llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) { @@ -36,18 +50,27 @@ llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) { return InMemoryBuffers[Entry]; } -std::pair<ModuleFile *, bool> +ModuleManager::AddModuleResult ModuleManager::addModule(StringRef FileName, ModuleKind Type, SourceLocation ImportLoc, ModuleFile *ImportedBy, - unsigned Generation, std::string &ErrorStr) { - const FileEntry *Entry = FileMgr.getFile(FileName, /*openFile=*/false, - /*cacheFailure=*/false); + unsigned Generation, + off_t ExpectedSize, time_t ExpectedModTime, + ModuleFile *&Module, + std::string &ErrorStr) { + Module = 0; + + // Look for the file entry. This only fails if the expected size or + // modification time differ. + const FileEntry *Entry; + if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) + return OutOfDate; + if (!Entry && FileName != "-") { ErrorStr = "file not found"; - return std::make_pair(static_cast<ModuleFile*>(0), false); + return Missing; } - - // Check whether we already loaded this module, before + + // Check whether we already loaded this module, before ModuleFile *&ModuleEntry = Modules[Entry]; bool NewModule = false; if (!ModuleEntry) { @@ -77,12 +100,13 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr)); if (!New->Buffer) - return std::make_pair(static_cast<ModuleFile*>(0), false); + return Missing; } // Initialize the stream New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(), - (const unsigned char *)New->Buffer->getBufferEnd()); } + (const unsigned char *)New->Buffer->getBufferEnd()); + } if (ImportedBy) { ModuleEntry->ImportedBy.insert(ImportedBy); @@ -93,8 +117,9 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, ModuleEntry->DirectlyImported = true; } - - return std::make_pair(ModuleEntry, NewModule); + + Module = ModuleEntry; + return NewModule? NewlyLoaded : AlreadyLoaded; } namespace { @@ -113,7 +138,8 @@ namespace { }; } -void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) { +void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last, + ModuleMap *modMap) { if (first == last) return; @@ -129,6 +155,14 @@ void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) { // Delete the modules and erase them from the various structures. for (ModuleIterator victim = first; victim != last; ++victim) { Modules.erase((*victim)->File); + + FileMgr.invalidateCache((*victim)->File); + if (modMap) { + StringRef ModuleName = llvm::sys::path::stem((*victim)->FileName); + if (Module *mod = modMap->findModule(ModuleName)) { + mod->setASTFile(0); + } + } delete *victim; } @@ -144,27 +178,6 @@ void ModuleManager::addInMemoryBuffer(StringRef FileName, InMemoryBuffers[Entry] = Buffer; } -void ModuleManager::updateModulesInCommonWithGlobalIndex() { - ModulesInCommonWithGlobalIndex.clear(); - - if (!GlobalIndex) - return; - - // Collect the set of modules known to the global index. - SmallVector<const FileEntry *, 16> KnownModules; - GlobalIndex->getKnownModules(KnownModules); - - // Map those modules to AST files known to the module manager. - for (unsigned I = 0, N = KnownModules.size(); I != N; ++I) { - llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known - = Modules.find(KnownModules[I]); - if (Known == Modules.end()) - continue; - - ModulesInCommonWithGlobalIndex.push_back(Known->second); - } -} - ModuleManager::VisitState *ModuleManager::allocateVisitState() { // Fast path: if we have a cached state, use it. if (FirstVisitState) { @@ -186,7 +199,25 @@ void ModuleManager::returnVisitState(VisitState *State) { void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) { GlobalIndex = Index; - updateModulesInCommonWithGlobalIndex(); + if (!GlobalIndex) { + ModulesInCommonWithGlobalIndex.clear(); + return; + } + + // Notify the global module index about all of the modules we've already + // loaded. + for (unsigned I = 0, N = Chain.size(); I != N; ++I) { + if (!GlobalIndex->loadedModuleFile(Chain[I])) { + ModulesInCommonWithGlobalIndex.push_back(Chain[I]); + } + } +} + +void ModuleManager::moduleFileAccepted(ModuleFile *MF) { + if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF)) + return; + + ModulesInCommonWithGlobalIndex.push_back(MF); } ModuleManager::ModuleManager(FileManager &FileMgr) @@ -201,7 +232,7 @@ ModuleManager::~ModuleManager() { void ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), void *UserData, - llvm::SmallPtrSet<const FileEntry *, 4> *ModuleFilesHit) { + llvm::SmallPtrSet<ModuleFile *, 4> *ModuleFilesHit) { // If the visitation order vector is the wrong size, recompute the order. if (VisitOrder.size() != Chain.size()) { unsigned N = size(); @@ -249,11 +280,6 @@ ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), assert(VisitOrder.size() == N && "Visitation order is wrong?"); - // We may need to update the set of modules we have in common with the - // global module index, since modules could have been added to the module - // manager since we loaded the global module index. - updateModulesInCommonWithGlobalIndex(); - delete FirstVisitState; FirstVisitState = 0; } @@ -268,7 +294,7 @@ ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I) { ModuleFile *M = ModulesInCommonWithGlobalIndex[I]; - if (!ModuleFilesHit->count(M->File)) + if (!ModuleFilesHit->count(M)) State->VisitNumber[M->Index] = VisitNumber; } } @@ -354,6 +380,24 @@ void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder } } +bool ModuleManager::lookupModuleFile(StringRef FileName, + off_t ExpectedSize, + time_t ExpectedModTime, + const FileEntry *&File) { + File = FileMgr.getFile(FileName, /*openFile=*/false, /*cacheFailure=*/false); + + if (!File && FileName != "-") { + return false; + } + + if ((ExpectedSize && ExpectedSize != File->getSize()) || + (ExpectedModTime && ExpectedModTime != File->getModificationTime())) { + return true; + } + + return false; +} + #ifndef NDEBUG namespace llvm { template<> diff --git a/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.cpp b/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.cpp new file mode 100644 index 0000000000..3dec8a58c9 --- /dev/null +++ b/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.cpp @@ -0,0 +1,24 @@ +//=- AllocationDiagnostics.cpp - Config options for allocation diags *- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Declares the configuration functions for leaks/allocation diagnostics. +// +//===-------------------------- + +#include "AllocationDiagnostics.h" + +namespace clang { +namespace ento { + +bool shouldIncludeAllocationSiteInLeakDiagnostics(AnalyzerOptions &AOpts) { + return AOpts.getBooleanOption("leak-diagnostics-reference-allocation", + false); +} + +}} diff --git a/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.h b/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.h new file mode 100644 index 0000000000..2b314a3b74 --- /dev/null +++ b/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.h @@ -0,0 +1,31 @@ +//=--- AllocationDiagnostics.h - Config options for allocation diags *- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Declares the configuration functions for leaks/allocation diagnostics. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_LIB_CHECKERS_ALLOC_DIAGS_H +#define LLVM_CLANG_SA_LIB_CHECKERS_ALLOC_DIAGS_H + +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" + +namespace clang { namespace ento { + +/// \brief Returns true if leak diagnostics should directly reference +/// the allocatin site (where possible). +/// +/// The default is false. +/// +bool shouldIncludeAllocationSiteInLeakDiagnostics(AnalyzerOptions &AOpts); + +}} + +#endif + diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index fdb6bbbe52..fba14a0fc4 100644 --- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -83,10 +83,6 @@ static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) { return result; } -static inline bool isNil(SVal X) { - return X.getAs<loc::ConcreteInt>().hasValue(); -} - //===----------------------------------------------------------------------===// // NilArgChecker - Check for prohibited nil arguments to ObjC method calls. //===----------------------------------------------------------------------===// @@ -95,29 +91,66 @@ namespace { class NilArgChecker : public Checker<check::PreObjCMessage> { mutable OwningPtr<APIMisuse> BT; - void WarnNilArg(CheckerContext &C, - const ObjCMethodCall &msg, unsigned Arg) const; + void WarnIfNilArg(CheckerContext &C, + const ObjCMethodCall &msg, unsigned Arg, + FoundationClass Class, + bool CanBeSubscript = false) const; public: void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; }; } -void NilArgChecker::WarnNilArg(CheckerContext &C, - const ObjCMethodCall &msg, - unsigned int Arg) const -{ +void NilArgChecker::WarnIfNilArg(CheckerContext &C, + const ObjCMethodCall &msg, + unsigned int Arg, + FoundationClass Class, + bool CanBeSubscript) const { + // Check if the argument is nil. + ProgramStateRef State = C.getState(); + if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue()) + return; + if (!BT) BT.reset(new APIMisuse("nil argument")); - + if (ExplodedNode *N = C.generateSink()) { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); - os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '" - << msg.getSelector().getAsString() << "' cannot be nil"; + + if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) { + + if (Class == FC_NSArray) { + os << "Array element cannot be nil"; + } else if (Class == FC_NSDictionary) { + if (Arg == 0) { + os << "Value stored into '"; + os << GetReceiverInterfaceName(msg) << "' cannot be nil"; + } else { + assert(Arg == 1); + os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil"; + } + } else + llvm_unreachable("Missing foundation class for the subscript expr"); + + } else { + if (Class == FC_NSDictionary) { + if (Arg == 0) + os << "Value argument "; + else { + assert(Arg == 1); + os << "Key argument "; + } + os << "to '" << msg.getSelector().getAsString() << "' cannot be nil"; + } else { + os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '" + << msg.getSelector().getAsString() << "' cannot be nil"; + } + } BugReport *R = new BugReport(*BT, os.str(), N); R->addRange(msg.getArgSourceRange(Arg)); + bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R); C.emitReport(R); } } @@ -127,8 +160,14 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, const ObjCInterfaceDecl *ID = msg.getReceiverInterface(); if (!ID) return; + + FoundationClass Class = findKnownClass(ID); + + static const unsigned InvalidArgIndex = UINT_MAX; + unsigned Arg = InvalidArgIndex; + bool CanBeSubscript = false; - if (findKnownClass(ID) == FC_NSString) { + if (Class == FC_NSString) { Selector S = msg.getSelector(); if (S.isUnarySelector()) @@ -152,10 +191,58 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, Name == "compare:options:range:locale:" || Name == "componentsSeparatedByCharactersInSet:" || Name == "initWithFormat:") { - if (isNil(msg.getArgSVal(0))) - WarnNilArg(C, msg, 0); + Arg = 0; + } + } else if (Class == FC_NSArray) { + Selector S = msg.getSelector(); + + if (S.isUnarySelector()) + return; + + if (S.getNameForSlot(0).equals("addObject")) { + Arg = 0; + } else if (S.getNameForSlot(0).equals("insertObject") && + S.getNameForSlot(1).equals("atIndex")) { + Arg = 0; + } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") && + S.getNameForSlot(1).equals("withObject")) { + Arg = 1; + } else if (S.getNameForSlot(0).equals("setObject") && + S.getNameForSlot(1).equals("atIndexedSubscript")) { + Arg = 0; + CanBeSubscript = true; + } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) { + Arg = 0; + } + } else if (Class == FC_NSDictionary) { + Selector S = msg.getSelector(); + + if (S.isUnarySelector()) + return; + + if (S.getNameForSlot(0).equals("dictionaryWithObject") && + S.getNameForSlot(1).equals("forKey")) { + Arg = 0; + WarnIfNilArg(C, msg, /* Arg */1, Class); + } else if (S.getNameForSlot(0).equals("setObject") && + S.getNameForSlot(1).equals("forKey")) { + Arg = 0; + WarnIfNilArg(C, msg, /* Arg */1, Class); + } else if (S.getNameForSlot(0).equals("setObject") && + S.getNameForSlot(1).equals("forKeyedSubscript")) { + CanBeSubscript = true; + Arg = 0; + WarnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript); + } else if (S.getNameForSlot(0).equals("removeObjectForKey")) { + Arg = 0; } } + + + // If argument is '0', report a warning. + if ((Arg != InvalidArgIndex)) + WarnIfNilArg(C, msg, Arg, Class, CanBeSubscript); + } //===----------------------------------------------------------------------===// @@ -301,7 +388,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, // FIXME: If the pointee isn't an integer type, should we flag a warning? // People can do weird stuff with pointers. - if (!T->isIntegerType()) + if (!T->isIntegralOrEnumerationType()) return; uint64_t SourceSize = Ctx.getTypeSize(T); @@ -672,38 +759,81 @@ static bool isKnownNonNilCollectionType(QualType T) { } } -void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS, - CheckerContext &C) const { - ProgramStateRef State = C.getState(); - - // Check if this is the branch for the end of the loop. - SVal CollectionSentinel = State->getSVal(FCS, C.getLocationContext()); - if (CollectionSentinel.isZeroConstant()) - return; - +/// Assumes that the collection is non-nil. +/// +/// If the collection is known to be nil, returns NULL to indicate an infeasible +/// path. +static ProgramStateRef checkCollectionNonNil(CheckerContext &C, + ProgramStateRef State, + const ObjCForCollectionStmt *FCS) { + if (!State) + return NULL; + + SVal CollectionVal = C.getSVal(FCS->getCollection()); + Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>(); + if (!KnownCollection) + return State; + + ProgramStateRef StNonNil, StNil; + llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection); + if (StNil && !StNonNil) { + // The collection is nil. This path is infeasible. + return NULL; + } + + return StNonNil; +} + +/// Assumes that the collection elements are non-nil. +/// +/// This only applies if the collection is one of those known not to contain +/// nil values. +static ProgramStateRef checkElementNonNil(CheckerContext &C, + ProgramStateRef State, + const ObjCForCollectionStmt *FCS) { + if (!State) + return NULL; + // See if the collection is one where we /know/ the elements are non-nil. - const Expr *Collection = FCS->getCollection(); - if (!isKnownNonNilCollectionType(Collection->getType())) - return; - - // FIXME: Copied from ExprEngineObjC. + if (!isKnownNonNilCollectionType(FCS->getCollection()->getType())) + return State; + + const LocationContext *LCtx = C.getLocationContext(); const Stmt *Element = FCS->getElement(); - SVal ElementVar; + + // FIXME: Copied from ExprEngineObjC. + Optional<Loc> ElementLoc; if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) { const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl()); assert(ElemDecl->getInit() == 0); - ElementVar = State->getLValue(ElemDecl, C.getLocationContext()); + ElementLoc = State->getLValue(ElemDecl, LCtx); } else { - ElementVar = State->getSVal(Element, C.getLocationContext()); + ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>(); } - if (!ElementVar.getAs<Loc>()) - return; + if (!ElementLoc) + return State; // Go ahead and assume the value is non-nil. - SVal Val = State->getSVal(ElementVar.castAs<Loc>()); - State = State->assume(Val.castAs<DefinedOrUnknownSVal>(), true); - C.addTransition(State); + SVal Val = State->getSVal(*ElementLoc); + return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true); +} + +void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS, + CheckerContext &C) const { + // Check if this is the branch for the end of the loop. + SVal CollectionSentinel = C.getSVal(FCS); + if (CollectionSentinel.isZeroConstant()) + return; + + ProgramStateRef State = C.getState(); + State = checkCollectionNonNil(C, State, FCS); + State = checkElementNonNil(C, State, FCS); + + if (!State) + C.generateSink(); + else if (State != C.getState()) + C.addTransition(State); } namespace { diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt index b7df10e7ff..7da6825106 100644 --- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -4,6 +4,7 @@ clang_tablegen(Checkers.inc -gen-clang-sa-checkers TARGET ClangSACheckers) add_clang_library(clangStaticAnalyzerCheckers + AllocationDiagnostics.cpp AnalyzerStatsChecker.cpp ArrayBoundChecker.cpp ArrayBoundCheckerV2.cpp @@ -42,8 +43,8 @@ add_clang_library(clangStaticAnalyzerCheckers MallocSizeofChecker.cpp NSAutoreleasePoolChecker.cpp NSErrorChecker.cpp - NonNullParamChecker.cpp NoReturnFunctionChecker.cpp + NonNullParamChecker.cpp ObjCAtSyncChecker.cpp ObjCContainersASTChecker.cpp ObjCContainersChecker.cpp diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index cc55e9f6ec..aa1ca6f2f8 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -114,6 +114,8 @@ public: bool isBounded = false, bool ignoreCase = false) const; + void evalStrsep(CheckerContext &C, const CallExpr *CE) const; + // Utility methods std::pair<ProgramStateRef , ProgramStateRef > static assumeZero(CheckerContext &C, @@ -1752,6 +1754,63 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, C.addTransition(state); } +void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const { + //char *strsep(char **stringp, const char *delim); + if (CE->getNumArgs() < 2) + return; + + // Sanity: does the search string parameter match the return type? + const Expr *SearchStrPtr = CE->getArg(0); + QualType CharPtrTy = SearchStrPtr->getType()->getPointeeType(); + if (CharPtrTy.isNull() || + CE->getType().getUnqualifiedType() != CharPtrTy.getUnqualifiedType()) + return; + + CurrentFunctionDescription = "strsep()"; + ProgramStateRef State = C.getState(); + const LocationContext *LCtx = C.getLocationContext(); + + // Check that the search string pointer is non-null (though it may point to + // a null string). + SVal SearchStrVal = State->getSVal(SearchStrPtr, LCtx); + State = checkNonNull(C, State, SearchStrPtr, SearchStrVal); + if (!State) + return; + + // Check that the delimiter string is non-null. + const Expr *DelimStr = CE->getArg(1); + SVal DelimStrVal = State->getSVal(DelimStr, LCtx); + State = checkNonNull(C, State, DelimStr, DelimStrVal); + if (!State) + return; + + SValBuilder &SVB = C.getSValBuilder(); + SVal Result; + if (Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) { + // Get the current value of the search string pointer, as a char*. + Result = State->getSVal(*SearchStrLoc, CharPtrTy); + + // Invalidate the search string, representing the change of one delimiter + // character to NUL. + State = InvalidateBuffer(C, State, SearchStrPtr, Result); + + // Overwrite the search string pointer. The new value is either an address + // further along in the same string, or NULL if there are no more tokens. + State = State->bindLoc(*SearchStrLoc, + SVB.conjureSymbolVal(getTag(), CE, LCtx, CharPtrTy, + C.blockCount())); + } else { + assert(SearchStrVal.isUnknown()); + // Conjure a symbolic value. It's the best we can do. + Result = SVB.conjureSymbolVal(0, CE, LCtx, C.blockCount()); + } + + // Set the return value, and finish. + State = State->BindExpr(CE, LCtx, Result); + C.addTransition(State); +} + + //===----------------------------------------------------------------------===// // The driver method, and other Checker callbacks. //===----------------------------------------------------------------------===// @@ -1762,6 +1821,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { if (!FDecl) return false; + // FIXME: Poorly-factored string switches are slow. FnCheck evalFunction = 0; if (C.isCLibraryFunction(FDecl, "memcpy")) evalFunction = &CStringChecker::evalMemcpy; @@ -1793,6 +1853,8 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { evalFunction = &CStringChecker::evalStrcasecmp; else if (C.isCLibraryFunction(FDecl, "strncasecmp")) evalFunction = &CStringChecker::evalStrncasecmp; + else if (C.isCLibraryFunction(FDecl, "strsep")) + evalFunction = &CStringChecker::evalStrsep; else if (C.isCLibraryFunction(FDecl, "bcopy")) evalFunction = &CStringChecker::evalBcopy; else if (C.isCLibraryFunction(FDecl, "bcmp")) diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp index 3a57a56aea..92c0eef3e8 100644 --- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp @@ -101,6 +101,8 @@ public: // - strncat(dst, src, sizeof(dst) - 1); // - strncat(dst, src, sizeof(dst)); bool WalkAST::containsBadStrncatPattern(const CallExpr *CE) { + if (CE->getNumArgs() != 3) + return false; const Expr *DstArg = CE->getArg(0); const Expr *SrcArg = CE->getArg(1); const Expr *LenArg = CE->getArg(2); diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 37e203df8e..4965d22996 100644 --- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -366,17 +366,23 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, if (!BT_msg_ret) BT_msg_ret.reset( - new BuiltinBug("Receiver in message expression is " - "'nil' and returns a garbage value")); + new BuiltinBug("Receiver in message expression is 'nil'")); const ObjCMessageExpr *ME = msg.getOriginExpr(); + QualType ResTy = msg.getResultType(); + SmallString<200> buf; llvm::raw_svector_ostream os(buf); os << "The receiver of message '" << ME->getSelector().getAsString() - << "' is nil and returns a value of type '"; - msg.getResultType().print(os, C.getLangOpts()); - os << "' that will be garbage"; + << "' is nil"; + if (ResTy->isReferenceType()) { + os << ", which results in forming a null reference"; + } else { + os << " and returns a value of type '"; + msg.getResultType().print(os, C.getLangOpts()); + os << "' that will be garbage"; + } BugReport *report = new BugReport(*BT_msg_ret, os.str(), N); report->addRange(ME->getReceiverRange()); @@ -397,6 +403,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, ProgramStateRef state, const ObjCMethodCall &Msg) const { ASTContext &Ctx = C.getASTContext(); + static SimpleProgramPointTag Tag("CallAndMessageChecker : NilReceiver"); // Check the return type of the message expression. A message to nil will // return different values depending on the return type and the architecture. @@ -407,7 +414,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, if (CanRetTy->isStructureOrClassType()) { // Structure returns are safe since the compiler zeroes them out. SVal V = C.getSValBuilder().makeZeroVal(RetTy); - C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V)); + C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag); return; } @@ -418,14 +425,15 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); - if (voidPtrSize < returnTypeSize && - !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) && - (Ctx.FloatTy == CanRetTy || - Ctx.DoubleTy == CanRetTy || - Ctx.LongDoubleTy == CanRetTy || - Ctx.LongLongTy == CanRetTy || - Ctx.UnsignedLongLongTy == CanRetTy))) { - if (ExplodedNode *N = C.generateSink(state)) + if (CanRetTy.getTypePtr()->isReferenceType()|| + (voidPtrSize < returnTypeSize && + !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) && + (Ctx.FloatTy == CanRetTy || + Ctx.DoubleTy == CanRetTy || + Ctx.LongDoubleTy == CanRetTy || + Ctx.LongLongTy == CanRetTy || + Ctx.UnsignedLongLongTy == CanRetTy)))) { + if (ExplodedNode *N = C.generateSink(state, 0 , &Tag)) emitNilReceiverBug(C, Msg, N); return; } @@ -444,7 +452,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, // of this case unless we have *a lot* more knowledge. // SVal V = C.getSValBuilder().makeZeroVal(RetTy); - C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V)); + C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag); return; } diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index 7ef13ab538..63080ea230 100644 --- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -345,7 +345,7 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { return; // Verify the first argument type is integer. - if (!FPT->getArgType(0)->isIntegerType()) + if (!FPT->getArgType(0)->isIntegralOrUnscopedEnumerationType()) return; // Verify the second argument type is char*. @@ -602,7 +602,7 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) { if (!PT) return; - if (! PT->getPointeeType()->isIntegerType()) + if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType()) return; } else if (FTP->getNumArgs() != 0) @@ -725,7 +725,7 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) { // The arguments must be integers. for (unsigned i = 0; i < FTP->getNumArgs(); i++) - if (! FTP->getArgType(i)->isIntegerType()) + if (! FTP->getArgType(i)->isIntegralOrUnscopedEnumerationType()) return; // Issue a warning. diff --git a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp index ed89788e90..a9dd19a395 100644 --- a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp @@ -52,6 +52,7 @@ class CheckerDocumentation : public Checker< check::PreStmt<ReturnStmt>, check::LiveSymbols, check::RegionChanges, check::PointerEscape, + check::ConstPointerEscape, check::Event<ImplicitNullDerefEvent>, check::ASTDecl<FunctionDecl> > { public: @@ -274,6 +275,17 @@ public: return State; } + /// \brief Called when const pointers escape. + /// + /// Note: in most cases checkPointerEscape callback is sufficient. + /// \sa checkPointerEscape + ProgramStateRef checkConstPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call, + PointerEscapeKind Kind) const { + return State; + } + /// check::Event<ImplicitNullDerefEvent> void checkEvent(ImplicitNullDerefEvent Event) const {} diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td index bbcf9aa438..fc35b223ee 100644 --- a/lib/StaticAnalyzer/Checkers/Checkers.td +++ b/lib/StaticAnalyzer/Checkers/Checkers.td @@ -166,12 +166,24 @@ def ReturnUndefChecker : Checker<"UndefReturn">, // C++ checkers. //===----------------------------------------------------------------------===// +let ParentPackage = Cplusplus in { + +def NewDeleteChecker : Checker<"NewDelete">, + HelpText<"Check for double-free and use-after-free problems. Traces memory managed by new/delete.">, + DescFile<"MallocChecker.cpp">; + +} // end: "cplusplus" + let ParentPackage = CplusplusAlpha in { def VirtualCallChecker : Checker<"VirtualCall">, HelpText<"Check virtual function calls during construction or destruction">, DescFile<"VirtualCallChecker.cpp">; +def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">, + HelpText<"Check for memory leaks. Traces memory managed by new/delete.">, + DescFile<"MallocChecker.cpp">; + } // end: "alpha.cplusplus" //===----------------------------------------------------------------------===// @@ -276,12 +288,16 @@ def UnixAPIChecker : Checker<"API">, DescFile<"UnixAPIChecker.cpp">; def MallocPessimistic : Checker<"Malloc">, - HelpText<"Check for memory leaks, double free, and use-after-free problems.">, + HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().">, DescFile<"MallocChecker.cpp">; def MallocSizeofChecker : Checker<"MallocSizeof">, HelpText<"Check for dubious malloc arguments involving sizeof">, DescFile<"MallocSizeofChecker.cpp">; + +def MismatchedDeallocatorChecker : Checker<"MismatchedDeallocator">, + HelpText<"Check for mismatched deallocators.">, + DescFile<"MallocChecker.cpp">; } // end "unix" @@ -292,7 +308,7 @@ def ChrootChecker : Checker<"Chroot">, DescFile<"ChrootChecker.cpp">; def MallocOptimistic : Checker<"MallocWithAnnotations">, - HelpText<"Check for memory leaks, double free, and use-after-free problems. Assumes that all user-defined functions which might free a pointer are annotated.">, + HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free(). Assumes that all user-defined functions which might free a pointer are annotated.">, DescFile<"MallocChecker.cpp">; def PthreadLockChecker : Checker<"PthreadLock">, @@ -343,7 +359,7 @@ let ParentPackage = OSX in { def MacOSXAPIChecker : Checker<"API">, InPackage<OSX>, - HelpText<"Check for proper uses of various Mac OS X APIs">, + HelpText<"Check for proper uses of various Apple APIs">, DescFile<"MacOSXAPIChecker.cpp">; def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">, @@ -523,4 +539,3 @@ def ExprInspectionChecker : Checker<"ExprInspection">, DescFile<"ExprInspectionChecker.cpp">; } // end "debug" - diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index f2e3e6d781..f336a6e680 100644 --- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -101,7 +101,8 @@ void ReachableCode::computeReachableBlocks() { } } -static const Expr *LookThroughTransitiveAssignments(const Expr *Ex) { +static const Expr * +LookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) { while (Ex) { const BinaryOperator *BO = dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts()); @@ -111,6 +112,10 @@ static const Expr *LookThroughTransitiveAssignments(const Expr *Ex) { Ex = BO->getRHS(); continue; } + if (BO->getOpcode() == BO_Comma) { + Ex = BO->getRHS(); + continue; + } break; } return Ex; @@ -266,7 +271,9 @@ public: if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { // Special case: check for assigning null to a pointer. // This is a common form of defensive programming. - const Expr *RHS = LookThroughTransitiveAssignments(B->getRHS()); + const Expr *RHS = + LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS()); + RHS = RHS->IgnoreParenCasts(); QualType T = VD->getType(); if (T->isPointerType() || T->isObjCObjectPointerType()) { @@ -274,7 +281,6 @@ public: return; } - RHS = RHS->IgnoreParenCasts(); // Special case: self-assignments. These are often used to shut up // "unused variable" compiler warnings. if (const DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS)) @@ -326,7 +332,7 @@ public: // Look through transitive assignments, e.g.: // int x = y = 0; - E = LookThroughTransitiveAssignments(E); + E = LookThroughTransitiveAssignmentsAndCommaOperators(E); // Don't warn on C++ objects (yet) until we can show that their // constructors/destructors don't have side effects. diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp index 29b4a637cd..fe12866e51 100644 --- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp +++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines a checkers that display debugging information. +// This file defines checkers that display debugging information. // //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 9f176a4b5b..759aa6605e 100644 --- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -27,7 +27,8 @@ namespace { class DynamicTypePropagation: public Checker< check::PreCall, check::PostCall, - check::PostStmt<ImplicitCastExpr> > { + check::PostStmt<ImplicitCastExpr>, + check::PostStmt<CXXNewExpr> > { const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, CheckerContext &C) const; @@ -38,6 +39,7 @@ public: void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkPostCall(const CallEvent &Call, CheckerContext &C) const; void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const; + void checkPostStmt(const CXXNewExpr *NewE, CheckerContext &C) const; }; } @@ -190,6 +192,20 @@ void DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE, return; } +void DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE, + CheckerContext &C) const { + if (NewE->isArray()) + return; + + // We only track dynamic type info for regions. + const MemRegion *MR = C.getSVal(NewE).getAsRegion(); + if (!MR) + return; + + C.addTransition(C.getState()->setDynamicTypeInfo(MR, NewE->getType(), + /*CanBeSubclass=*/false)); +} + const ObjCObjectType * DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, CheckerContext &C) const { diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp index 579ba9cf80..271ba4702c 100644 --- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp @@ -423,12 +423,12 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G, if (LHSRelevant) { const Expr *LHS = i->first->getLHS(); report->addRange(LHS->getSourceRange()); - FindLastStoreBRVisitor::registerStatementVarDecls(*report, LHS); + FindLastStoreBRVisitor::registerStatementVarDecls(*report, LHS, false); } if (RHSRelevant) { const Expr *RHS = i->first->getRHS(); report->addRange(i->first->getRHS()->getSourceRange()); - FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS); + FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS, false); } BR.emitReport(report); diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp index 5ed28e955d..cc940be7b1 100644 --- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp @@ -437,6 +437,7 @@ visit(const ObjCImplementationDecl *ImplD) const { // Remove ivars invalidated by the partial invalidation methods. They do not // need to be invalidated in the regular invalidation methods. + bool AtImplementationContainsAtLeastOnePartialInvalidationMethod = false; for (MethodSet::iterator I = PartialInfo.InvalidationMethods.begin(), E = PartialInfo.InvalidationMethods.end(); I != E; ++I) { @@ -446,6 +447,8 @@ visit(const ObjCImplementationDecl *ImplD) const { const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(), InterfD->isInstanceMethod()); if (D && D->hasBody()) { + AtImplementationContainsAtLeastOnePartialInvalidationMethod = true; + bool CalledAnotherInvalidationMethod = false; // The MethodCrowler is going to remove the invalidated ivars. MethodCrawler(Ivars, @@ -471,7 +474,7 @@ visit(const ObjCImplementationDecl *ImplD) const { containsInvalidationMethod(InterfaceD, Info, /*LookForPartial*/ false); // Report an error in case none of the invalidation methods are declared. - if (!Info.needsInvalidation()) { + if (!Info.needsInvalidation() && !PartialInfo.needsInvalidation()) { if (Filter.check_MissingInvalidationMethod) reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, /*MissingDeclaration*/ true); @@ -520,9 +523,19 @@ visit(const ObjCImplementationDecl *ImplD) const { } // Report an error in case none of the invalidation methods are implemented. - if (!AtImplementationContainsAtLeastOneInvalidationMethod) - reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, - /*MissingDeclaration*/ false); + if (!AtImplementationContainsAtLeastOneInvalidationMethod) { + if (AtImplementationContainsAtLeastOnePartialInvalidationMethod) { + // Warn on the ivars that were not invalidated by the prrtial + // invalidation methods. + for (IvarSet::const_iterator + I = Ivars.begin(), E = Ivars.end(); I != E; ++I) + reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, 0); + } else { + // Otherwise, no invalidation methods were implemented. + reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, + /*MissingDeclaration*/ false); + } + } } void IvarInvalidationCheckerImpl:: @@ -551,19 +564,27 @@ reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl, void IvarInvalidationCheckerImpl:: reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD, - const IvarToPropMapTy &IvarToPopertyMap, - const ObjCMethodDecl *MethodD) const { + const IvarToPropMapTy &IvarToPopertyMap, + const ObjCMethodDecl *MethodD) const { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); printIvar(os, IvarD, IvarToPopertyMap); os << "needs to be invalidated or set to nil"; - PathDiagnosticLocation MethodDecLocation = - PathDiagnosticLocation::createEnd(MethodD->getBody(), - BR.getSourceManager(), - Mgr.getAnalysisDeclContext(MethodD)); - BR.EmitBasicReport(MethodD, "Incomplete invalidation", - categories::CoreFoundationObjectiveC, os.str(), - MethodDecLocation); + if (MethodD) { + PathDiagnosticLocation MethodDecLocation = + PathDiagnosticLocation::createEnd(MethodD->getBody(), + BR.getSourceManager(), + Mgr.getAnalysisDeclContext(MethodD)); + BR.EmitBasicReport(MethodD, "Incomplete invalidation", + categories::CoreFoundationObjectiveC, os.str(), + MethodDecLocation); + } else { + BR.EmitBasicReport(IvarD, "Incomplete invalidation", + categories::CoreFoundationObjectiveC, os.str(), + PathDiagnosticLocation::createBegin(IvarD, + BR.getSourceManager())); + + } } void IvarInvalidationCheckerImpl::MethodCrawler::markInvalidated( diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp index 2cd4afe718..f1f06c798c 100644 --- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -91,7 +91,8 @@ private: inline void initBugType() const { if (!BT) - BT.reset(new BugType("Improper use of SecKeychain API", "Mac OS API")); + BT.reset(new BugType("Improper use of SecKeychain API", + "API Misuse (Apple)")); } void generateDeallocatorMismatchReport(const AllocationPair &AP, diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp index a76b3d7a7e..32ebb51226 100644 --- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This defines MacOSXAPIChecker, which is an assortment of checks on calls -// to various, widely used Mac OS X functions. +// to various, widely used Apple APIs. // // FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated // to here, using the new Checker interface. @@ -68,7 +68,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, if (!BT_dispatchOnce) BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'", - "Mac OS X API")); + "API Misuse (Apple)")); // Handle _dispatch_once. In some versions of the OS X SDK we have the case // that dispatch_once is a macro that wraps a call to _dispatch_once. diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 28a2999f04..5d3eb65148 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -35,6 +35,14 @@ using namespace ento; namespace { +// Used to check correspondence between allocators and deallocators. +enum AllocationFamily { + AF_None, + AF_Malloc, + AF_CXXNew, + AF_CXXNewArray +}; + class RefState { enum Kind { // Reference to allocated memory. Allocated, @@ -42,33 +50,53 @@ class RefState { Released, // The responsibility for freeing resources has transfered from // this reference. A relinquished symbol should not be freed. - Relinquished } K; + Relinquished, + // We are no longer guaranteed to have observed all manipulations + // of this pointer/memory. For example, it could have been + // passed as a parameter to an opaque function. + Escaped + }; + const Stmt *S; + unsigned K : 2; // Kind enum, but stored as a bitfield. + unsigned Family : 30; // Rest of 32-bit word, currently just an allocation + // family. + RefState(Kind k, const Stmt *s, unsigned family) + : S(s), K(k), Family(family) { + assert(family != AF_None); + } public: - RefState(Kind k, const Stmt *s) : K(k), S(s) {} - bool isAllocated() const { return K == Allocated; } bool isReleased() const { return K == Released; } bool isRelinquished() const { return K == Relinquished; } - + bool isEscaped() const { return K == Escaped; } + AllocationFamily getAllocationFamily() const { + return (AllocationFamily)Family; + } const Stmt *getStmt() const { return S; } bool operator==(const RefState &X) const { - return K == X.K && S == X.S; + return K == X.K && S == X.S && Family == X.Family; } - static RefState getAllocated(const Stmt *s) { - return RefState(Allocated, s); + static RefState getAllocated(unsigned family, const Stmt *s) { + return RefState(Allocated, s, family); + } + static RefState getReleased(unsigned family, const Stmt *s) { + return RefState(Released, s, family); } - static RefState getReleased(const Stmt *s) { return RefState(Released, s); } - static RefState getRelinquished(const Stmt *s) { - return RefState(Relinquished, s); + static RefState getRelinquished(unsigned family, const Stmt *s) { + return RefState(Relinquished, s, family); + } + static RefState getEscaped(const RefState *RS) { + return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily()); } void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); ID.AddPointer(S); + ID.AddInteger(Family); } void dump(raw_ostream &OS) const { @@ -117,9 +145,12 @@ typedef std::pair<const ExplodedNode*, const MemRegion*> LeakInfo; class MallocChecker : public Checker<check::DeadSymbols, check::PointerEscape, + check::ConstPointerEscape, check::PreStmt<ReturnStmt>, - check::PreStmt<CallExpr>, + check::PreCall, check::PostStmt<CallExpr>, + check::PostStmt<CXXNewExpr>, + check::PreStmt<CXXDeleteExpr>, check::PostStmt<BlockExpr>, check::PostObjCMessage, check::Location, @@ -129,6 +160,7 @@ class MallocChecker : public Checker<check::DeadSymbols, mutable OwningPtr<BugType> BT_Leak; mutable OwningPtr<BugType> BT_UseFree; mutable OwningPtr<BugType> BT_BadFree; + mutable OwningPtr<BugType> BT_MismatchedDealloc; mutable OwningPtr<BugType> BT_OffsetFree; mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc, *II_valloc, *II_reallocf, *II_strndup, *II_strdup; @@ -142,12 +174,17 @@ public: struct ChecksFilter { DefaultBool CMallocPessimistic; DefaultBool CMallocOptimistic; + DefaultBool CNewDeleteChecker; + DefaultBool CNewDeleteLeaksChecker; + DefaultBool CMismatchedDeallocatorChecker; }; ChecksFilter Filter; - void checkPreStmt(const CallExpr *S, CheckerContext &C) const; + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; + void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const; + void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const; void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const; void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; @@ -161,6 +198,10 @@ public: const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind) const; + ProgramStateRef checkConstPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call, + PointerEscapeKind Kind) const; void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const; @@ -168,32 +209,52 @@ public: private: void initIdentifierInfo(ASTContext &C) const; + /// \brief Determine family of a deallocation expression. + AllocationFamily getAllocationFamily(CheckerContext &C, const Stmt *S) const; + + /// \brief Print names of allocators and deallocators. + /// + /// \returns true on success. + bool printAllocDeallocName(raw_ostream &os, CheckerContext &C, + const Expr *E) const; + + /// \brief Print expected name of an allocator based on the deallocator's + /// family derived from the DeallocExpr. + void printExpectedAllocName(raw_ostream &os, CheckerContext &C, + const Expr *DeallocExpr) const; + /// \brief Print expected name of a deallocator based on the allocator's + /// family. + void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) const; + ///@{ /// Check if this is one of the functions which can allocate/reallocate memory /// pointed to by one of its arguments. bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const; bool isFreeFunction(const FunctionDecl *FD, ASTContext &C) const; bool isAllocationFunction(const FunctionDecl *FD, ASTContext &C) const; + bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const; ///@} static ProgramStateRef MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, const OwnershipAttr* Att); static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE, const Expr *SizeEx, SVal Init, - ProgramStateRef state) { + ProgramStateRef State, + AllocationFamily Family = AF_Malloc) { return MallocMemAux(C, CE, - state->getSVal(SizeEx, C.getLocationContext()), - Init, state); + State->getSVal(SizeEx, C.getLocationContext()), + Init, State, Family); } static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE, SVal SizeEx, SVal Init, - ProgramStateRef state); + ProgramStateRef State, + AllocationFamily Family = AF_Malloc); /// Update the RefState to reflect the new memory allocation. - static ProgramStateRef MallocUpdateRefState(CheckerContext &C, - const CallExpr *CE, - ProgramStateRef state); + static ProgramStateRef + MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, + AllocationFamily Family = AF_Malloc); ProgramStateRef FreeMemAttr(CheckerContext &C, const CallExpr *CE, const OwnershipAttr* Att) const; @@ -216,8 +277,7 @@ private: ///\brief Check if the memory associated with this symbol was released. bool isReleased(SymbolRef Sym, CheckerContext &C) const; - bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, - const Stmt *S = 0) const; + bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const; /// Check if the function is known not to free memory, or if it is /// "interesting" and should be modeled explicitly. @@ -227,10 +287,34 @@ private: bool doesNotFreeMemOrInteresting(const CallEvent *Call, ProgramStateRef State) const; + // Implementation of the checkPointerEscape callabcks. + ProgramStateRef checkPointerEscapeAux(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call, + PointerEscapeKind Kind, + bool(*CheckRefState)(const RefState*)) const; + + ///@{ + /// Tells if a given family/call/symbol is tracked by the current checker. + bool isTrackedByCurrentChecker(AllocationFamily Family) const; + bool isTrackedByCurrentChecker(CheckerContext &C, + const Stmt *AllocDeallocStmt) const; + bool isTrackedByCurrentChecker(CheckerContext &C, SymbolRef Sym) const; + ///@} static bool SummarizeValue(raw_ostream &os, SVal V); static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR); - void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const; - void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range)const; + void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range, + const Expr *DeallocExpr) const; + void ReportMismatchedDealloc(CheckerContext &C, SourceRange Range, + const Expr *DeallocExpr, const RefState *RS, + SymbolRef Sym) const; + void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range, + const Expr *DeallocExpr, + const Expr *AllocExpr = 0) const; + void ReportUseAfterFree(CheckerContext &C, SourceRange Range, + SymbolRef Sym) const; + void ReportDoubleFree(CheckerContext &C, SourceRange Range, bool Released, + SymbolRef Sym, SymbolRef PrevSym) const; /// Find the location of the allocation for Sym on the path leading to the /// exploded node N. @@ -275,14 +359,14 @@ private: inline bool isAllocated(const RefState *S, const RefState *SPrev, const Stmt *Stmt) { // Did not track -> allocated. Other state (released) -> allocated. - return (Stmt && isa<CallExpr>(Stmt) && + return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXNewExpr>(Stmt)) && (S && S->isAllocated()) && (!SPrev || !SPrev->isAllocated())); } inline bool isReleased(const RefState *S, const RefState *SPrev, const Stmt *Stmt) { // Did not track -> released. Other state (allocated) -> released. - return (Stmt && isa<CallExpr>(Stmt) && + return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXDeleteExpr>(Stmt)) && (S && S->isReleased()) && (!SPrev || !SPrev->isReleased())); } @@ -392,6 +476,9 @@ bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const { if (isAllocationFunction(FD, C)) return true; + if (isStandardNewDelete(FD, C)) + return true; + return false; } @@ -443,6 +530,39 @@ bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const return false; } +// Tells if the callee is one of the following: +// 1) A global non-placement new/delete operator function. +// 2) A global placement operator function with the single placement argument +// of type std::nothrow_t. +bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD, + ASTContext &C) const { + if (!FD) + return false; + + OverloadedOperatorKind Kind = FD->getOverloadedOperator(); + if (Kind != OO_New && Kind != OO_Array_New && + Kind != OO_Delete && Kind != OO_Array_Delete) + return false; + + // Skip all operator new/delete methods. + if (isa<CXXMethodDecl>(FD)) + return false; + + // Return true if tested operator is a standard placement nothrow operator. + if (FD->getNumParams() == 2) { + QualType T = FD->getParamDecl(1)->getType(); + if (const IdentifierInfo *II = T.getBaseTypeIdentifier()) + return II->getName().equals("nothrow_t"); + } + + // Skip placement operators. + if (FD->getNumParams() != 1 || FD->isVariadic()) + return false; + + // One of the standard new/new[]/delete/delete[] non-placement operators. + return true; +} + void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { if (C.wasInlined) return; @@ -475,9 +595,26 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { } else if (FunI == II_strndup) { State = MallocUpdateRefState(C, CE, State); } + else if (isStandardNewDelete(FD, C.getASTContext())) { + // Process direct calls to operator new/new[]/delete/delete[] functions + // as distinct from new/new[]/delete/delete[] expressions that are + // processed by the checkPostStmt callbacks for CXXNewExpr and + // CXXDeleteExpr. + OverloadedOperatorKind K = FD->getOverloadedOperator(); + if (K == OO_New) + State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, + AF_CXXNew); + else if (K == OO_Array_New) + State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, + AF_CXXNewArray); + else if (K == OO_Delete || K == OO_Array_Delete) + State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory); + else + llvm_unreachable("not a new/delete operator"); + } } - if (Filter.CMallocOptimistic) { + if (Filter.CMallocOptimistic || Filter.CMismatchedDeallocatorChecker) { // Check all the attributes, if there are any. // There can be multiple of these attributes. if (FD->hasAttrs()) @@ -499,6 +636,46 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { C.addTransition(State); } +void MallocChecker::checkPostStmt(const CXXNewExpr *NE, + CheckerContext &C) const { + + if (NE->getNumPlacementArgs()) + for (CXXNewExpr::const_arg_iterator I = NE->placement_arg_begin(), + E = NE->placement_arg_end(); I != E; ++I) + if (SymbolRef Sym = C.getSVal(*I).getAsSymbol()) + checkUseAfterFree(Sym, C, *I); + + if (!isStandardNewDelete(NE->getOperatorNew(), C.getASTContext())) + return; + + ProgramStateRef State = C.getState(); + // The return value from operator new is bound to a specified initialization + // value (if any) and we don't want to loose this value. So we call + // MallocUpdateRefState() instead of MallocMemAux() which breakes the + // existing binding. + State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray + : AF_CXXNew); + C.addTransition(State); +} + +void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE, + CheckerContext &C) const { + + if (!Filter.CNewDeleteChecker) + if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol()) + checkUseAfterFree(Sym, C, DE->getArgument()); + + if (!isStandardNewDelete(DE->getOperatorDelete(), C.getASTContext())) + return; + + ProgramStateRef State = C.getState(); + bool ReleasedAllocated; + State = FreeMemAux(C, DE->getArgument(), DE, State, + /*Hold*/false, ReleasedAllocated); + + C.addTransition(State); +} + static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call) { // If the first selector piece is one of the names below, assume that the // object takes ownership of the memory, promising to eventually deallocate it @@ -562,7 +739,8 @@ ProgramStateRef MallocChecker::MallocMemReturnsAttr(CheckerContext &C, ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, const CallExpr *CE, SVal Size, SVal Init, - ProgramStateRef state) { + ProgramStateRef State, + AllocationFamily Family) { // Bind the return value to the symbolic value from the heap region. // TODO: We could rewrite post visit to eval call; 'malloc' does not have @@ -572,14 +750,14 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); DefinedSVal RetVal = svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count) .castAs<DefinedSVal>(); - state = state->BindExpr(CE, C.getLocationContext(), RetVal); + State = State->BindExpr(CE, C.getLocationContext(), RetVal); // We expect the malloc functions to return a pointer. if (!RetVal.getAs<Loc>()) return 0; // Fill the region with the initialization value. - state = state->bindDefault(RetVal, Init); + State = State->bindDefault(RetVal, Init); // Set the region's extent equal to the Size parameter. const SymbolicRegion *R = @@ -591,20 +769,21 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, SValBuilder &svalBuilder = C.getSValBuilder(); DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder); DefinedOrUnknownSVal extentMatchesSize = - svalBuilder.evalEQ(state, Extent, *DefinedSize); + svalBuilder.evalEQ(State, Extent, *DefinedSize); - state = state->assume(extentMatchesSize, true); - assert(state); + State = State->assume(extentMatchesSize, true); + assert(State); } - return MallocUpdateRefState(C, CE, state); + return MallocUpdateRefState(C, CE, State, Family); } ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C, - const CallExpr *CE, - ProgramStateRef state) { + const Expr *E, + ProgramStateRef State, + AllocationFamily Family) { // Get the return value. - SVal retVal = state->getSVal(CE, C.getLocationContext()); + SVal retVal = State->getSVal(E, C.getLocationContext()); // We expect the malloc functions to return a pointer. if (!retVal.getAs<Loc>()) @@ -614,8 +793,7 @@ ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C, assert(Sym); // Set the symbol's state to Allocated. - return state->set<RegionState>(Sym, RefState::getAllocated(CE)); - + return State->set<RegionState>(Sym, RefState::getAllocated(Family, E)); } ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C, @@ -667,6 +845,107 @@ static bool didPreviousFreeFail(ProgramStateRef State, return false; } +AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C, + const Stmt *S) const { + if (!S) + return AF_None; + + if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { + const FunctionDecl *FD = C.getCalleeDecl(CE); + + if (!FD) + FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl()); + + ASTContext &Ctx = C.getASTContext(); + + if (isAllocationFunction(FD, Ctx) || isFreeFunction(FD, Ctx)) + return AF_Malloc; + + if (isStandardNewDelete(FD, Ctx)) { + OverloadedOperatorKind Kind = FD->getOverloadedOperator(); + if (Kind == OO_New || Kind == OO_Delete) + return AF_CXXNew; + else if (Kind == OO_Array_New || Kind == OO_Array_Delete) + return AF_CXXNewArray; + } + + return AF_None; + } + + if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(S)) + return NE->isArray() ? AF_CXXNewArray : AF_CXXNew; + + if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(S)) + return DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew; + + if (isa<ObjCMessageExpr>(S)) + return AF_Malloc; + + return AF_None; +} + +bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C, + const Expr *E) const { + if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { + // FIXME: This doesn't handle indirect calls. + const FunctionDecl *FD = CE->getDirectCallee(); + if (!FD) + return false; + + os << *FD; + if (!FD->isOverloadedOperator()) + os << "()"; + return true; + } + + if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) { + if (Msg->isInstanceMessage()) + os << "-"; + else + os << "+"; + os << Msg->getSelector().getAsString(); + return true; + } + + if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) { + os << "'" + << getOperatorSpelling(NE->getOperatorNew()->getOverloadedOperator()) + << "'"; + return true; + } + + if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E)) { + os << "'" + << getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator()) + << "'"; + return true; + } + + return false; +} + +void MallocChecker::printExpectedAllocName(raw_ostream &os, CheckerContext &C, + const Expr *E) const { + AllocationFamily Family = getAllocationFamily(C, E); + + switch(Family) { + case AF_Malloc: os << "malloc()"; return; + case AF_CXXNew: os << "'new'"; return; + case AF_CXXNewArray: os << "'new[]'"; return; + case AF_None: llvm_unreachable("not a deallocation expression"); + } +} + +void MallocChecker::printExpectedDeallocName(raw_ostream &os, + AllocationFamily Family) const { + switch(Family) { + case AF_Malloc: os << "free()"; return; + case AF_CXXNew: os << "'delete'"; return; + case AF_CXXNewArray: os << "'delete[]'"; return; + case AF_None: llvm_unreachable("suspicious AF_None argument"); + } +} + ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr, const Expr *ParentExpr, @@ -700,7 +979,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, // Nonlocs can't be freed, of course. // Non-region locations (labels and fixed addresses) also shouldn't be freed. if (!R) { - ReportBadFree(C, ArgVal, ArgExpr->getSourceRange()); + ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr); return 0; } @@ -708,13 +987,14 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, // Blocks might show up as heap data, but should not be free()d if (isa<BlockDataRegion>(R)) { - ReportBadFree(C, ArgVal, ArgExpr->getSourceRange()); + ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr); return 0; } const MemSpaceRegion *MS = R->getMemorySpace(); - // Parameters, locals, statics, and globals shouldn't be freed. + // Parameters, locals, statics, globals, and memory returned by alloca() + // shouldn't be freed. if (!(isa<UnknownSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS))) { // FIXME: at the time this code was written, malloc() regions were // represented by conjured symbols, which are all in UnknownSpaceRegion. @@ -724,7 +1004,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, // function, so UnknownSpaceRegion is always a possibility. // False negatives are better than false positives. - ReportBadFree(C, ArgVal, ArgExpr->getSourceRange()); + ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr); return 0; } @@ -738,38 +1018,40 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, const RefState *RsBase = State->get<RegionState>(SymBase); SymbolRef PreviousRetStatusSymbol = 0; - // Check double free. - if (RsBase && - (RsBase->isReleased() || RsBase->isRelinquished()) && - !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) { - - if (ExplodedNode *N = C.generateSink()) { - if (!BT_DoubleFree) - BT_DoubleFree.reset( - new BugType("Double free", "Memory Error")); - BugReport *R = new BugReport(*BT_DoubleFree, - (RsBase->isReleased() ? "Attempt to free released memory" - : "Attempt to free non-owned memory"), - N); - R->addRange(ArgExpr->getSourceRange()); - R->markInteresting(SymBase); - if (PreviousRetStatusSymbol) - R->markInteresting(PreviousRetStatusSymbol); - R->addVisitor(new MallocBugVisitor(SymBase)); - C.emitReport(R); - } - return 0; - } + if (RsBase) { - // Check if the memory location being freed is the actual location - // allocated, or an offset. - RegionOffset Offset = R->getAsOffset(); - if (RsBase && RsBase->isAllocated() && - Offset.isValid() && - !Offset.hasSymbolicOffset() && - Offset.getOffset() != 0) { - ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange()); - return 0; + // Check for double free first. + if ((RsBase->isReleased() || RsBase->isRelinquished()) && + !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) { + ReportDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(), + SymBase, PreviousRetStatusSymbol); + return 0; + + // If the pointer is allocated or escaped, but we are now trying to free it, + // check that the call to free is proper. + } else if (RsBase->isAllocated() || RsBase->isEscaped()) { + + // Check if an expected deallocation function matches the real one. + bool DeallocMatchesAlloc = + RsBase->getAllocationFamily() == getAllocationFamily(C, ParentExpr); + if (!DeallocMatchesAlloc) { + ReportMismatchedDealloc(C, ArgExpr->getSourceRange(), + ParentExpr, RsBase, SymBase); + return 0; + } + + // Check if the memory location being freed is the actual location + // allocated, or an offset. + RegionOffset Offset = R->getAsOffset(); + if (Offset.isValid() && + !Offset.hasSymbolicOffset() && + Offset.getOffset() != 0) { + const Expr *AllocExpr = cast<Expr>(RsBase->getStmt()); + ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, + AllocExpr); + return 0; + } + } } ReleasedAllocated = (RsBase != 0); @@ -788,12 +1070,50 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, } } + AllocationFamily Family = RsBase ? RsBase->getAllocationFamily() + : getAllocationFamily(C, ParentExpr); // Normal free. - if (Hold) { + if (Hold) return State->set<RegionState>(SymBase, - RefState::getRelinquished(ParentExpr)); + RefState::getRelinquished(Family, + ParentExpr)); + + return State->set<RegionState>(SymBase, + RefState::getReleased(Family, ParentExpr)); +} + +bool MallocChecker::isTrackedByCurrentChecker(AllocationFamily Family) const { + switch (Family) { + case AF_Malloc: { + if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic) + return false; + return true; + } + case AF_CXXNew: + case AF_CXXNewArray: { + if (!Filter.CNewDeleteChecker) + return false; + return true; + } + case AF_None: { + llvm_unreachable("no family"); } - return State->set<RegionState>(SymBase, RefState::getReleased(ParentExpr)); + } + llvm_unreachable("unhandled family"); +} + +bool +MallocChecker::isTrackedByCurrentChecker(CheckerContext &C, + const Stmt *AllocDeallocStmt) const { + return isTrackedByCurrentChecker(getAllocationFamily(C, AllocDeallocStmt)); +} + +bool MallocChecker::isTrackedByCurrentChecker(CheckerContext &C, + SymbolRef Sym) const { + + const RefState *RS = C.getState()->get<RegionState>(Sym); + assert(RS); + return isTrackedByCurrentChecker(RS->getAllocationFamily()); } bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) { @@ -883,47 +1203,105 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os, } } -void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, - SourceRange range) const { +void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, + SourceRange Range, + const Expr *DeallocExpr) const { + + if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic && + !Filter.CNewDeleteChecker) + return; + + if (!isTrackedByCurrentChecker(C, DeallocExpr)) + return; + if (ExplodedNode *N = C.generateSink()) { if (!BT_BadFree) BT_BadFree.reset(new BugType("Bad free", "Memory Error")); SmallString<100> buf; llvm::raw_svector_ostream os(buf); - + const MemRegion *MR = ArgVal.getAsRegion(); - if (MR) { - while (const ElementRegion *ER = dyn_cast<ElementRegion>(MR)) - MR = ER->getSuperRegion(); - - // Special case for alloca() - if (isa<AllocaRegion>(MR)) - os << "Argument to free() was allocated by alloca(), not malloc()"; - else { - os << "Argument to free() is "; - if (SummarizeRegion(os, MR)) - os << ", which is not memory allocated by malloc()"; - else - os << "not memory allocated by malloc()"; - } - } else { - os << "Argument to free() is "; - if (SummarizeValue(os, ArgVal)) - os << ", which is not memory allocated by malloc()"; + while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR)) + MR = ER->getSuperRegion(); + + if (MR && isa<AllocaRegion>(MR)) + os << "Memory allocated by alloca() should not be deallocated"; + else { + os << "Argument to "; + if (!printAllocDeallocName(os, C, DeallocExpr)) + os << "deallocator"; + + os << " is "; + bool Summarized = MR ? SummarizeRegion(os, MR) + : SummarizeValue(os, ArgVal); + if (Summarized) + os << ", which is not memory allocated by "; else - os << "not memory allocated by malloc()"; + os << "not memory allocated by "; + + printExpectedAllocName(os, C, DeallocExpr); } - + BugReport *R = new BugReport(*BT_BadFree, os.str(), N); R->markInteresting(MR); - R->addRange(range); + R->addRange(Range); + C.emitReport(R); + } +} + +void MallocChecker::ReportMismatchedDealloc(CheckerContext &C, + SourceRange Range, + const Expr *DeallocExpr, + const RefState *RS, + SymbolRef Sym) const { + + if (!Filter.CMismatchedDeallocatorChecker) + return; + + if (ExplodedNode *N = C.generateSink()) { + if (!BT_MismatchedDealloc) + BT_MismatchedDealloc.reset(new BugType("Bad deallocator", + "Memory Error")); + + SmallString<100> buf; + llvm::raw_svector_ostream os(buf); + + const Expr *AllocExpr = cast<Expr>(RS->getStmt()); + SmallString<20> AllocBuf; + llvm::raw_svector_ostream AllocOs(AllocBuf); + SmallString<20> DeallocBuf; + llvm::raw_svector_ostream DeallocOs(DeallocBuf); + + os << "Memory"; + if (printAllocDeallocName(AllocOs, C, AllocExpr)) + os << " allocated by " << AllocOs.str(); + + os << " should be deallocated by "; + printExpectedDeallocName(os, RS->getAllocationFamily()); + + if (printAllocDeallocName(DeallocOs, C, DeallocExpr)) + os << ", not " << DeallocOs.str(); + + BugReport *R = new BugReport(*BT_MismatchedDealloc, os.str(), N); + R->markInteresting(Sym); + R->addRange(Range); + R->addVisitor(new MallocBugVisitor(Sym)); C.emitReport(R); } } void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, - SourceRange Range) const { + SourceRange Range, const Expr *DeallocExpr, + const Expr *AllocExpr) const { + + if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic && + !Filter.CNewDeleteChecker) + return; + + if (!isTrackedByCurrentChecker(C, AllocExpr)) + return; + ExplodedNode *N = C.generateSink(); if (N == NULL) return; @@ -933,6 +1311,8 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, SmallString<100> buf; llvm::raw_svector_ostream os(buf); + SmallString<20> AllocNameBuf; + llvm::raw_svector_ostream AllocNameOs(AllocNameBuf); const MemRegion *MR = ArgVal.getAsRegion(); assert(MR && "Only MemRegion based symbols can have offset free errors"); @@ -945,11 +1325,18 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth(); - os << "Argument to free() is offset by " + os << "Argument to "; + if (!printAllocDeallocName(os, C, DeallocExpr)) + os << "deallocator"; + os << " is offset by " << offsetBytes << " " << ((abs(offsetBytes) > 1) ? "bytes" : "byte") - << " from the start of memory allocated by malloc()"; + << " from the start of "; + if (AllocExpr && printAllocDeallocName(AllocNameOs, C, AllocExpr)) + os << "memory allocated by " << AllocNameOs.str(); + else + os << "allocated memory"; BugReport *R = new BugReport(*BT_OffsetFree, os.str(), N); R->markInteresting(MR->getBaseRegion()); @@ -957,6 +1344,58 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, C.emitReport(R); } +void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range, + SymbolRef Sym) const { + + if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic && + !Filter.CNewDeleteChecker) + return; + + if (!isTrackedByCurrentChecker(C, Sym)) + return; + + if (ExplodedNode *N = C.generateSink()) { + if (!BT_UseFree) + BT_UseFree.reset(new BugType("Use-after-free", "Memory Error")); + + BugReport *R = new BugReport(*BT_UseFree, + "Use of memory after it is freed", N); + + R->markInteresting(Sym); + R->addRange(Range); + R->addVisitor(new MallocBugVisitor(Sym)); + C.emitReport(R); + } +} + +void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range, + bool Released, SymbolRef Sym, + SymbolRef PrevSym) const { + + if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic && + !Filter.CNewDeleteChecker) + return; + + if (!isTrackedByCurrentChecker(C, Sym)) + return; + + if (ExplodedNode *N = C.generateSink()) { + if (!BT_DoubleFree) + BT_DoubleFree.reset(new BugType("Double free", "Memory Error")); + + BugReport *R = new BugReport(*BT_DoubleFree, + (Released ? "Attempt to free released memory" + : "Attempt to free non-owned memory"), + N); + R->addRange(Range); + R->markInteresting(Sym); + if (PrevSym) + R->markInteresting(PrevSym); + R->addVisitor(new MallocBugVisitor(Sym)); + C.emitReport(R); + } +} + ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE, bool FreesOnFail) const { @@ -1091,13 +1530,19 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym, // Find the most recent expression bound to the symbol in the current // context. - if (!ReferenceRegion) { - if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) { - SVal Val = State->getSVal(MR); - if (Val.getAsLocSymbol() == Sym) - ReferenceRegion = MR; + if (!ReferenceRegion) { + if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) { + SVal Val = State->getSVal(MR); + if (Val.getAsLocSymbol() == Sym) { + const VarRegion* VR = MR->getBaseRegion()->getAs<VarRegion>(); + // Do not show local variables belonging to a function other than + // where the error is reported. + if (!VR || + (VR->getStackFrame() == LeakContext->getCurrentStackFrame())) + ReferenceRegion = MR; + } + } } - } // Allocation node, is the last node in the current context in which the // symbol was tracked. @@ -1111,6 +1556,23 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym, void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const { + + if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic && + !Filter.CNewDeleteLeaksChecker) + return; + + const RefState *RS = C.getState()->get<RegionState>(Sym); + assert(RS && "cannot leak an untracked symbol"); + AllocationFamily Family = RS->getAllocationFamily(); + if (!isTrackedByCurrentChecker(Family)) + return; + + // Special case for new and new[]; these are controlled by a separate checker + // flag so that they can be selectively disabled. + if (Family == AF_CXXNew || Family == AF_CXXNewArray) + if (!Filter.CNewDeleteLeaksChecker) + return; + assert(N); if (!BT_Leak) { BT_Leak.reset(new BugType("Memory leak", "Memory Error")); @@ -1143,11 +1605,11 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, SmallString<200> buf; llvm::raw_svector_ostream os(buf); - os << "Memory is never released; potential leak"; if (Region && Region->canPrintPretty()) { - os << " of memory pointed to by '"; + os << "Potential leak of memory pointed to by "; Region->printPretty(os); - os << '\''; + } else { + os << "Potential memory leak"; } BugReport *R = new BugReport(*BT_Leak, os.str(), N, @@ -1211,21 +1673,39 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, C.addTransition(state->set<RegionState>(RS), N); } -void MallocChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { +void MallocChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + // We will check for double free in the post visit. - if (isFreeFunction(C.getCalleeDecl(CE), C.getASTContext())) - return; + if (const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&Call)) { + const FunctionDecl *FD = FC->getDecl(); + if (!FD) + return; - // Check use after free, when a freed pointer is passed to a call. - ProgramStateRef State = C.getState(); - for (CallExpr::const_arg_iterator I = CE->arg_begin(), - E = CE->arg_end(); I != E; ++I) { - const Expr *A = *I; - if (A->getType().getTypePtr()->isAnyPointerType()) { - SymbolRef Sym = State->getSVal(A, C.getLocationContext()).getAsSymbol(); + if ((Filter.CMallocOptimistic || Filter.CMallocPessimistic) && + isFreeFunction(FD, C.getASTContext())) + return; + + if (Filter.CNewDeleteChecker && + isStandardNewDelete(FD, C.getASTContext())) + return; + } + + // Check if the callee of a method is deleted. + if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) { + SymbolRef Sym = CC->getCXXThisVal().getAsSymbol(); + if (!Sym || checkUseAfterFree(Sym, C, CC->getCXXThisExpr())) + return; + } + + // Check arguments for being used after free. + for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) { + SVal ArgSVal = Call.getArgSVal(I); + if (ArgSVal.getAs<Loc>()) { + SymbolRef Sym = ArgSVal.getAsSymbol(); if (!Sym) continue; - if (checkUseAfterFree(Sym, C, A)) + if (checkUseAfterFree(Sym, C, Call.getArgExpr(I))) return; } } @@ -1303,21 +1783,12 @@ bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const { bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const { + if (isReleased(Sym, C)) { - if (ExplodedNode *N = C.generateSink()) { - if (!BT_UseFree) - BT_UseFree.reset(new BugType("Use-after-free", "Memory Error")); - - BugReport *R = new BugReport(*BT_UseFree, - "Use of memory after it is freed",N); - if (S) - R->addRange(S->getSourceRange()); - R->markInteresting(Sym); - R->addVisitor(new MallocBugVisitor(Sym)); - C.emitReport(R); - return true; - } + ReportUseAfterFree(C, S->getSourceRange(), Sym); + return true; } + return false; } @@ -1358,7 +1829,7 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state, if (RS->isReleased()) { if (I.getData().Kind == RPToBeFreedAfterFailure) state = state->set<RegionState>(ReallocSym, - RefState::getAllocated(RS->getStmt())); + RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt())); else if (I.getData().Kind == RPDoNotTrackAfterFailure) state = state->remove<RegionState>(ReallocSym); else @@ -1510,10 +1981,35 @@ bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call, return true; } +static bool retTrue(const RefState *RS) { + return true; +} + +static bool checkIfNewOrNewArrayFamily(const RefState *RS) { + return (RS->getAllocationFamily() == AF_CXXNewArray || + RS->getAllocationFamily() == AF_CXXNew); +} + ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind) const { + return checkPointerEscapeAux(State, Escaped, Call, Kind, &retTrue); +} + +ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call, + PointerEscapeKind Kind) const { + return checkPointerEscapeAux(State, Escaped, Call, Kind, + &checkIfNewOrNewArrayFamily); +} + +ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call, + PointerEscapeKind Kind, + bool(*CheckRefState)(const RefState*)) const { // If we know that the call does not free memory, or we want to process the // call later, keep tracking the top level arguments. if ((Kind == PSK_DirectEscapeOnCall || @@ -1523,13 +2019,15 @@ ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State, } for (InvalidatedSymbols::const_iterator I = Escaped.begin(), - E = Escaped.end(); - I != E; ++I) { + E = Escaped.end(); + I != E; ++I) { SymbolRef sym = *I; if (const RefState *RS = State->get<RegionState>(sym)) { - if (RS->isAllocated()) + if (RS->isAllocated() && CheckRefState(RS)) { State = State->remove<RegionState>(sym); + State = State->set<RegionState>(sym, RefState::getEscaped(RS)); + } } } return State; @@ -1594,7 +2092,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, } else if (isReleased(RS, RSPrev, S)) { Msg = "Memory is released"; StackHint = new StackHintGeneratorForSymbol(Sym, - "Returned released memory"); + "Returning; memory was released"); } else if (isRelinquished(RS, RSPrev, S)) { Msg = "Memory ownership is transfered"; StackHint = new StackHintGeneratorForSymbol(Sym, ""); @@ -1654,6 +2152,14 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State, } } +void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) { + registerCStringCheckerBasic(mgr); + mgr.registerChecker<MallocChecker>()->Filter.CNewDeleteLeaksChecker = true; + // We currently treat NewDeleteLeaks checker as a subchecker of NewDelete + // checker. + mgr.registerChecker<MallocChecker>()->Filter.CNewDeleteChecker = true; +} + #define REGISTER_CHECKER(name) \ void ento::register##name(CheckerManager &mgr) {\ registerCStringCheckerBasic(mgr); \ @@ -1662,3 +2168,5 @@ void ento::register##name(CheckerManager &mgr) {\ REGISTER_CHECKER(MallocPessimistic) REGISTER_CHECKER(MallocOptimistic) +REGISTER_CHECKER(NewDeleteChecker) +REGISTER_CHECKER(MismatchedDeallocatorChecker) diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp index ce7d4ccf7a..d29f34fb03 100644 --- a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp @@ -188,7 +188,7 @@ public: for (CallExpr::const_arg_iterator ai = i->AllocCall->arg_begin(), ae = i->AllocCall->arg_end(); ai != ae; ++ai) { - if (!(*ai)->getType()->isIntegerType()) + if (!(*ai)->getType()->isIntegralOrUnscopedEnumerationType()) continue; SizeofFinder SFinder; diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 856463a981..0f456ea8d7 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -37,6 +37,8 @@ #include "llvm/ADT/StringExtras.h" #include <cstdarg> +#include "AllocationDiagnostics.h" + using namespace clang; using namespace ento; using llvm::StrInStrNoCase; @@ -324,7 +326,7 @@ void RefVal::print(raw_ostream &Out) const { break; case RefVal::ErrorOverAutorelease: - Out << "Over autoreleased"; + Out << "Over-autoreleased"; break; case RefVal::ErrorReturnedNotOwned: @@ -782,6 +784,10 @@ public: const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD, Selector S, QualType RetTy); + /// Determine if there is a special return effect for this function or method. + Optional<RetEffect> getRetEffectFromAnnotations(QualType RetTy, + const Decl *D); + void updateSummaryFromAnnotations(const RetainSummary *&Summ, const ObjCMethodDecl *MD); @@ -1110,12 +1116,14 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { // correctly. ScratchArgs = AF.add(ScratchArgs, 12, StopTracking); S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); - } else if (FName == "dispatch_set_context") { + } else if (FName == "dispatch_set_context" || + FName == "xpc_connection_set_context") { // <rdar://problem/11059275> - The analyzer currently doesn't have // a good way to reason about the finalizer function for libdispatch. // If we pass a context object that is memory managed, stop tracking it. + // <rdar://problem/13783514> - Same problem, but for XPC. // FIXME: this hack should possibly go away once we can handle - // libdispatch finalizers. + // libdispatch and XPC finalizers. ScratchArgs = AF.add(ScratchArgs, 1, StopTracking); S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } else if (FName.startswith("NSLog")) { @@ -1271,6 +1279,30 @@ RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) { // Summary creation for Selectors. //===----------------------------------------------------------------------===// +Optional<RetEffect> +RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy, + const Decl *D) { + if (cocoa::isCocoaObjectRef(RetTy)) { + if (D->getAttr<NSReturnsRetainedAttr>()) + return ObjCAllocRetE; + + if (D->getAttr<NSReturnsNotRetainedAttr>() || + D->getAttr<NSReturnsAutoreleasedAttr>()) + return RetEffect::MakeNotOwned(RetEffect::ObjC); + + } else if (!RetTy->isPointerType()) { + return None; + } + + if (D->getAttr<CFReturnsRetainedAttr>()) + return RetEffect::MakeOwned(RetEffect::CF, true); + + if (D->getAttr<CFReturnsNotRetainedAttr>()) + return RetEffect::MakeNotOwned(RetEffect::CF); + + return None; +} + void RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, const FunctionDecl *FD) { @@ -1285,40 +1317,15 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, for (FunctionDecl::param_const_iterator pi = FD->param_begin(), pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) { const ParmVarDecl *pd = *pi; - if (pd->getAttr<NSConsumedAttr>()) { - if (!GCEnabled) { - Template->addArg(AF, parm_idx, DecRef); - } - } else if (pd->getAttr<CFConsumedAttr>()) { + if (pd->getAttr<NSConsumedAttr>()) + Template->addArg(AF, parm_idx, DecRefMsg); + else if (pd->getAttr<CFConsumedAttr>()) Template->addArg(AF, parm_idx, DecRef); - } } QualType RetTy = FD->getResultType(); - - // Determine if there is a special return effect for this method. - if (cocoa::isCocoaObjectRef(RetTy)) { - if (FD->getAttr<NSReturnsRetainedAttr>()) { - Template->setRetEffect(ObjCAllocRetE); - } - else if (FD->getAttr<CFReturnsRetainedAttr>()) { - Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); - } - else if (FD->getAttr<NSReturnsNotRetainedAttr>() || - FD->getAttr<NSReturnsAutoreleasedAttr>()) { - Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC)); - } - else if (FD->getAttr<CFReturnsNotRetainedAttr>()) - Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); - } - else if (RetTy->getAs<PointerType>()) { - if (FD->getAttr<CFReturnsRetainedAttr>()) { - Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); - } - else if (FD->getAttr<CFReturnsNotRetainedAttr>()) { - Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); - } - } + if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD)) + Template->setRetEffect(*RetE); } void @@ -1329,13 +1336,10 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, assert(Summ && "Must have a valid summary to add annotations to"); RetainSummaryTemplate Template(Summ, *this); - bool isTrackedLoc = false; // Effects on the receiver. - if (MD->getAttr<NSConsumesSelfAttr>()) { - if (!GCEnabled) - Template->setReceiverEffect(DecRefMsg); - } + if (MD->getAttr<NSConsumesSelfAttr>()) + Template->setReceiverEffect(DecRefMsg); // Effects on the parameters. unsigned parm_idx = 0; @@ -1343,38 +1347,16 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, pi=MD->param_begin(), pe=MD->param_end(); pi != pe; ++pi, ++parm_idx) { const ParmVarDecl *pd = *pi; - if (pd->getAttr<NSConsumedAttr>()) { - if (!GCEnabled) - Template->addArg(AF, parm_idx, DecRef); - } - else if(pd->getAttr<CFConsumedAttr>()) { + if (pd->getAttr<NSConsumedAttr>()) + Template->addArg(AF, parm_idx, DecRefMsg); + else if (pd->getAttr<CFConsumedAttr>()) { Template->addArg(AF, parm_idx, DecRef); } } - // Determine if there is a special return effect for this method. - if (cocoa::isCocoaObjectRef(MD->getResultType())) { - if (MD->getAttr<NSReturnsRetainedAttr>()) { - Template->setRetEffect(ObjCAllocRetE); - return; - } - if (MD->getAttr<NSReturnsNotRetainedAttr>() || - MD->getAttr<NSReturnsAutoreleasedAttr>()) { - Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC)); - return; - } - - isTrackedLoc = true; - } else { - isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL; - } - - if (isTrackedLoc) { - if (MD->getAttr<CFReturnsRetainedAttr>()) - Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); - else if (MD->getAttr<CFReturnsNotRetainedAttr>()) - Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); - } + QualType RetTy = MD->getResultType(); + if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD)) + Template->setRetEffect(*RetE); } const RetainSummary * @@ -1682,10 +1664,10 @@ namespace { class OverAutorelease : public CFRefBug { public: OverAutorelease() - : CFRefBug("Object sent -autorelease too many times") {} + : CFRefBug("Object autoreleased too many times") {} const char *getDescription() const { - return "Object sent -autorelease too many times"; + return "Object autoreleased too many times"; } }; @@ -1795,11 +1777,11 @@ namespace { class CFRefLeakReport : public CFRefReport { const MemRegion* AllocBinding; - public: CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled, const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, - CheckerContext &Ctx); + CheckerContext &Ctx, + bool IncludeAllocationLine); PathDiagnosticLocation getLocation(const SourceManager &SM) const { assert(Location.isValid()); @@ -2070,7 +2052,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, return 0; assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount()); - os << "Object sent -autorelease message"; + os << "Object autoreleased"; break; } @@ -2156,32 +2138,86 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, // Find the first node in the current function context that referred to the // tracked symbol and the memory location that value was stored to. Note, the // value is only reported if the allocation occurred in the same function as -// the leak. -static std::pair<const ExplodedNode*,const MemRegion*> +// the leak. The function can also return a location context, which should be +// treated as interesting. +struct AllocationInfo { + const ExplodedNode* N; + const MemRegion *R; + const LocationContext *InterestingMethodContext; + AllocationInfo(const ExplodedNode *InN, + const MemRegion *InR, + const LocationContext *InInterestingMethodContext) : + N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {} +}; + +static AllocationInfo GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N, SymbolRef Sym) { - const ExplodedNode *Last = N; + const ExplodedNode *AllocationNode = N; + const ExplodedNode *AllocationNodeInCurrentContext = N; const MemRegion* FirstBinding = 0; const LocationContext *LeakContext = N->getLocationContext(); + // The location context of the init method called on the leaked object, if + // available. + const LocationContext *InitMethodContext = 0; + while (N) { ProgramStateRef St = N->getState(); + const LocationContext *NContext = N->getLocationContext(); if (!getRefBinding(St, Sym)) break; StoreManager::FindUniqueBinding FB(Sym); StateMgr.iterBindings(St, FB); - if (FB) FirstBinding = FB.getRegion(); - - // Allocation node, is the last node in the current context in which the - // symbol was tracked. - if (N->getLocationContext() == LeakContext) - Last = N; + + if (FB) { + const MemRegion *R = FB.getRegion(); + const VarRegion *VR = R->getBaseRegion()->getAs<VarRegion>(); + // Do not show local variables belonging to a function other than + // where the error is reported. + if (!VR || VR->getStackFrame() == LeakContext->getCurrentStackFrame()) + FirstBinding = R; + } + + // AllocationNode is the last node in which the symbol was tracked. + AllocationNode = N; + + // AllocationNodeInCurrentContext, is the last node in the current context + // in which the symbol was tracked. + if (NContext == LeakContext) + AllocationNodeInCurrentContext = N; + + // Find the last init that was called on the given symbol and store the + // init method's location context. + if (!InitMethodContext) + if (Optional<CallEnter> CEP = N->getLocation().getAs<CallEnter>()) { + const Stmt *CE = CEP->getCallExpr(); + if (const ObjCMessageExpr *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) { + const Stmt *RecExpr = ME->getInstanceReceiver(); + if (RecExpr) { + SVal RecV = St->getSVal(RecExpr, NContext); + if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym) + InitMethodContext = CEP->getCalleeContext(); + } + } + } N = N->pred_empty() ? NULL : *(N->pred_begin()); } + // If we are reporting a leak of the object that was allocated with alloc, + // mark its init method as interesting. + const LocationContext *InterestingMethodContext = 0; + if (InitMethodContext) { + const ProgramPoint AllocPP = AllocationNode->getLocation(); + if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>()) + if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>()) + if (ME->getMethodFamily() == OMF_alloc) + InterestingMethodContext = InitMethodContext; + } + // If allocation happened in a function different from the leak node context, // do not report the binding. assert(N && "Could not find allocation node"); @@ -2189,7 +2225,9 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N, FirstBinding = 0; } - return std::make_pair(Last, FirstBinding); + return AllocationInfo(AllocationNodeInCurrentContext, + FirstBinding, + InterestingMethodContext); } PathDiagnosticPiece* @@ -2212,12 +2250,12 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, // We are reporting a leak. Walk up the graph to get to the first node where // the symbol appeared, and also get the first VarDecl that tracked object // is stored to. - const ExplodedNode *AllocNode = 0; - const MemRegion* FirstBinding = 0; - - llvm::tie(AllocNode, FirstBinding) = + AllocationInfo AllocI = GetAllocationSite(BRC.getStateManager(), EndN, Sym); + const MemRegion* FirstBinding = AllocI.R; + BR.markInteresting(AllocI.InterestingMethodContext); + SourceManager& SM = BRC.getSourceManager(); // Compute an actual location for the leak. Sometimes a leak doesn't @@ -2289,8 +2327,9 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled, const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, - CheckerContext &Ctx) -: CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) { + CheckerContext &Ctx, + bool IncludeAllocationLine) + : CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) { // Most bug reports are cached at the location where they occurred. // With leaks, we want to unique them by the location where they were @@ -2304,9 +2343,13 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, const SourceManager& SMgr = Ctx.getSourceManager(); - llvm::tie(AllocNode, AllocBinding) = // Set AllocBinding. + AllocationInfo AllocI = GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym); + AllocNode = AllocI.N; + AllocBinding = AllocI.R; + markInteresting(AllocI.InterestingMethodContext); + // Get the SourceLocation for the allocation site. // FIXME: This will crash the analyzer if an allocation comes from an // implicit call. (Currently there are no such allocations in Cocoa, though.) @@ -2317,8 +2360,17 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, else AllocStmt = P.castAs<PostStmt>().getStmt(); assert(AllocStmt && "All allocations must come from explicit calls"); - Location = PathDiagnosticLocation::createBegin(AllocStmt, SMgr, - n->getLocationContext()); + + PathDiagnosticLocation AllocLocation = + PathDiagnosticLocation::createBegin(AllocStmt, SMgr, + AllocNode->getLocationContext()); + Location = AllocLocation; + + // Set uniqieing info, which will be used for unique the bug reports. The + // leaks should be uniqued on the allocation site. + UniqueingLocation = AllocLocation; + UniqueingDecl = AllocNode->getLocationContext()->getDecl(); + // Fill in the description of the bug. Description.clear(); llvm::raw_string_ostream os(Description); @@ -2327,9 +2379,13 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, os << "(when using garbage collection) "; os << "of an object"; - // FIXME: AllocBinding doesn't get populated for RegionStore yet. - if (AllocBinding) + if (AllocBinding) { os << " stored into '" << AllocBinding->getString() << '\''; + if (IncludeAllocationLine) { + FullSourceLoc SL(AllocStmt->getLocStart(), Ctx.getSourceManager()); + os << " (allocated on line " << SL.getSpellingLineNumber() << ")"; + } + } addVisitor(new CFRefLeakReportVisitor(sym, GCEnabled, Log)); } @@ -2370,8 +2426,14 @@ class RetainCountChecker mutable SummaryLogTy SummaryLog; mutable bool ShouldResetSummaryLog; + /// Optional setting to indicate if leak reports should include + /// the allocation line. + mutable bool IncludeAllocationLine; + public: - RetainCountChecker() : ShouldResetSummaryLog(false) {} + RetainCountChecker(AnalyzerOptions &AO) + : ShouldResetSummaryLog(false), + IncludeAllocationLine(shouldIncludeAllocationSiteInLeakDiagnostics(AO)) {} virtual ~RetainCountChecker() { DeleteContainerSeconds(DeadSymbolTags); @@ -3316,7 +3378,8 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, CFRefReport *report = new CFRefLeakReport(*getLeakAtReturnBug(LOpts, GCEnabled), LOpts, GCEnabled, SummaryLog, - N, Sym, C); + N, Sym, C, IncludeAllocationLine); + C.emitReport(report); } } @@ -3502,10 +3565,12 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, if (N) { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); - os << "Object over-autoreleased: object was sent -autorelease "; + os << "Object was autoreleased "; if (V.getAutoreleaseCount() > 1) - os << V.getAutoreleaseCount() << " times "; - os << "but the object has a +" << V.getCount() << " retain count"; + os << V.getAutoreleaseCount() << " times but the object "; + else + os << "but "; + os << "has a +" << V.getCount() << " retain count"; if (!overAutorelease) overAutorelease.reset(new OverAutorelease()); @@ -3556,7 +3621,8 @@ RetainCountChecker::processLeaks(ProgramStateRef state, assert(BT && "BugType not initialized."); CFRefLeakReport *report = new CFRefLeakReport(*BT, LOpts, GCEnabled, - SummaryLog, N, *I, Ctx); + SummaryLog, N, *I, Ctx, + IncludeAllocationLine); Ctx.emitReport(report); } } @@ -3661,8 +3727,10 @@ void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State, RefBindingsTy B = State->get<RefBindings>(); - if (!B.isEmpty()) - Out << Sep << NL; + if (B.isEmpty()) + return; + + Out << Sep << NL; for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { Out << I->first << " : "; @@ -3676,6 +3744,6 @@ void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State, //===----------------------------------------------------------------------===// void ento::registerRetainCountChecker(CheckerManager &Mgr) { - Mgr.registerChecker<RetainCountChecker>(); + Mgr.registerChecker<RetainCountChecker>(Mgr.getAnalyzerOptions()); } diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index 7a5d993601..ed96c401a7 100644 --- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -55,8 +55,17 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS, // void test() { // return foo(); // } - if (RT.isNull() || !RT->isVoidType()) - emitUndef(C, RetE); + if (!RT.isNull() && RT->isVoidType()) + return; + + // Not all blocks have explicitly-specified return types; if the return type + // is not available, but the return value expression has 'void' type, assume + // Sema already checked it. + if (RT.isNull() && isa<BlockDecl>(SFC->getDecl()) && + RetE->getType()->isVoidType()) + return; + + emitUndef(C, RetE); return; } diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 1c38ab0b18..ffdf2d54b4 100644 --- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -400,9 +400,8 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, SymbolRef Sym = *I; ProgramStateRef state = C.getState(); const StreamState *SS = state->get<StreamMap>(Sym); - // TODO: Shouldn't we have a continue here? if (!SS) - return; + continue; if (SS->isOpened()) { ExplodedNode *N = C.generateSink(); diff --git a/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp b/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp index 8b242404b3..57c9ed4ce2 100644 --- a/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp @@ -61,9 +61,11 @@ void ento::registerTraversalDumper(CheckerManager &mgr) { //------------------------------------------------------------------------------ namespace { -class CallDumper : public Checker< check::PreCall > { +class CallDumper : public Checker< check::PreCall, + check::PostCall > { public: void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + void checkPostCall(const CallEvent &Call, CheckerContext &C) const; }; } @@ -80,6 +82,26 @@ void CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const { Call.dump(llvm::outs()); } +void CallDumper::checkPostCall(const CallEvent &Call, CheckerContext &C) const { + const Expr *CallE = Call.getOriginExpr(); + if (!CallE) + return; + + unsigned Indentation = 0; + for (const LocationContext *LC = C.getLocationContext()->getParent(); + LC != 0; LC = LC->getParent()) + ++Indentation; + + // It is mildly evil to print directly to llvm::outs() rather than emitting + // warnings, but this ensures things do not get filtered out by the rest of + // the static analyzer machinery. + llvm::outs().indent(Indentation); + if (Call.getResultType()->isVoidType()) + llvm::outs() << "Returning void\n"; + else + llvm::outs() << "Returning " << C.getSVal(CallE) << "\n"; +} + void ento::registerCallDumper(CheckerManager &mgr) { mgr.registerChecker<CallDumper>(); } diff --git a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp index f0ca8a8312..93812f7148 100644 --- a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp @@ -91,7 +91,8 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE, BugReport *R = new BugReport(*BT, os.str(), N); if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD)) R->addRange(Ex->getSourceRange()); - R->addVisitor(new FindLastStoreBRVisitor(*V, VR)); + R->addVisitor(new FindLastStoreBRVisitor(*V, VR, + /*EnableNullFPSuppression*/false)); R->disablePathPruning(); // need location of block C.emitReport(R); diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp index be3a34f3ea..176ee48082 100644 --- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp @@ -34,18 +34,28 @@ public: void UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A, CheckerContext &C) const { - if (C.getState()->getSVal(A->getIdx(), C.getLocationContext()).isUndef()) { - if (ExplodedNode *N = C.generateSink()) { - if (!BT) - BT.reset(new BuiltinBug("Array subscript is undefined")); - - // Generate a report for this bug. - BugReport *R = new BugReport(*BT, BT->getName(), N); - R->addRange(A->getIdx()->getSourceRange()); - bugreporter::trackNullOrUndefValue(N, A->getIdx(), *R); - C.emitReport(R); - } - } + const Expr *Index = A->getIdx(); + if (!C.getSVal(Index).isUndef()) + return; + + // Sema generates anonymous array variables for copying array struct fields. + // Don't warn if we're in an implicitly-generated constructor. + const Decl *D = C.getLocationContext()->getDecl(); + if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) + if (Ctor->isImplicitlyDefined()) + return; + + ExplodedNode *N = C.generateSink(); + if (!N) + return; + if (!BT) + BT.reset(new BuiltinBug("Array subscript is undefined")); + + // Generate a report for this bug. + BugReport *R = new BugReport(*BT, BT->getName(), N); + R->addRange(A->getIdx()->getSourceRange()); + bugreporter::trackNullOrUndefValue(N, A->getIdx(), *R); + C.emitReport(R); } void ento::registerUndefinedArraySubscriptChecker(CheckerManager &mgr) { diff --git a/lib/StaticAnalyzer/Core/APSIntType.cpp b/lib/StaticAnalyzer/Core/APSIntType.cpp index 884b0faa9e..c7e9526821 100644 --- a/lib/StaticAnalyzer/Core/APSIntType.cpp +++ b/lib/StaticAnalyzer/Core/APSIntType.cpp @@ -13,20 +13,31 @@ using namespace clang; using namespace ento; APSIntType::RangeTestResultKind -APSIntType::testInRange(const llvm::APSInt &Value) const { +APSIntType::testInRange(const llvm::APSInt &Value, + bool AllowSignConversions) const { + // Negative numbers cannot be losslessly converted to unsigned type. - if (IsUnsigned && Value.isSigned() && Value.isNegative()) + if (IsUnsigned && !AllowSignConversions && + Value.isSigned() && Value.isNegative()) return RTR_Below; - // Signed integers can be converted to signed integers of the same width - // or (if positive) unsigned integers with one fewer bit. - // Unsigned integers can be converted to unsigned integers of the same width - // or signed integers with one more bit. unsigned MinBits; - if (Value.isSigned()) - MinBits = Value.getMinSignedBits() - IsUnsigned; - else - MinBits = Value.getActiveBits() + !IsUnsigned; + if (AllowSignConversions) { + if (Value.isSigned() && !IsUnsigned) + MinBits = Value.getMinSignedBits(); + else + MinBits = Value.getActiveBits(); + + } else { + // Signed integers can be converted to signed integers of the same width + // or (if positive) unsigned integers with one fewer bit. + // Unsigned integers can be converted to unsigned integers of the same width + // or signed integers with one more bit. + if (Value.isSigned()) + MinBits = Value.getMinSignedBits() - IsUnsigned; + else + MinBits = Value.getActiveBits() + !IsUnsigned; + } if (MinBits <= BitWidth) return RTR_Within; diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp index 011d4c09a2..747b73c416 100644 --- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -25,7 +25,8 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, /*AddImplicitDtors=*/true, /*AddInitializers=*/true, Options.includeTemporaryDtorsInCFG(), - Options.shouldSynthesizeBodies()), + Options.shouldSynthesizeBodies(), + Options.shouldConditionalizeStaticInitializers()), Ctx(ctx), Diags(diags), LangOpts(lang), diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index dca68f71ab..ae707395fc 100644 --- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -74,7 +74,7 @@ AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) { static const char *ModeKey = "c++-inlining"; StringRef ModeStr(Config.GetOrCreateValue(ModeKey, - "constructors").getValue()); + "destructors").getValue()); CXXInlineableMemberKind &MutableMode = const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode); @@ -134,6 +134,13 @@ bool AnalyzerOptions::mayInlineTemplateFunctions() { /*Default=*/true); } +bool AnalyzerOptions::mayInlineCXXContainerCtorsAndDtors() { + return getBooleanOption(InlineCXXContainerCtorsAndDtors, + "c++-container-inlining", + /*Default=*/false); +} + + bool AnalyzerOptions::mayInlineObjCMethod() { return getBooleanOption(ObjCInliningMode, "objc-inlining", @@ -158,6 +165,12 @@ bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() { /* Default = */ true); } +bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() { + return getBooleanOption(SuppressFromCXXStandardLibrary, + "suppress-c++-stdlib", + /* Default = */ false); +} + int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) { SmallString<10> StrBuf; llvm::raw_svector_ostream OS(StrBuf); @@ -236,3 +249,8 @@ bool AnalyzerOptions::shouldSynthesizeBodies() { bool AnalyzerOptions::shouldPrunePaths() { return getBooleanOption("prune-paths", true); } + +bool AnalyzerOptions::shouldConditionalizeStaticInitializers() { + return getBooleanOption("cfg-conditional-static-initializers", true); +} + diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index 0729b5e842..a85235c3e4 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -12,6 +12,8 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "BugReporter" + #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -29,12 +31,19 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Support/raw_ostream.h" #include <queue> using namespace clang; using namespace ento; +STATISTIC(MaxBugClassSize, + "The maximum number of bug reports in the same equivalence class"); +STATISTIC(MaxValidBugClassSize, + "The maximum number of bug reports in the same equivalence class " + "where at least one report is valid (not suppressed)"); + BugReporterVisitor::~BugReporterVisitor() {} void BugReporterContext::anchor() {} @@ -43,77 +52,22 @@ void BugReporterContext::anchor() {} // Helper routines for walking the ExplodedGraph and fetching statements. //===----------------------------------------------------------------------===// -static inline const Stmt *GetStmt(const ProgramPoint &P) { - if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) - return SP->getStmt(); - if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) - return BE->getSrc()->getTerminator(); - if (Optional<CallEnter> CE = P.getAs<CallEnter>()) - return CE->getCallExpr(); - if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) - return CEE->getCalleeContext()->getCallSite(); - - return 0; -} - -static inline const ExplodedNode* -GetPredecessorNode(const ExplodedNode *N) { - return N->pred_empty() ? NULL : *(N->pred_begin()); -} - -static inline const ExplodedNode* -GetSuccessorNode(const ExplodedNode *N) { - return N->succ_empty() ? NULL : *(N->succ_begin()); -} - static const Stmt *GetPreviousStmt(const ExplodedNode *N) { - for (N = GetPredecessorNode(N); N; N = GetPredecessorNode(N)) - if (const Stmt *S = GetStmt(N->getLocation())) - return S; - - return 0; -} - -static const Stmt *GetNextStmt(const ExplodedNode *N) { - for (N = GetSuccessorNode(N); N; N = GetSuccessorNode(N)) - if (const Stmt *S = GetStmt(N->getLocation())) { - // Check if the statement is '?' or '&&'/'||'. These are "merges", - // not actual statement points. - switch (S->getStmtClass()) { - case Stmt::ChooseExprClass: - case Stmt::BinaryConditionalOperatorClass: continue; - case Stmt::ConditionalOperatorClass: continue; - case Stmt::BinaryOperatorClass: { - BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode(); - if (Op == BO_LAnd || Op == BO_LOr) - continue; - break; - } - default: - break; - } + for (N = N->getFirstPred(); N; N = N->getFirstPred()) + if (const Stmt *S = PathDiagnosticLocation::getStmt(N)) return S; - } return 0; } static inline const Stmt* GetCurrentOrPreviousStmt(const ExplodedNode *N) { - if (const Stmt *S = GetStmt(N->getLocation())) + if (const Stmt *S = PathDiagnosticLocation::getStmt(N)) return S; return GetPreviousStmt(N); } -static inline const Stmt* -GetCurrentOrNextStmt(const ExplodedNode *N) { - if (const Stmt *S = GetStmt(N->getLocation())) - return S; - - return GetNextStmt(N); -} - //===----------------------------------------------------------------------===// // Diagnostic cleanup. //===----------------------------------------------------------------------===// @@ -189,10 +143,16 @@ static void removeRedundantMsgs(PathPieces &path) { } } +/// A map from PathDiagnosticPiece to the LocationContext of the inlined +/// function call it represents. +typedef llvm::DenseMap<const PathPieces *, const LocationContext *> + LocationContextMap; + /// Recursively scan through a path and prune out calls and macros pieces /// that aren't needed. Return true if afterwards the path contains /// "interesting stuff" which means it shouldn't be pruned from the parent path. -bool BugReporter::RemoveUnneededCalls(PathPieces &pieces, BugReport *R) { +static bool removeUnneededCalls(PathPieces &pieces, BugReport *R, + LocationContextMap &LCM) { bool containsSomethingInteresting = false; const unsigned N = pieces.size(); @@ -213,13 +173,13 @@ bool BugReporter::RemoveUnneededCalls(PathPieces &pieces, BugReport *R) { case PathDiagnosticPiece::Call: { PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece); // Check if the location context is interesting. - assert(LocationContextMap.count(call)); - if (R->isInteresting(LocationContextMap[call])) { + assert(LCM.count(&call->path)); + if (R->isInteresting(LCM[&call->path])) { containsSomethingInteresting = true; break; } - if (!RemoveUnneededCalls(call->path, R)) + if (!removeUnneededCalls(call->path, R, LCM)) continue; containsSomethingInteresting = true; @@ -227,7 +187,7 @@ bool BugReporter::RemoveUnneededCalls(PathPieces &pieces, BugReport *R) { } case PathDiagnosticPiece::Macro: { PathDiagnosticMacroPiece *macro = cast<PathDiagnosticMacroPiece>(piece); - if (!RemoveUnneededCalls(macro->subPieces, R)) + if (!removeUnneededCalls(macro->subPieces, R, LCM)) continue; containsSomethingInteresting = true; break; @@ -290,19 +250,14 @@ static void adjustCallLocations(PathPieces &Pieces, // PathDiagnosticBuilder and its associated routines and helper objects. //===----------------------------------------------------------------------===// -typedef llvm::DenseMap<const ExplodedNode*, -const ExplodedNode*> NodeBackMap; - namespace { class NodeMapClosure : public BugReport::NodeResolver { - NodeBackMap& M; + InterExplodedGraphMap &M; public: - NodeMapClosure(NodeBackMap *m) : M(*m) {} - ~NodeMapClosure() {} + NodeMapClosure(InterExplodedGraphMap &m) : M(m) {} const ExplodedNode *getOriginalNode(const ExplodedNode *N) { - NodeBackMap::iterator I = M.find(N); - return I == M.end() ? 0 : I->second; + return M.lookup(N); } }; @@ -314,7 +269,7 @@ public: const LocationContext *LC; PathDiagnosticBuilder(GRBugReporter &br, - BugReport *r, NodeBackMap *Backmap, + BugReport *r, InterExplodedGraphMap &Backmap, PathDiagnosticConsumer *pdc) : BugReporterContext(br), R(r), PDC(pdc), NMC(Backmap), LC(r->getErrorNode()->getLocationContext()) @@ -351,7 +306,7 @@ public: PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode *N) { - if (const Stmt *S = GetNextStmt(N)) + if (const Stmt *S = PathDiagnosticLocation::getNextStmt(N)) return PathDiagnosticLocation(S, getSourceManager(), LC); return PathDiagnosticLocation::createDeclEnd(N->getLocationContext(), @@ -562,6 +517,7 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM); static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, + LocationContextMap &LCM, ArrayRef<BugReporterVisitor *> visitors) { SourceManager& SMgr = PDB.getSourceManager(); @@ -574,7 +530,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, while (NextNode) { N = NextNode; PDB.LC = N->getLocationContext(); - NextNode = GetPredecessorNode(N); + NextNode = N->getFirstPred(); ProgramPoint P = N->getLocation(); @@ -582,8 +538,8 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) { PathDiagnosticCallPiece *C = PathDiagnosticCallPiece::construct(N, *CE, SMgr); - GRBugReporter& BR = PDB.getBugReporter(); - BR.addCallPieceLocationContextPair(C, CE->getCalleeContext()); + // Record the mapping from call piece to LocationContext. + LCM[&C->path] = CE->getCalleeContext(); PD.getActivePath().push_front(C); PD.pushActivePath(&C->path); CallStack.push_back(StackDiagPair(C, N)); @@ -606,8 +562,8 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, } else { const Decl *Caller = CE->getLocationContext()->getDecl(); C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller); - GRBugReporter& BR = PDB.getBugReporter(); - BR.addCallPieceLocationContextPair(C, CE->getCalleeContext()); + // Record the mapping from call piece to LocationContext. + LCM[&C->path] = CE->getCalleeContext(); } C->setCallee(*CE, SMgr); @@ -636,7 +592,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, case Stmt::GotoStmtClass: case Stmt::IndirectGotoStmtClass: { - const Stmt *S = GetNextStmt(N); + const Stmt *S = PathDiagnosticLocation::getNextStmt(N); if (!S) break; @@ -925,6 +881,50 @@ public: bool isDead() const { return IsDead; } }; +static PathDiagnosticLocation cleanUpLocation(PathDiagnosticLocation L, + const LocationContext *LC, + bool firstCharOnly = false) { + if (const Stmt *S = L.asStmt()) { + const Stmt *Original = S; + while (1) { + // Adjust the location for some expressions that are best referenced + // by one of their subexpressions. + switch (S->getStmtClass()) { + default: + break; + case Stmt::ParenExprClass: + case Stmt::GenericSelectionExprClass: + S = cast<Expr>(S)->IgnoreParens(); + firstCharOnly = true; + continue; + case Stmt::BinaryConditionalOperatorClass: + case Stmt::ConditionalOperatorClass: + S = cast<AbstractConditionalOperator>(S)->getCond(); + firstCharOnly = true; + continue; + case Stmt::ChooseExprClass: + S = cast<ChooseExpr>(S)->getCond(); + firstCharOnly = true; + continue; + case Stmt::BinaryOperatorClass: + S = cast<BinaryOperator>(S)->getLHS(); + firstCharOnly = true; + continue; + } + + break; + } + + if (S != Original) + L = PathDiagnosticLocation(S, L.getManager(), LC); + } + + if (firstCharOnly) + L = PathDiagnosticLocation::createSingleLocation(L); + + return L; +} + class EdgeBuilder { std::vector<ContextLocation> CLocs; typedef std::vector<ContextLocation>::iterator iterator; @@ -939,53 +939,12 @@ class EdgeBuilder { PathDiagnosticLocation getContextLocation(const PathDiagnosticLocation &L); - PathDiagnosticLocation cleanUpLocation(PathDiagnosticLocation L, - bool firstCharOnly = false) { - if (const Stmt *S = L.asStmt()) { - const Stmt *Original = S; - while (1) { - // Adjust the location for some expressions that are best referenced - // by one of their subexpressions. - switch (S->getStmtClass()) { - default: - break; - case Stmt::ParenExprClass: - case Stmt::GenericSelectionExprClass: - S = cast<Expr>(S)->IgnoreParens(); - firstCharOnly = true; - continue; - case Stmt::BinaryConditionalOperatorClass: - case Stmt::ConditionalOperatorClass: - S = cast<AbstractConditionalOperator>(S)->getCond(); - firstCharOnly = true; - continue; - case Stmt::ChooseExprClass: - S = cast<ChooseExpr>(S)->getCond(); - firstCharOnly = true; - continue; - case Stmt::BinaryOperatorClass: - S = cast<BinaryOperator>(S)->getLHS(); - firstCharOnly = true; - continue; - } - - break; - } - - if (S != Original) - L = PathDiagnosticLocation(S, L.getManager(), PDB.LC); - } - - if (firstCharOnly) - L = PathDiagnosticLocation::createSingleLocation(L); - return L; - } void popLocation() { if (!CLocs.back().isDead() && CLocs.back().asLocation().isFileID()) { // For contexts, we only one the first character as the range. - rawAddEdge(cleanUpLocation(CLocs.back(), true)); + rawAddEdge(cleanUpLocation(CLocs.back(), PDB.LC, true)); } CLocs.pop_back(); } @@ -1022,7 +981,8 @@ public: PrevLoc = PathDiagnosticLocation(); } - void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false); + void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false, + bool IsPostJump = false); void rawAddEdge(PathDiagnosticLocation NewLoc); @@ -1098,8 +1058,8 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) { return; } - const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc); - const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc); + const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc, PDB.LC); + const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc, PDB.LC); if (PrevLocClean.asLocation().isInvalid()) { PrevLoc = NewLoc; @@ -1118,7 +1078,8 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) { PrevLoc = NewLoc; } -void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) { +void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd, + bool IsPostJump) { if (!alwaysAdd && NewLoc.asLocation().isMacroID()) return; @@ -1131,13 +1092,14 @@ void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) { // Is the top location context the same as the one for the new location? if (TopContextLoc == CLoc) { if (alwaysAdd) { - if (IsConsumedExpr(TopContextLoc) && - !IsControlFlowExpr(TopContextLoc.asStmt())) - TopContextLoc.markDead(); + if (IsConsumedExpr(TopContextLoc)) + TopContextLoc.markDead(); rawAddEdge(NewLoc); } + if (IsPostJump) + TopContextLoc.markDead(); return; } @@ -1145,13 +1107,13 @@ void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) { if (alwaysAdd) { rawAddEdge(NewLoc); - if (IsConsumedExpr(CLoc) && !IsControlFlowExpr(CLoc.asStmt())) { - CLocs.push_back(ContextLocation(CLoc, true)); + if (IsConsumedExpr(CLoc)) { + CLocs.push_back(ContextLocation(CLoc, /*IsDead=*/true)); return; } } - CLocs.push_back(CLoc); + CLocs.push_back(ContextLocation(CLoc, /*IsDead=*/IsPostJump)); return; } @@ -1305,6 +1267,7 @@ static bool isLoopJumpPastBody(const Stmt *Term, const BlockEdge *BE) { switch (Term->getStmtClass()) { case Stmt::ForStmtClass: case Stmt::WhileStmtClass: + case Stmt::ObjCForCollectionStmtClass: break; default: // Note that we intentionally do not include do..while here. @@ -1335,7 +1298,7 @@ static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term, if (!isContainedByStmt(PM, Term, S)) return S; } - N = GetPredecessorNode(N); + N = N->getFirstPred(); } return 0; } @@ -1350,6 +1313,11 @@ static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) { LoopBody = FS->getBody(); break; } + case Stmt::ObjCForCollectionStmtClass: { + const ObjCForCollectionStmt *FC = cast<ObjCForCollectionStmt>(Term); + LoopBody = FC->getBody(); + break; + } case Stmt::WhileStmtClass: LoopBody = cast<WhileStmt>(Term)->getBody(); break; @@ -1366,6 +1334,7 @@ static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) { static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, + LocationContextMap &LCM, ArrayRef<BugReporterVisitor *> visitors) { EdgeBuilder EB(PD, PDB); const SourceManager& SM = PDB.getSourceManager(); @@ -1375,7 +1344,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin()); while (NextNode) { N = NextNode; - NextNode = GetPredecessorNode(N); + NextNode = N->getFirstPred(); ProgramPoint P = N->getLocation(); do { @@ -1396,10 +1365,9 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, PathDiagnosticCallPiece *C = PathDiagnosticCallPiece::construct(N, *CE, SM); - GRBugReporter& BR = PDB.getBugReporter(); - BR.addCallPieceLocationContextPair(C, CE->getCalleeContext()); + LCM[&C->path] = CE->getCalleeContext(); - EB.addEdge(C->callReturn, true); + EB.addEdge(C->callReturn, /*AlwaysAdd=*/true, /*IsPostJump=*/true); EB.flushLocations(); PD.getActivePath().push_front(C); @@ -1434,8 +1402,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, } else { const Decl *Caller = CE->getLocationContext()->getDecl(); C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller); - GRBugReporter& BR = PDB.getBugReporter(); - BR.addCallPieceLocationContextPair(C, CE->getCalleeContext()); + LCM[&C->path] = CE->getCalleeContext(); } C->setCallee(*CE, SM); @@ -1563,6 +1530,458 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, return PDB.getBugReport()->isValid(); } +/// \brief Adds a sanitized control-flow diagnostic edge to a path. +static void addEdgeToPath(PathPieces &path, + PathDiagnosticLocation &PrevLoc, + PathDiagnosticLocation NewLoc, + const LocationContext *LC) { + if (!NewLoc.isValid()) + return; + + SourceLocation NewLocL = NewLoc.asLocation(); + if (NewLocL.isInvalid() || NewLocL.isMacroID()) + return; + + if (!PrevLoc.isValid()) { + PrevLoc = NewLoc; + return; + } + + // FIXME: ignore intra-macro edges for now. + if (NewLoc.asLocation().getExpansionLoc() == + PrevLoc.asLocation().getExpansionLoc()) + return; + + path.push_front(new PathDiagnosticControlFlowPiece(NewLoc, + PrevLoc)); + PrevLoc = NewLoc; +} + +static bool +GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, + PathDiagnosticBuilder &PDB, + const ExplodedNode *N, + LocationContextMap &LCM, + ArrayRef<BugReporterVisitor *> visitors) { + + BugReport *report = PDB.getBugReport(); + const SourceManager& SM = PDB.getSourceManager(); + StackDiagVector CallStack; + InterestingExprs IE; + + // Record the last location for a given visited stack frame. + llvm::DenseMap<const StackFrameContext *, PathDiagnosticLocation> + PrevLocMap; + + const ExplodedNode *NextNode = N->getFirstPred(); + while (NextNode) { + N = NextNode; + NextNode = N->getFirstPred(); + ProgramPoint P = N->getLocation(); + const LocationContext *LC = N->getLocationContext(); + assert(!LCM[&PD.getActivePath()] || LCM[&PD.getActivePath()] == LC); + LCM[&PD.getActivePath()] = LC; + PathDiagnosticLocation &PrevLoc = PrevLocMap[LC->getCurrentStackFrame()]; + + do { + if (Optional<PostStmt> PS = P.getAs<PostStmt>()) { + // For expressions, make sure we propagate the + // interesting symbols correctly. + if (const Expr *Ex = PS->getStmtAs<Expr>()) + reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, + N->getState().getPtr(), Ex, + N->getLocationContext()); + + PathDiagnosticLocation L = + PathDiagnosticLocation(PS->getStmt(), SM, LC); + addEdgeToPath(PD.getActivePath(), PrevLoc, L, LC); + break; + } + + // Have we encountered an exit from a function call? + if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) { + const Stmt *S = CE->getCalleeContext()->getCallSite(); + // Propagate the interesting symbols accordingly. + if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) { + reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, + N->getState().getPtr(), Ex, + N->getLocationContext()); + } + + // We are descending into a call (backwards). Construct + // a new call piece to contain the path pieces for that call. + PathDiagnosticCallPiece *C = + PathDiagnosticCallPiece::construct(N, *CE, SM); + + // Record the location context for this call piece. + LCM[&C->path] = CE->getCalleeContext(); + + // Add the edge to the return site. + addEdgeToPath(PD.getActivePath(), PrevLoc, C->callReturn, LC); + + // Make the contents of the call the active path for now. + PD.pushActivePath(&C->path); + CallStack.push_back(StackDiagPair(C, N)); + break; + } + + // Have we encountered an entrance to a call? It may be + // the case that we have not encountered a matching + // call exit before this point. This means that the path + // terminated within the call itself. + if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { + // Add an edge to the start of the function. + const Decl *D = CE->getCalleeContext()->getDecl(); + addEdgeToPath(PD.getActivePath(), PrevLoc, + PathDiagnosticLocation::createBegin(D, SM), LC); + + // Did we visit an entire call? + bool VisitedEntireCall = PD.isWithinCall(); + PD.popActivePath(); + + PathDiagnosticCallPiece *C; + if (VisitedEntireCall) { + C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front()); + } else { + const Decl *Caller = CE->getLocationContext()->getDecl(); + C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller); + LCM[&C->path] = CE->getCalleeContext(); + } + C->setCallee(*CE, SM); + + if (!CallStack.empty()) { + assert(CallStack.back().first == C); + CallStack.pop_back(); + } + break; + } + + // Block edges. + if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { + // Does this represent entering a call? If so, look at propagating + // interesting symbols across call boundaries. + if (NextNode) { + const LocationContext *CallerCtx = NextNode->getLocationContext(); + const LocationContext *CalleeCtx = PDB.LC; + if (CallerCtx != CalleeCtx) { + reversePropagateInterestingSymbols(*PDB.getBugReport(), IE, + N->getState().getPtr(), + CalleeCtx, CallerCtx); + } + } + + // Are we jumping to the head of a loop? Add a special diagnostic. + if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) { + PathDiagnosticLocation L(Loop, SM, PDB.LC); + const CompoundStmt *CS = NULL; + + if (const ForStmt *FS = dyn_cast<ForStmt>(Loop)) + CS = dyn_cast<CompoundStmt>(FS->getBody()); + else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop)) + CS = dyn_cast<CompoundStmt>(WS->getBody()); + + PathDiagnosticEventPiece *p = + new PathDiagnosticEventPiece(L, "Looping back to the head " + "of the loop"); + p->setPrunable(true); + + addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), LC); + PD.getActivePath().push_front(p); + + if (CS) { + addEdgeToPath(PD.getActivePath(), PrevLoc, + PathDiagnosticLocation::createEndBrace(CS, SM), LC); + } + } + + const CFGBlock *BSrc = BE->getSrc(); + ParentMap &PM = PDB.getParentMap(); + + if (const Stmt *Term = BSrc->getTerminator()) { + // Are we jumping past the loop body without ever executing the + // loop (because the condition was false)? + if (isLoopJumpPastBody(Term, &*BE) && + !isInLoopBody(PM, + getStmtBeforeCond(PM, + BSrc->getTerminatorCondition(), + N), + Term)) + { + PathDiagnosticLocation L(Term, SM, PDB.LC); + PathDiagnosticEventPiece *PE = + new PathDiagnosticEventPiece(L, "Loop body executed 0 times"); + PE->setPrunable(true); + addEdgeToPath(PD.getActivePath(), PrevLoc, + PE->getLocation(), LC); + PD.getActivePath().push_front(PE); + } + } + break; + } + } while (0); + + if (!NextNode) + continue; + + // Add pieces from custom visitors. + for (ArrayRef<BugReporterVisitor *>::iterator I = visitors.begin(), + E = visitors.end(); + I != E; ++I) { + if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *report)) { + addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), LC); + PD.getActivePath().push_front(p); + updateStackPiecesWithMessage(p, CallStack); + } + } + } + + return report->isValid(); +} + +const Stmt *getLocStmt(PathDiagnosticLocation L) { + if (!L.isValid()) + return 0; + return L.asStmt(); +} + +const Stmt *getStmtParent(const Stmt *S, ParentMap &PM) { + if (!S) + return 0; + return PM.getParentIgnoreParens(S); +} + +#if 0 +static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond) { + // Note that we intentionally to do not handle || and && here. + switch (S->getStmtClass()) { + case Stmt::ForStmtClass: + return cast<ForStmt>(S)->getCond() == Cond; + case Stmt::WhileStmtClass: + return cast<WhileStmt>(S)->getCond() == Cond; + case Stmt::DoStmtClass: + return cast<DoStmt>(S)->getCond() == Cond; + case Stmt::ChooseExprClass: + return cast<ChooseExpr>(S)->getCond() == Cond; + case Stmt::IndirectGotoStmtClass: + return cast<IndirectGotoStmt>(S)->getTarget() == Cond; + case Stmt::SwitchStmtClass: + return cast<SwitchStmt>(S)->getCond() == Cond; + case Stmt::BinaryConditionalOperatorClass: + return cast<BinaryConditionalOperator>(S)->getCond() == Cond; + case Stmt::ConditionalOperatorClass: + return cast<ConditionalOperator>(S)->getCond() == Cond; + case Stmt::ObjCForCollectionStmtClass: + return cast<ObjCForCollectionStmt>(S)->getElement() == Cond; + default: + return false; + } +} +#endif + +typedef llvm::DenseSet<const PathDiagnosticControlFlowPiece *> + ControlFlowBarrierSet; + +typedef llvm::DenseSet<const PathDiagnosticCallPiece *> + OptimizedCallsSet; + +static bool isBarrier(ControlFlowBarrierSet &CFBS, + const PathDiagnosticControlFlowPiece *P) { + return CFBS.count(P); +} + +static bool optimizeEdges(PathPieces &path, SourceManager &SM, + ControlFlowBarrierSet &CFBS, + OptimizedCallsSet &OCS, + LocationContextMap &LCM) { + bool hasChanges = false; + const LocationContext *LC = LCM[&path]; + assert(LC); + bool isFirst = true; + + for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) { + bool wasFirst = isFirst; + isFirst = false; + + // Optimize subpaths. + if (PathDiagnosticCallPiece *CallI = dyn_cast<PathDiagnosticCallPiece>(*I)){ + // Record the fact that a call has been optimized so we only do the + // effort once. + if (!OCS.count(CallI)) { + while (optimizeEdges(CallI->path, SM, CFBS, OCS, LCM)) {} + OCS.insert(CallI); + } + ++I; + continue; + } + + // Pattern match the current piece and its successor. + PathDiagnosticControlFlowPiece *PieceI = + dyn_cast<PathDiagnosticControlFlowPiece>(*I); + + if (!PieceI) { + ++I; + continue; + } + + ParentMap &PM = LC->getParentMap(); + const Stmt *s1Start = getLocStmt(PieceI->getStartLocation()); + const Stmt *s1End = getLocStmt(PieceI->getEndLocation()); + const Stmt *level1 = getStmtParent(s1Start, PM); + const Stmt *level2 = getStmtParent(s1End, PM); + + if (wasFirst) { +#if 0 + // Apply the "first edge" case for Rule V. here. + if (s1Start && level1 && isConditionForTerminator(level1, s1Start)) { + PathDiagnosticLocation NewLoc(level2, SM, LC); + PieceI->setStartLocation(NewLoc); + CFBS.insert(PieceI); + return true; + } +#endif + // Apply the "first edge" case for Rule III. here. + if (!isBarrier(CFBS, PieceI) && + level1 && level2 && level2 == PM.getParent(level1)) { + path.erase(I); + // Since we are erasing the current edge at the start of the + // path, just return now so we start analyzing the start of the path + // again. + return true; + } + } + + PathPieces::iterator NextI = I; ++NextI; + if (NextI == E) + break; + + PathDiagnosticControlFlowPiece *PieceNextI = + dyn_cast<PathDiagnosticControlFlowPiece>(*NextI); + + if (!PieceNextI) { + ++I; + continue; + } + + const Stmt *s2Start = getLocStmt(PieceNextI->getStartLocation()); + const Stmt *s2End = getLocStmt(PieceNextI->getEndLocation()); + const Stmt *level3 = getStmtParent(s2Start, PM); + const Stmt *level4 = getStmtParent(s2End, PM); + + // Rule I. + // + // If we have two consecutive control edges whose end/begin locations + // are at the same level (e.g. statements or top-level expressions within + // a compound statement, or siblings share a single ancestor expression), + // then merge them if they have no interesting intermediate event. + // + // For example: + // + // (1.1 -> 1.2) -> (1.2 -> 1.3) becomes (1.1 -> 1.3) because the common + // parent is '1'. Here 'x.y.z' represents the hierarchy of statements. + // + // NOTE: this will be limited later in cases where we add barriers + // to prevent this optimization. + // + if (level1 && level1 == level2 && level1 == level3 && level1 == level4) { + PieceI->setEndLocation(PieceNextI->getEndLocation()); + path.erase(NextI); + hasChanges = true; + continue; + } + + // Rule II. + // + // If we have two consecutive control edges where we decend to a + // subexpression and then pop out merge them. + // + // NOTE: this will be limited later in cases where we add barriers + // to prevent this optimization. + // + // For example: + // + // (1.1 -> 1.1.1) -> (1.1.1 -> 1.2) becomes (1.1 -> 1.2). + if (level1 && level2 && + level1 == level4 && + level2 == level3 && PM.getParentIgnoreParens(level2) == level1) { + PieceI->setEndLocation(PieceNextI->getEndLocation()); + path.erase(NextI); + hasChanges = true; + continue; + } + + // Rule III. + // + // Eliminate unnecessary edges where we descend to a subexpression from + // a statement at the same level as our parent. + // + // NOTE: this will be limited later in cases where we add barriers + // to prevent this optimization. + // + // For example: + // + // (1.1 -> 1.1.1) -> (1.1.1 -> X) becomes (1.1 -> X). + // + if (level1 && level2 && level1 == PM.getParentIgnoreParens(level2)) { + PieceI->setEndLocation(PieceNextI->getEndLocation()); + path.erase(NextI); + hasChanges = true; + continue; + } + + // Rule IV. + // + // Eliminate unnecessary edges where we ascend from a subexpression to + // a statement at the same level as our parent. + // + // NOTE: this will be limited later in cases where we add barriers + // to prevent this optimization. + // + // For example: + // + // (X -> 1.1.1) -> (1.1.1 -> 1.1) becomes (X -> 1.1). + // [first edge] (1.1.1 -> 1.1) -> eliminate + // + if (level2 && level4 && level2 == level3 && level4 == PM.getParent(level2)){ + PieceI->setEndLocation(PieceNextI->getEndLocation()); + path.erase(NextI); + hasChanges = true; + continue; + } +#if 0 + // Rule V. + // + // Replace terminator conditions with terminators when the condition + // itself has no control-flow. + // + // For example: + // + // (X -> condition) -> (condition -> Y) becomes (X -> term) -> (term -> Y) + // [first edge] (condition -> Y) becomes (term -> Y) + // + // This applies to 'if', 'for', 'while', 'do .. while', 'switch'... + // + if (!isBarrier(CFBS, PieceNextI) && + s1End && s1End == s2Start && level2) { + if (isConditionForTerminator(level2, s1End)) { + PathDiagnosticLocation NewLoc(level2, SM, LC); + PieceI->setEndLocation(NewLoc); + PieceNextI->setStartLocation(NewLoc); + CFBS.insert(PieceI); + hasChanges = true; + continue; + } + + } +#endif + + // No changes at this index? Move to the next one. + ++I; + } + + // No changes. + return hasChanges; +} + //===----------------------------------------------------------------------===// // Methods for BugType and subclasses. //===----------------------------------------------------------------------===// @@ -1748,7 +2167,7 @@ const Stmt *BugReport::getStmt() const { S = GetPreviousStmt(ErrorNode); } if (!S) - S = GetStmt(ProgP); + S = PathDiagnosticLocation::getStmt(ErrorNode); return S; } @@ -1775,22 +2194,7 @@ PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const { if (ErrorNode) { assert(!Location.isValid() && "Either Location or ErrorNode should be specified but not both."); - - if (const Stmt *S = GetCurrentOrPreviousStmt(ErrorNode)) { - const LocationContext *LC = ErrorNode->getLocationContext(); - - // For member expressions, return the location of the '.' or '->'. - if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) - return PathDiagnosticLocation::createMemberLoc(ME, SM); - // For binary operators, return the location of the operator. - if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) - return PathDiagnosticLocation::createOperatorLoc(B, SM); - - if (ErrorNode->getLocation().getAs<PostStmtPurgeDeadSymbols>()) - return PathDiagnosticLocation::createEnd(S, SM, LC); - - return PathDiagnosticLocation::createBegin(S, SM, LC); - } + return PathDiagnosticLocation::createEndOfPath(ErrorNode, SM); } else { assert(Location.isValid()); return Location; @@ -1863,141 +2267,175 @@ void BugReporter::FlushReports() { // PathDiagnostics generation. //===----------------------------------------------------------------------===// -static std::pair<std::pair<ExplodedGraph*, NodeBackMap*>, - std::pair<ExplodedNode*, unsigned> > -MakeReportGraph(const ExplodedGraph* G, - SmallVectorImpl<const ExplodedNode*> &nodes) { +namespace { +/// A wrapper around a report graph, which contains only a single path, and its +/// node maps. +class ReportGraph { +public: + InterExplodedGraphMap BackMap; + OwningPtr<ExplodedGraph> Graph; + const ExplodedNode *ErrorNode; + size_t Index; +}; + +/// A wrapper around a trimmed graph and its node maps. +class TrimmedGraph { + InterExplodedGraphMap InverseMap; + + typedef llvm::DenseMap<const ExplodedNode *, unsigned> PriorityMapTy; + PriorityMapTy PriorityMap; + + typedef std::pair<const ExplodedNode *, size_t> NodeIndexPair; + SmallVector<NodeIndexPair, 32> ReportNodes; - // Create the trimmed graph. It will contain the shortest paths from the - // error nodes to the root. In the new graph we should only have one - // error node unless there are two or more error nodes with the same minimum - // path length. - ExplodedGraph* GTrim; - InterExplodedGraphMap* NMap; + OwningPtr<ExplodedGraph> G; - llvm::DenseMap<const void*, const void*> InverseMap; - llvm::tie(GTrim, NMap) = G->Trim(nodes.data(), nodes.data() + nodes.size(), - &InverseMap); + /// A helper class for sorting ExplodedNodes by priority. + template <bool Descending> + class PriorityCompare { + const PriorityMapTy &PriorityMap; - // Create owning pointers for GTrim and NMap just to ensure that they are - // released when this function exists. - OwningPtr<ExplodedGraph> AutoReleaseGTrim(GTrim); - OwningPtr<InterExplodedGraphMap> AutoReleaseNMap(NMap); + public: + PriorityCompare(const PriorityMapTy &M) : PriorityMap(M) {} + + bool operator()(const ExplodedNode *LHS, const ExplodedNode *RHS) const { + PriorityMapTy::const_iterator LI = PriorityMap.find(LHS); + PriorityMapTy::const_iterator RI = PriorityMap.find(RHS); + PriorityMapTy::const_iterator E = PriorityMap.end(); + + if (LI == E) + return Descending; + if (RI == E) + return !Descending; + + return Descending ? LI->second > RI->second + : LI->second < RI->second; + } + + bool operator()(const NodeIndexPair &LHS, const NodeIndexPair &RHS) const { + return (*this)(LHS.first, RHS.first); + } + }; + +public: + TrimmedGraph(const ExplodedGraph *OriginalGraph, + ArrayRef<const ExplodedNode *> Nodes); + + bool popNextReportGraph(ReportGraph &GraphWrapper); +}; +} + +TrimmedGraph::TrimmedGraph(const ExplodedGraph *OriginalGraph, + ArrayRef<const ExplodedNode *> Nodes) { + // The trimmed graph is created in the body of the constructor to ensure + // that the DenseMaps have been initialized already. + InterExplodedGraphMap ForwardMap; + G.reset(OriginalGraph->trim(Nodes, &ForwardMap, &InverseMap)); // Find the (first) error node in the trimmed graph. We just need to consult - // the node map (NMap) which maps from nodes in the original graph to nodes + // the node map which maps from nodes in the original graph to nodes // in the new graph. + llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes; - std::queue<const ExplodedNode*> WS; - typedef llvm::DenseMap<const ExplodedNode*, unsigned> IndexMapTy; - IndexMapTy IndexMap; - - for (unsigned nodeIndex = 0 ; nodeIndex < nodes.size(); ++nodeIndex) { - const ExplodedNode *originalNode = nodes[nodeIndex]; - if (const ExplodedNode *N = NMap->getMappedNode(originalNode)) { - WS.push(N); - IndexMap[originalNode] = nodeIndex; + for (unsigned i = 0, count = Nodes.size(); i < count; ++i) { + if (const ExplodedNode *NewNode = ForwardMap.lookup(Nodes[i])) { + ReportNodes.push_back(std::make_pair(NewNode, i)); + RemainingNodes.insert(NewNode); } } - assert(!WS.empty() && "No error node found in the trimmed graph."); - - // Create a new (third!) graph with a single path. This is the graph - // that will be returned to the caller. - ExplodedGraph *GNew = new ExplodedGraph(); + assert(!RemainingNodes.empty() && "No error node found in the trimmed graph"); - // Sometimes the trimmed graph can contain a cycle. Perform a reverse BFS - // to the root node, and then construct a new graph that contains only - // a single path. - llvm::DenseMap<const void*,unsigned> Visited; + // Perform a forward BFS to find all the shortest paths. + std::queue<const ExplodedNode *> WS; - unsigned cnt = 0; - const ExplodedNode *Root = 0; + assert(G->num_roots() == 1); + WS.push(*G->roots_begin()); + unsigned Priority = 0; while (!WS.empty()) { const ExplodedNode *Node = WS.front(); WS.pop(); - if (Visited.find(Node) != Visited.end()) - continue; - - Visited[Node] = cnt++; + PriorityMapTy::iterator PriorityEntry; + bool IsNew; + llvm::tie(PriorityEntry, IsNew) = + PriorityMap.insert(std::make_pair(Node, Priority)); + ++Priority; - if (Node->pred_empty()) { - Root = Node; - break; + if (!IsNew) { + assert(PriorityEntry->second <= Priority); + continue; } - for (ExplodedNode::const_pred_iterator I=Node->pred_begin(), - E=Node->pred_end(); I!=E; ++I) + if (RemainingNodes.erase(Node)) + if (RemainingNodes.empty()) + break; + + for (ExplodedNode::const_pred_iterator I = Node->succ_begin(), + E = Node->succ_end(); + I != E; ++I) WS.push(*I); } - assert(Root); + // Sort the error paths from longest to shortest. + std::sort(ReportNodes.begin(), ReportNodes.end(), + PriorityCompare<true>(PriorityMap)); +} - // Now walk from the root down the BFS path, always taking the successor - // with the lowest number. - ExplodedNode *Last = 0, *First = 0; - NodeBackMap *BM = new NodeBackMap(); - unsigned NodeIndex = 0; +bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) { + if (ReportNodes.empty()) + return false; - for ( const ExplodedNode *N = Root ;;) { - // Lookup the number associated with the current node. - llvm::DenseMap<const void*,unsigned>::iterator I = Visited.find(N); - assert(I != Visited.end()); + const ExplodedNode *OrigN; + llvm::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val(); + assert(PriorityMap.find(OrigN) != PriorityMap.end() && + "error node not accessible from root"); + + // Create a new graph with a single path. This is the graph + // that will be returned to the caller. + ExplodedGraph *GNew = new ExplodedGraph(); + GraphWrapper.Graph.reset(GNew); + GraphWrapper.BackMap.clear(); + // Now walk from the error node up the BFS path, always taking the + // predeccessor with the lowest number. + ExplodedNode *Succ = 0; + while (true) { // Create the equivalent node in the new graph with the same state // and location. - ExplodedNode *NewN = GNew->getNode(N->getLocation(), N->getState()); + ExplodedNode *NewN = GNew->getNode(OrigN->getLocation(), OrigN->getState(), + OrigN->isSink()); // Store the mapping to the original node. - llvm::DenseMap<const void*, const void*>::iterator IMitr=InverseMap.find(N); + InterExplodedGraphMap::const_iterator IMitr = InverseMap.find(OrigN); assert(IMitr != InverseMap.end() && "No mapping to original node."); - (*BM)[NewN] = (const ExplodedNode*) IMitr->second; + GraphWrapper.BackMap[NewN] = IMitr->second; // Link up the new node with the previous node. - if (Last) - NewN->addPredecessor(Last, *GNew); + if (Succ) + Succ->addPredecessor(NewN, *GNew); + else + GraphWrapper.ErrorNode = NewN; - Last = NewN; + Succ = NewN; // Are we at the final node? - IndexMapTy::iterator IMI = - IndexMap.find((const ExplodedNode*)(IMitr->second)); - if (IMI != IndexMap.end()) { - First = NewN; - NodeIndex = IMI->second; + if (OrigN->pred_empty()) { + GNew->addRoot(NewN); break; } - // Find the next successor node. We choose the node that is marked - // with the lowest DFS number. - ExplodedNode::const_succ_iterator SI = N->succ_begin(); - ExplodedNode::const_succ_iterator SE = N->succ_end(); - N = 0; - - for (unsigned MinVal = 0; SI != SE; ++SI) { - - I = Visited.find(*SI); - - if (I == Visited.end()) - continue; - - if (!N || I->second < MinVal) { - N = *SI; - MinVal = I->second; - } - } - - assert(N); + // Find the next predeccessor node. We choose the node that is marked + // with the lowest BFS number. + OrigN = *std::min_element(OrigN->pred_begin(), OrigN->pred_end(), + PriorityCompare<false>(PriorityMap)); } - assert(First); - - return std::make_pair(std::make_pair(GNew, BM), - std::make_pair(First, NodeIndex)); + return true; } + /// CompactPathDiagnostic - This function postprocesses a PathDiagnostic object /// and collapses PathDiagosticPieces that are expanded by macros. static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) { @@ -2100,133 +2538,150 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD, assert(!bugReports.empty()); bool HasValid = false; - SmallVector<const ExplodedNode *, 10> errorNodes; + bool HasInvalid = false; + SmallVector<const ExplodedNode *, 32> errorNodes; for (ArrayRef<BugReport*>::iterator I = bugReports.begin(), E = bugReports.end(); I != E; ++I) { if ((*I)->isValid()) { HasValid = true; errorNodes.push_back((*I)->getErrorNode()); } else { + // Keep the errorNodes list in sync with the bugReports list. + HasInvalid = true; errorNodes.push_back(0); } } - // If all the reports have been marked invalid, we're done. + // If all the reports have been marked invalid by a previous path generation, + // we're done. if (!HasValid) return false; - // Construct a new graph that contains only a single path from the error - // node to a root. - const std::pair<std::pair<ExplodedGraph*, NodeBackMap*>, - std::pair<ExplodedNode*, unsigned> >& - GPair = MakeReportGraph(&getGraph(), errorNodes); - - // Find the BugReport with the original location. - assert(GPair.second.second < bugReports.size()); - BugReport *R = bugReports[GPair.second.second]; - assert(R && "No original report found for sliced graph."); - assert(R->isValid() && "Report selected from trimmed graph marked invalid."); - - OwningPtr<ExplodedGraph> ReportGraph(GPair.first.first); - OwningPtr<NodeBackMap> BackMap(GPair.first.second); - const ExplodedNode *N = GPair.second.first; - - // Start building the path diagnostic... - PathDiagnosticBuilder PDB(*this, R, BackMap.get(), &PC); - - // Register additional node visitors. - R->addVisitor(new NilReceiverBRVisitor()); - R->addVisitor(new ConditionBRVisitor()); - R->addVisitor(new LikelyFalsePositiveSuppressionBRVisitor()); - - BugReport::VisitorList visitors; - unsigned originalReportConfigToken, finalReportConfigToken; - - // While generating diagnostics, it's possible the visitors will decide - // new symbols and regions are interesting, or add other visitors based on - // the information they find. If they do, we need to regenerate the path - // based on our new report configuration. - do { - // Get a clean copy of all the visitors. - for (BugReport::visitor_iterator I = R->visitor_begin(), - E = R->visitor_end(); I != E; ++I) - visitors.push_back((*I)->clone()); - - // Clear out the active path from any previous work. - PD.resetPath(); - originalReportConfigToken = R->getConfigurationChangeToken(); - - // Generate the very last diagnostic piece - the piece is visible before - // the trace is expanded. - PathDiagnosticPiece *LastPiece = 0; - for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end(); - I != E; ++I) { - if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) { - assert (!LastPiece && - "There can only be one final piece in a diagnostic."); - LastPiece = Piece; - } - } + typedef PathDiagnosticConsumer::PathGenerationScheme PathGenerationScheme; + PathGenerationScheme ActiveScheme = PC.getGenerationScheme(); - if (PDB.getGenerationScheme() != PathDiagnosticConsumer::None) { - if (!LastPiece) - LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R); - if (LastPiece) - PD.setEndOfPath(LastPiece); - else - return false; + if (ActiveScheme == PathDiagnosticConsumer::Extensive) { + AnalyzerOptions &options = getEngine().getAnalysisManager().options; + if (options.getBooleanOption("path-diagnostics-alternate", false)) { + ActiveScheme = PathDiagnosticConsumer::AlternateExtensive; } + } - switch (PDB.getGenerationScheme()) { - case PathDiagnosticConsumer::Extensive: - if (!GenerateExtensivePathDiagnostic(PD, PDB, N, visitors)) { - assert(!R->isValid() && "Failed on valid report"); - // Try again. We'll filter out the bad report when we trim the graph. - // FIXME: It would be more efficient to use the same intermediate - // trimmed graph, and just repeat the shortest-path search. - return generatePathDiagnostic(PD, PC, bugReports); + TrimmedGraph TrimG(&getGraph(), errorNodes); + ReportGraph ErrorGraph; + + while (TrimG.popNextReportGraph(ErrorGraph)) { + // Find the BugReport with the original location. + assert(ErrorGraph.Index < bugReports.size()); + BugReport *R = bugReports[ErrorGraph.Index]; + assert(R && "No original report found for sliced graph."); + assert(R->isValid() && "Report selected by trimmed graph marked invalid."); + + // Start building the path diagnostic... + PathDiagnosticBuilder PDB(*this, R, ErrorGraph.BackMap, &PC); + const ExplodedNode *N = ErrorGraph.ErrorNode; + + // Register additional node visitors. + R->addVisitor(new NilReceiverBRVisitor()); + R->addVisitor(new ConditionBRVisitor()); + R->addVisitor(new LikelyFalsePositiveSuppressionBRVisitor()); + + BugReport::VisitorList visitors; + unsigned origReportConfigToken, finalReportConfigToken; + LocationContextMap LCM; + + // While generating diagnostics, it's possible the visitors will decide + // new symbols and regions are interesting, or add other visitors based on + // the information they find. If they do, we need to regenerate the path + // based on our new report configuration. + do { + // Get a clean copy of all the visitors. + for (BugReport::visitor_iterator I = R->visitor_begin(), + E = R->visitor_end(); I != E; ++I) + visitors.push_back((*I)->clone()); + + // Clear out the active path from any previous work. + PD.resetPath(); + origReportConfigToken = R->getConfigurationChangeToken(); + + // Generate the very last diagnostic piece - the piece is visible before + // the trace is expanded. + PathDiagnosticPiece *LastPiece = 0; + for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end(); + I != E; ++I) { + if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) { + assert (!LastPiece && + "There can only be one final piece in a diagnostic."); + LastPiece = Piece; + } } - break; - case PathDiagnosticConsumer::Minimal: - if (!GenerateMinimalPathDiagnostic(PD, PDB, N, visitors)) { - assert(!R->isValid() && "Failed on valid report"); - // Try again. We'll filter out the bad report when we trim the graph. - return generatePathDiagnostic(PD, PC, bugReports); + + if (ActiveScheme != PathDiagnosticConsumer::None) { + if (!LastPiece) + LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R); + assert(LastPiece); + PD.setEndOfPath(LastPiece); } - break; - case PathDiagnosticConsumer::None: - if (!GenerateVisitorsOnlyPathDiagnostic(PD, PDB, N, visitors)) { - assert(!R->isValid() && "Failed on valid report"); - // Try again. We'll filter out the bad report when we trim the graph. - return generatePathDiagnostic(PD, PC, bugReports); + + // Make sure we get a clean location context map so we don't + // hold onto old mappings. + LCM.clear(); + + switch (ActiveScheme) { + case PathDiagnosticConsumer::AlternateExtensive: + GenerateAlternateExtensivePathDiagnostic(PD, PDB, N, LCM, visitors); + break; + case PathDiagnosticConsumer::Extensive: + GenerateExtensivePathDiagnostic(PD, PDB, N, LCM, visitors); + break; + case PathDiagnosticConsumer::Minimal: + GenerateMinimalPathDiagnostic(PD, PDB, N, LCM, visitors); + break; + case PathDiagnosticConsumer::None: + GenerateVisitorsOnlyPathDiagnostic(PD, PDB, N, visitors); + break; } - break; - } - // Clean up the visitors we used. - llvm::DeleteContainerPointers(visitors); + // Clean up the visitors we used. + llvm::DeleteContainerPointers(visitors); - // Did anything change while generating this path? - finalReportConfigToken = R->getConfigurationChangeToken(); - } while(finalReportConfigToken != originalReportConfigToken); + // Did anything change while generating this path? + finalReportConfigToken = R->getConfigurationChangeToken(); + } while (finalReportConfigToken != origReportConfigToken); - // Finally, prune the diagnostic path of uninteresting stuff. - if (!PD.path.empty()) { - // Remove messages that are basically the same. - removeRedundantMsgs(PD.getMutablePieces()); + if (!R->isValid()) + continue; - if (R->shouldPrunePath() && - getEngine().getAnalysisManager().options.shouldPrunePaths()) { - bool hasSomethingInteresting = RemoveUnneededCalls(PD.getMutablePieces(), - R); - assert(hasSomethingInteresting); - (void) hasSomethingInteresting; + // Finally, prune the diagnostic path of uninteresting stuff. + if (!PD.path.empty()) { + // Remove messages that are basically the same. + removeRedundantMsgs(PD.getMutablePieces()); + + if (R->shouldPrunePath() && + getEngine().getAnalysisManager().options.shouldPrunePaths()) { + bool stillHasNotes = removeUnneededCalls(PD.getMutablePieces(), R, LCM); + assert(stillHasNotes); + (void)stillHasNotes; + } + + adjustCallLocations(PD.getMutablePieces()); + + if (ActiveScheme == PathDiagnosticConsumer::AlternateExtensive) { + ControlFlowBarrierSet CFBS; + OptimizedCallsSet OCS; + while (optimizeEdges(PD.getMutablePieces(), getSourceManager(), CFBS, + OCS, LCM)) {} + } } - adjustCallLocations(PD.getMutablePieces()); + // We found a report and didn't suppress it. + return true; } - return true; + // We suppressed all the reports in this equivalence class. + assert(!HasInvalid && "Inconsistent suppression"); + (void)HasInvalid; + return false; } void BugReporter::Register(BugType *BT) { @@ -2396,6 +2851,9 @@ void BugReporter::FlushReport(BugReport *exampleReport, exampleReport->getUniqueingLocation(), exampleReport->getUniqueingDecl())); + MaxBugClassSize = std::max(bugReports.size(), + static_cast<size_t>(MaxBugClassSize)); + // Generate the full path diagnostic, using the generation scheme // specified by the PathDiagnosticConsumer. Note that we have to generate // path diagnostics even for consumers which do not support paths, because @@ -2404,6 +2862,9 @@ void BugReporter::FlushReport(BugReport *exampleReport, if (!generatePathDiagnostic(*D.get(), PD, bugReports)) return; + MaxValidBugClassSize = std::max(bugReports.size(), + static_cast<size_t>(MaxValidBugClassSize)); + // If the path is empty, generate a single step path with the location // of the issue. if (D->path.empty()) { diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 517c1a10f8..e078745737 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -41,7 +41,7 @@ bool bugreporter::isDeclRefExprToReference(const Expr *E) { } const Expr *bugreporter::getDerefExpr(const Stmt *S) { - // Pattern match for a few useful cases (do something smarter later): + // Pattern match for a few useful cases: // a[0], p->f, *p const Expr *E = dyn_cast<Expr>(S); if (!E) @@ -61,6 +61,10 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) { else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) { return ME->getBase()->IgnoreParenCasts(); + } else { + // If we have a member expr with a dot, the base must have been + // dereferenced. + return getDerefExpr(ME->getBase()); } } else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) { @@ -69,6 +73,9 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) { else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(E)) { return AE->getBase(); } + else if (isDeclRefExprToReference(E)) { + return E; + } break; } @@ -137,11 +144,12 @@ class ReturnVisitor : public BugReporterVisitorImpl<ReturnVisitor> { MaybeUnsuppress, Satisfied } Mode; - bool InitiallySuppressed; + + bool EnableNullFPSuppression; public: ReturnVisitor(const StackFrameContext *Frame, bool Suppressed) - : StackFrame(Frame), Mode(Initial), InitiallySuppressed(Suppressed) {} + : StackFrame(Frame), Mode(Initial), EnableNullFPSuppression(Suppressed) {} static void *getTag() { static int Tag = 0; @@ -151,7 +159,7 @@ public: virtual void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(ReturnVisitor::getTag()); ID.AddPointer(StackFrame); - ID.AddBoolean(InitiallySuppressed); + ID.AddBoolean(EnableNullFPSuppression); } /// Adds a ReturnVisitor if the given statement represents a call that was @@ -162,7 +170,8 @@ public: /// the statement is a call that was inlined, we add the visitor to the /// bug report, so it can print a note later. static void addVisitorIfNecessary(const ExplodedNode *Node, const Stmt *S, - BugReport &BR) { + BugReport &BR, + bool InEnableNullFPSuppression) { if (!CallEvent::isCallStmt(S)) return; @@ -207,13 +216,13 @@ public: assert(Eng && "Cannot file a bug report without an owning engine"); AnalyzerOptions &Options = Eng->getAnalysisManager().options; - bool InitiallySuppressed = false; - if (Options.shouldSuppressNullReturnPaths()) + bool EnableNullFPSuppression = false; + if (InEnableNullFPSuppression && Options.shouldSuppressNullReturnPaths()) if (Optional<Loc> RetLoc = RetVal.getAs<Loc>()) - InitiallySuppressed = !State->assume(*RetLoc, true); + EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue(); BR.markInteresting(CalleeContext); - BR.addVisitor(new ReturnVisitor(CalleeContext, InitiallySuppressed)); + BR.addVisitor(new ReturnVisitor(CalleeContext, EnableNullFPSuppression)); } /// Returns true if any counter-suppression heuristics are enabled for @@ -270,14 +279,16 @@ public: // If we can't prove the return value is 0, just mark it interesting, and // make sure to track it into any further inner functions. - if (State->assume(V.castAs<DefinedSVal>(), true)) { + if (!State->isNull(V).isConstrainedTrue()) { BR.markInteresting(V); - ReturnVisitor::addVisitorIfNecessary(N, RetE, BR); + ReturnVisitor::addVisitorIfNecessary(N, RetE, BR, + EnableNullFPSuppression); return 0; } // If we're returning 0, we should track where that 0 came from. - bugreporter::trackNullOrUndefValue(N, RetE, BR); + bugreporter::trackNullOrUndefValue(N, RetE, BR, /*IsArg*/ false, + EnableNullFPSuppression); // Build an appropriate message based on the return value. SmallString<64> Msg; @@ -289,7 +300,7 @@ public: // the report is resurrected as valid later on. ExprEngine &Eng = BRC.getBugReporter().getEngine(); AnalyzerOptions &Options = Eng.getAnalysisManager().options; - if (InitiallySuppressed && hasCounterSuppression(Options)) + if (EnableNullFPSuppression && hasCounterSuppression(Options)) Mode = MaybeUnsuppress; if (RetE->getType()->isObjCObjectPointerType()) @@ -303,9 +314,9 @@ public: if (LValue) { if (const MemRegion *MR = LValue->getAsRegion()) { if (MR->canPrintPretty()) { - Out << " (reference to '"; + Out << " (reference to "; MR->printPretty(Out); - Out << "')"; + Out << ")"; } } } else { @@ -357,10 +368,11 @@ public: continue; // Is it possible for this argument to be non-null? - if (State->assume(*ArgV, true)) + if (!State->isNull(*ArgV).isConstrainedTrue()) continue; - if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true)) + if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true, + EnableNullFPSuppression)) BR.removeInvalidation(ReturnVisitor::getTag(), StackFrame); // If we /can't/ track the null pointer, we should err on the side of @@ -390,7 +402,7 @@ public: PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR) { - if (InitiallySuppressed) + if (EnableNullFPSuppression) BR.markInvalid(ReturnVisitor::getTag(), StackFrame); return 0; } @@ -403,6 +415,36 @@ void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(&tag); ID.AddPointer(R); ID.Add(V); + ID.AddBoolean(EnableNullFPSuppression); +} + +/// Returns true if \p N represents the DeclStmt declaring and initializing +/// \p VR. +static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) { + Optional<PostStmt> P = N->getLocationAs<PostStmt>(); + if (!P) + return false; + + const DeclStmt *DS = P->getStmtAs<DeclStmt>(); + if (!DS) + return false; + + if (DS->getSingleDecl() != VR->getDecl()) + return false; + + const MemSpaceRegion *VarSpace = VR->getMemorySpace(); + const StackSpaceRegion *FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace); + if (!FrameSpace) { + // If we ever directly evaluate global DeclStmts, this assertion will be + // invalid, but this still seems preferable to silently accepting an + // initialization that may be for a path-sensitive variable. + assert(VR->getDecl()->isStaticLocal() && "non-static stackless VarRegion"); + return true; + } + + assert(VR->getDecl()->hasLocalStorage()); + const LocationContext *LCtx = N->getLocationContext(); + return FrameSpace->getStackFrame() == LCtx->getCurrentStackFrame(); } PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, @@ -419,16 +461,22 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, // First see if we reached the declaration of the region. if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - if (Optional<PostStmt> P = Pred->getLocationAs<PostStmt>()) { - if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) { - if (DS->getSingleDecl() == VR->getDecl()) { - StoreSite = Pred; - InitE = VR->getDecl()->getInit(); - } - } + if (isInitializationOfVar(Pred, VR)) { + StoreSite = Pred; + InitE = VR->getDecl()->getInit(); } } + // If this is a post initializer expression, initializing the region, we + // should track the initializer expression. + if (Optional<PostInitializer> PIP = Pred->getLocationAs<PostInitializer>()) { + const MemRegion *FieldReg = (const MemRegion *)PIP->getLocationValue(); + if (FieldReg && FieldReg == R) { + StoreSite = Pred; + InitE = PIP->getInitializer()->getInit(); + } + } + // Otherwise, see if this is the store site: // (1) Succ has this binding and Pred does not, i.e. this is // where the binding first occurred. @@ -470,6 +518,11 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, IsParam = true; } } + + // If this is a CXXTempObjectRegion, the Expr responsible for its creation + // is wrapped inside of it. + if (const CXXTempObjectRegion *TmpR = dyn_cast<CXXTempObjectRegion>(R)) + InitE = TmpR->getExpr(); } if (!StoreSite) @@ -482,16 +535,14 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, if (V.isUndef() || V.getAs<loc::ConcreteInt>()) { if (!IsParam) InitE = InitE->IgnoreParenCasts(); - bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam); + bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam, + EnableNullFPSuppression); } else { ReturnVisitor::addVisitorIfNecessary(StoreSite, InitE->IgnoreParenCasts(), - BR); + BR, EnableNullFPSuppression); } } - if (!R->canPrintPretty()) - return 0; - // Okay, we've found the binding. Emit an appropriate message. SmallString<256> sbuf; llvm::raw_svector_ostream os(sbuf); @@ -503,9 +554,11 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, const VarRegion *VR = dyn_cast<VarRegion>(R); if (DS) { - action = "initialized to "; + action = R->canPrintPretty() ? "initialized to " : + "Initializing to "; } else if (isa<BlockExpr>(S)) { - action = "captured by block as "; + action = R->canPrintPretty() ? "captured by block as " : + "Captured by block as "; if (VR) { // See if we can get the BlockVarRegion. ProgramStateRef State = StoreSite->getState(); @@ -515,19 +568,18 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) { if (Optional<KnownSVal> KV = State->getSVal(OriginalR).getAs<KnownSVal>()) - BR.addVisitor(new FindLastStoreBRVisitor(*KV, OriginalR)); + BR.addVisitor(new FindLastStoreBRVisitor(*KV, OriginalR, + EnableNullFPSuppression)); } } } } if (action) { - if (!R) - return 0; - - os << '\''; - R->printPretty(os); - os << "' "; + if (R->canPrintPretty()) { + R->printPretty(os); + os << " "; + } if (V.getAs<loc::ConcreteInt>()) { bool b = false; @@ -550,14 +602,18 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, if (V.isUndef()) { if (isa<VarRegion>(R)) { const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); - if (VD->getInit()) - os << "initialized to a garbage value"; - else - os << "declared without an initial value"; + if (VD->getInit()) { + os << (R->canPrintPretty() ? "initialized" : "Initializing") + << " to a garbage value"; + } else { + os << (R->canPrintPretty() ? "declared" : "Declaring") + << " without an initial value"; + } } } else { - os << "initialized here"; + os << (R->canPrintPretty() ? "initialized" : "Initialized") + << " here"; } } } @@ -583,10 +639,11 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, // Printed parameter indexes are 1-based, not 0-based. unsigned Idx = Param->getFunctionScopeIndex() + 1; - os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter '"; - - R->printPretty(os); - os << '\''; + os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter"; + if (R->canPrintPretty()) { + os << " "; + R->printPretty(os); + } } } @@ -596,27 +653,42 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, if (R->isBoundable()) { if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { if (TR->getValueType()->isObjCObjectPointerType()) { - os << "nil object reference stored to "; + os << "nil object reference stored"; b = true; } } } + if (!b) { + if (R->canPrintPretty()) + os << "Null pointer value stored"; + else + os << "Storing null pointer value"; + } + + } else if (V.isUndef()) { + if (R->canPrintPretty()) + os << "Uninitialized value stored"; + else + os << "Storing uninitialized value"; - if (!b) - os << "Null pointer value stored to "; - } - else if (V.isUndef()) { - os << "Uninitialized value stored to "; } else if (Optional<nonloc::ConcreteInt> CV = V.getAs<nonloc::ConcreteInt>()) { - os << "The value " << CV->getValue() << " is assigned to "; - } - else - os << "Value assigned to "; + if (R->canPrintPretty()) + os << "The value " << CV->getValue() << " is assigned"; + else + os << "Assigning " << CV->getValue(); - os << '\''; - R->printPretty(os); - os << '\''; + } else { + if (R->canPrintPretty()) + os << "Value assigned"; + else + os << "Assigning value"; + } + + if (R->canPrintPretty()) { + os << " to "; + R->printPretty(os); + } } // Construct a new PathDiagnosticPiece. @@ -645,30 +717,43 @@ const char *TrackConstraintBRVisitor::getTag() { return "TrackConstraintBRVisitor"; } +bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const { + if (IsZeroCheck) + return N->getState()->isNull(Constraint).isUnderconstrained(); + return N->getState()->assume(Constraint, !Assumption); +} + PathDiagnosticPiece * TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, BugReport &BR) { - if (isSatisfied) + if (IsSatisfied) return NULL; + // Start tracking after we see the first state in which the value is + // constrained. + if (!IsTrackingTurnedOn) + if (!isUnderconstrained(N)) + IsTrackingTurnedOn = true; + if (!IsTrackingTurnedOn) + return 0; + // Check if in the previous state it was feasible for this constraint // to *not* be true. - if (PrevN->getState()->assume(Constraint, !Assumption)) { + if (isUnderconstrained(PrevN)) { - isSatisfied = true; + IsSatisfied = true; // As a sanity check, make sure that the negation of the constraint // was infeasible in the current state. If it is feasible, we somehow // missed the transition point. - if (N->getState()->assume(Constraint, !Assumption)) - return NULL; + assert(!isUnderconstrained(N)); // We found the transition point for the constraint. We now need to // pretty-print the constraint. (work-in-progress) - std::string sbuf; - llvm::raw_string_ostream os(sbuf); + SmallString<64> sbuf; + llvm::raw_svector_ostream os(sbuf); if (Constraint.getAs<Loc>()) { os << "Assuming pointer value is "; @@ -695,16 +780,22 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, SuppressInlineDefensiveChecksVisitor:: SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N) - : V(Value), IsSatisfied(false), StartN(N) { + : V(Value), IsSatisfied(false), IsTrackingTurnedOn(false) { - assert(N->getState()->isNull(V).isConstrainedTrue() && - "The visitor only tracks the cases where V is constrained to 0"); + // Check if the visitor is disabled. + SubEngine *Eng = N->getState()->getStateManager().getOwningEngine(); + assert(Eng && "Cannot file a bug report without an owning engine"); + AnalyzerOptions &Options = Eng->getAnalysisManager().options; + if (!Options.shouldSuppressInlinedDefensiveChecks()) + IsSatisfied = true; + + assert(N->getState()->isNull(V).isConstrainedTrue() && + "The visitor only tracks the cases where V is constrained to 0"); } void SuppressInlineDefensiveChecksVisitor::Profile(FoldingSetNodeID &ID) const { static int id = 0; ID.AddPointer(&id); - ID.AddPointer(StartN); ID.Add(V); } @@ -713,15 +804,6 @@ const char *SuppressInlineDefensiveChecksVisitor::getTag() { } PathDiagnosticPiece * -SuppressInlineDefensiveChecksVisitor::getEndPath(BugReporterContext &BRC, - const ExplodedNode *N, - BugReport &BR) { - if (StartN == BR.getErrorNode()) - StartN = 0; - return 0; -} - -PathDiagnosticPiece * SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred, BugReporterContext &BRC, @@ -729,23 +811,19 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, if (IsSatisfied) return 0; - // Start tracking after we see node StartN. - if (StartN == Succ) - StartN = 0; - if (StartN) - return 0; - - AnalyzerOptions &Options = - BRC.getBugReporter().getEngine().getAnalysisManager().options; - if (!Options.shouldSuppressInlinedDefensiveChecks()) + // Start tracking after we see the first state in which the value is null. + if (!IsTrackingTurnedOn) + if (Succ->getState()->isNull(V).isConstrainedTrue()) + IsTrackingTurnedOn = true; + if (!IsTrackingTurnedOn) return 0; // Check if in the previous state it was feasible for this value // to *not* be null. - if (Pred->getState()->assume(V, true)) { + if (!Pred->getState()->isNull(V).isConstrainedTrue()) { IsSatisfied = true; - assert(!Succ->getState()->assume(V, true)); + assert(Succ->getState()->isNull(V).isConstrainedTrue()); // Check if this is inlined defensive checks. const LocationContext *CurLC =Succ->getLocationContext(); @@ -756,16 +834,73 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, return 0; } -bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode, +static const MemRegion *getLocationRegionIfReference(const Expr *E, + const ExplodedNode *N) { + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { + if (!VD->getType()->isReferenceType()) + return 0; + ProgramStateManager &StateMgr = N->getState()->getStateManager(); + MemRegionManager &MRMgr = StateMgr.getRegionManager(); + return MRMgr.getVarRegion(VD, N->getLocationContext()); + } + } + + // FIXME: This does not handle other kinds of null references, + // for example, references from FieldRegions: + // struct Wrapper { int &ref; }; + // Wrapper w = { *(int *)0 }; + // w.ref = 1; + + return 0; +} + +static const Expr *peelOffOuterExpr(const Expr *Ex, + const ExplodedNode *N) { + Ex = Ex->IgnoreParenCasts(); + if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Ex)) + return peelOffOuterExpr(EWC->getSubExpr(), N); + if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Ex)) + return peelOffOuterExpr(OVE->getSourceExpr(), N); + + // Peel off the ternary operator. + if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(Ex)) { + // Find a node where the branching occured and find out which branch + // we took (true/false) by looking at the ExplodedGraph. + const ExplodedNode *NI = N; + do { + ProgramPoint ProgPoint = NI->getLocation(); + if (Optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) { + const CFGBlock *srcBlk = BE->getSrc(); + if (const Stmt *term = srcBlk->getTerminator()) { + if (term == CO) { + bool TookTrueBranch = (*(srcBlk->succ_begin()) == BE->getDst()); + if (TookTrueBranch) + return peelOffOuterExpr(CO->getTrueExpr(), N); + else + return peelOffOuterExpr(CO->getFalseExpr(), N); + } + } + } + NI = NI->getFirstPred(); + } while (NI); + } + return Ex; +} + +bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, - BugReport &report, bool IsArg) { - if (!S || !ErrorNode) + BugReport &report, bool IsArg, + bool EnableNullFPSuppression) { + if (!S || !N) return false; - if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) - S = OVE->getSourceExpr(); - - const ExplodedNode *N = ErrorNode; + if (const Expr *Ex = dyn_cast<Expr>(S)) { + Ex = Ex->IgnoreParenCasts(); + const Expr *PeeledEx = peelOffOuterExpr(Ex, N); + if (Ex != PeeledEx) + S = PeeledEx; + } const Expr *Inner = 0; if (const Expr *Ex = dyn_cast<Expr>(S)) { @@ -774,7 +909,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode, Inner = Ex; } - if (IsArg) { + if (IsArg && !Inner) { assert(N->getLocation().getAs<CallEnter>() && "Tracking arg but not at call"); } else { // Walk through nodes until we get one that matches the statement exactly. @@ -782,7 +917,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode, // gone too far (though we can likely track the lvalue better anyway). do { const ProgramPoint &pp = N->getLocation(); - if (Optional<PostStmt> ps = pp.getAs<PostStmt>()) { + if (Optional<StmtPoint> ps = pp.getAs<StmtPoint>()) { if (ps->getStmt() == S || ps->getStmt() == Inner) break; } else if (Optional<CallExitEnd> CEE = pp.getAs<CallExitEnd>()) { @@ -799,86 +934,79 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode, ProgramStateRef state = N->getState(); - // See if the expression we're interested refers to a variable. + // The message send could be nil due to the receiver being nil. + // At this point in the path, the receiver should be live since we are at the + // message send expr. If it is nil, start tracking it. + if (const Expr *Receiver = NilReceiverBRVisitor::getNilReceiver(S, N)) + trackNullOrUndefValue(N, Receiver, report, false, EnableNullFPSuppression); + + + // See if the expression we're interested refers to a variable. // If so, we can track both its contents and constraints on its value. if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) { const MemRegion *R = 0; - // First check if this is a DeclRefExpr for a C++ reference type. - // For those, we want the location of the reference. - if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Inner)) { - if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { - if (VD->getType()->isReferenceType()) { - ProgramStateManager &StateMgr = state->getStateManager(); - MemRegionManager &MRMgr = StateMgr.getRegionManager(); - R = MRMgr.getVarRegion(VD, N->getLocationContext()); - } + // Find the ExplodedNode where the lvalue (the value of 'Ex') + // was computed. We need this for getting the location value. + const ExplodedNode *LVNode = N; + while (LVNode) { + if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) { + if (P->getStmt() == Inner) + break; } + LVNode = LVNode->getFirstPred(); } + assert(LVNode && "Unable to find the lvalue node."); + ProgramStateRef LVState = LVNode->getState(); + SVal LVal = LVState->getSVal(Inner, LVNode->getLocationContext()); + + if (LVState->isNull(LVal).isConstrainedTrue()) { + // In case of C++ references, we want to differentiate between a null + // reference and reference to null pointer. + // If the LVal is null, check if we are dealing with null reference. + // For those, we want to track the location of the reference. + if (const MemRegion *RR = getLocationRegionIfReference(Inner, N)) + R = RR; + } else { + R = LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion(); - // For all other cases, find the location by scouring the ExplodedGraph. - if (!R) { - // Find the ExplodedNode where the lvalue (the value of 'Ex') - // was computed. We need this for getting the location value. - const ExplodedNode *LVNode = N; - while (LVNode) { - if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) { - if (P->getStmt() == Inner) - break; - } - LVNode = LVNode->getFirstPred(); + // If this is a C++ reference to a null pointer, we are tracking the + // pointer. In additon, we should find the store at which the reference + // got initialized. + if (const MemRegion *RR = getLocationRegionIfReference(Inner, N)) { + if (Optional<KnownSVal> KV = LVal.getAs<KnownSVal>()) + report.addVisitor(new FindLastStoreBRVisitor(*KV, RR, + EnableNullFPSuppression)); } - assert(LVNode && "Unable to find the lvalue node."); - ProgramStateRef LVState = LVNode->getState(); - R = LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion(); } if (R) { // Mark both the variable region and its contents as interesting. - SVal V = state->getRawSVal(loc::MemRegionVal(R)); - - // If the value matches the default for the variable region, that - // might mean that it's been cleared out of the state. Fall back to - // the full argument expression (with casts and such intact). - if (IsArg) { - bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant(); - if (!UseArgValue) { - const SymbolRegionValue *SRV = - dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol()); - if (SRV) - UseArgValue = (SRV->getRegion() == R); - } - if (UseArgValue) - V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); - } + SVal V = LVState->getRawSVal(loc::MemRegionVal(R)); report.markInteresting(R); report.markInteresting(V); report.addVisitor(new UndefOrNullArgVisitor(R)); - if (isa<SymbolicRegion>(R)) { - TrackConstraintBRVisitor *VI = - new TrackConstraintBRVisitor(loc::MemRegionVal(R), false); - report.addVisitor(VI); - } - // If the contents are symbolic, find out when they became null. - if (V.getAsLocSymbol()) { + if (V.getAsLocSymbol(/*IncludeBaseRegions*/ true)) { BugReporterVisitor *ConstraintTracker = new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false); report.addVisitor(ConstraintTracker); // Add visitor, which will suppress inline defensive checks. - if (ErrorNode->getState()->isNull(V).isConstrainedTrue()) { + if (LVState->isNull(V).isConstrainedTrue() && + EnableNullFPSuppression) { BugReporterVisitor *IDCSuppressor = new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(), - ErrorNode); + LVNode); report.addVisitor(IDCSuppressor); } } if (Optional<KnownSVal> KV = V.getAs<KnownSVal>()) - report.addVisitor(new FindLastStoreBRVisitor(*KV, R)); + report.addVisitor(new FindLastStoreBRVisitor(*KV, R, + EnableNullFPSuppression)); return true; } } @@ -891,7 +1019,8 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode, // sure that function isn't pruned in our output. if (const Expr *E = dyn_cast<Expr>(S)) S = E->IgnoreParenCasts(); - ReturnVisitor::addVisitorIfNecessary(N, S, report); + + ReturnVisitor::addVisitorIfNecessary(N, S, report, EnableNullFPSuppression); // Uncomment this to find cases where we aren't properly getting the // base value that was dereferenced. @@ -900,7 +1029,13 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode, if (Optional<loc::MemRegionVal> L = V.getAs<loc::MemRegionVal>()) { // At this point we are dealing with the region's LValue. // However, if the rvalue is a symbolic region, we should track it as well. - SVal RVal = state->getSVal(L->getRegion()); + // Try to use the correct type when looking up the value. + SVal RVal; + if (const Expr *E = dyn_cast<Expr>(S)) + RVal = state->getRawSVal(L.getValue(), E->getType()); + else + RVal = state->getSVal(L->getRegion()); + const MemRegion *RegionRVal = RVal.getAsRegion(); report.addVisitor(new UndefOrNullArgVisitor(L->getRegion())); @@ -914,14 +1049,17 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode, return true; } -BugReporterVisitor * -FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N, - const MemRegion *R) { - assert(R && "The memory region is null."); - - ProgramStateRef state = N->getState(); - if (Optional<KnownSVal> KV = state->getSVal(R).getAs<KnownSVal>()) - return new FindLastStoreBRVisitor(*KV, R); +const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S, + const ExplodedNode *N) { + const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S); + if (!ME) + return 0; + if (const Expr *Receiver = ME->getInstanceReceiver()) { + ProgramStateRef state = N->getState(); + SVal V = state->getSVal(Receiver, N->getLocationContext()); + if (state->isNull(V).isConstrainedTrue()) + return Receiver; + } return 0; } @@ -929,38 +1067,41 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, BugReport &BR) { - Optional<PostStmt> P = N->getLocationAs<PostStmt>(); + Optional<PreStmt> P = N->getLocationAs<PreStmt>(); if (!P) return 0; - const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>(); - if (!ME) - return 0; - const Expr *Receiver = ME->getInstanceReceiver(); + + const Stmt *S = P->getStmt(); + const Expr *Receiver = getNilReceiver(S, N); if (!Receiver) return 0; - ProgramStateRef state = N->getState(); - const SVal &V = state->getSVal(Receiver, N->getLocationContext()); - Optional<DefinedOrUnknownSVal> DV = V.getAs<DefinedOrUnknownSVal>(); - if (!DV) - return 0; - state = state->assume(*DV, true); - if (state) - return 0; + + llvm::SmallString<256> Buf; + llvm::raw_svector_ostream OS(Buf); + + if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) { + OS << "'" << ME->getSelector().getAsString() << "' not called"; + } + else { + OS << "No method is called"; + } + OS << " because the receiver is nil"; // The receiver was nil, and hence the method was skipped. // Register a BugReporterVisitor to issue a message telling us how // the receiver was null. - bugreporter::trackNullOrUndefValue(N, Receiver, BR); + bugreporter::trackNullOrUndefValue(N, Receiver, BR, /*IsArg*/ false, + /*EnableNullFPSuppression*/ false); // Issue a message saying that the method was skipped. PathDiagnosticLocation L(Receiver, BRC.getSourceManager(), N->getLocationContext()); - return new PathDiagnosticEventPiece(L, "No method is called " - "because the receiver is nil"); + return new PathDiagnosticEventPiece(L, OS.str()); } // Registers every VarDecl inside a Stmt with a last store visitor. void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR, - const Stmt *S) { + const Stmt *S, + bool EnableNullFPSuppression) { const ExplodedNode *N = BR.getErrorNode(); std::deque<const Stmt *> WorkList; WorkList.push_back(S); @@ -982,7 +1123,8 @@ void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR, if (V.getAs<loc::ConcreteInt>() || V.getAs<nonloc::ConcreteInt>()) { // Register a new visitor with the BugReport. - BR.addVisitor(new FindLastStoreBRVisitor(V.castAs<KnownSVal>(), R)); + BR.addVisitor(new FindLastStoreBRVisitor(V.castAs<KnownSVal>(), R, + EnableNullFPSuppression)); } } } @@ -1282,7 +1424,7 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, Out << (tookTrue ? "not nil" : "nil"); else if (Ty->isBooleanType()) Out << (tookTrue ? "true" : "false"); - else if (Ty->isIntegerType()) + else if (Ty->isIntegralOrEnumerationType()) Out << (tookTrue ? "non-zero" : "zero"); else return 0; @@ -1353,28 +1495,53 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, return event; } + +// FIXME: Copied from ExprEngineCallAndReturn.cpp. +static bool isInStdNamespace(const Decl *D) { + const DeclContext *DC = D->getDeclContext()->getEnclosingNamespaceContext(); + const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC); + if (!ND) + return false; + + while (const NamespaceDecl *Parent = dyn_cast<NamespaceDecl>(ND->getParent())) + ND = Parent; + + return ND->getName() == "std"; +} + + PathDiagnosticPiece * LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR) { - const Stmt *S = BR.getStmt(); - if (!S) - return 0; - - // Here we suppress false positives coming from system macros. This list is + // Here we suppress false positives coming from system headers. This list is // based on known issues. + // Skip reports within the 'std' namespace. Although these can sometimes be + // the user's fault, we currently don't report them very well, and + // Note that this will not help for any other data structure libraries, like + // TR1, Boost, or llvm/ADT. + ExprEngine &Eng = BRC.getBugReporter().getEngine(); + AnalyzerOptions &Options = Eng.getAnalysisManager().options; + if (Options.shouldSuppressFromCXXStandardLibrary()) { + const LocationContext *LCtx = N->getLocationContext(); + if (isInStdNamespace(LCtx->getDecl())) { + BR.markInvalid(getTag(), 0); + return 0; + } + } + // Skip reports within the sys/queue.h macros as we do not have the ability to // reason about data structure shapes. SourceManager &SM = BRC.getSourceManager(); - SourceLocation Loc = S->getLocStart(); + FullSourceLoc Loc = BR.getLocation(SM).asLocation(); while (Loc.isMacroID()) { if (SM.isInSystemMacro(Loc) && (SM.getFilename(SM.getSpellingLoc(Loc)).endswith("sys/queue.h"))) { BR.markInvalid(getTag(), 0); return 0; } - Loc = SM.getSpellingLoc(Loc); + Loc = Loc.getSpellingLoc(); } return 0; diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index c482978ca2..dfd20b8b33 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -125,7 +125,7 @@ static bool isPointerToConst(QualType Ty) { // Try to retrieve the function declaration and find the function parameter // types which are pointers/references to a non-pointer const. // We will not invalidate the corresponding argument regions. -static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, +static void findPtrToConstParams(llvm::SmallSet<unsigned, 4> &PreserveArgs, const CallEvent &Call) { unsigned Idx = 0; for (CallEvent::param_type_iterator I = Call.param_type_begin(), @@ -137,71 +137,35 @@ static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, } ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, - ProgramStateRef Orig) const { + ProgramStateRef Orig) const { ProgramStateRef Result = (Orig ? Orig : getState()); - SmallVector<const MemRegion *, 8> RegionsToInvalidate; - getExtraInvalidatedRegions(RegionsToInvalidate); + SmallVector<SVal, 8> ConstValues; + SmallVector<SVal, 8> ValuesToInvalidate; + + getExtraInvalidatedValues(ValuesToInvalidate); // Indexes of arguments whose values will be preserved by the call. - llvm::SmallSet<unsigned, 1> PreserveArgs; + llvm::SmallSet<unsigned, 4> PreserveArgs; if (!argumentsMayEscape()) findPtrToConstParams(PreserveArgs, *this); for (unsigned Idx = 0, Count = getNumArgs(); Idx != Count; ++Idx) { + // Mark this region for invalidation. We batch invalidate regions + // below for efficiency. if (PreserveArgs.count(Idx)) - continue; - - SVal V = getArgSVal(Idx); - - // If we are passing a location wrapped as an integer, unwrap it and - // invalidate the values referred by the location. - if (Optional<nonloc::LocAsInteger> Wrapped = - V.getAs<nonloc::LocAsInteger>()) - V = Wrapped->getLoc(); - else if (!V.getAs<Loc>()) - continue; - - if (const MemRegion *R = V.getAsRegion()) { - // Invalidate the value of the variable passed by reference. - - // Are we dealing with an ElementRegion? If the element type is - // a basic integer type (e.g., char, int) and the underlying region - // is a variable region then strip off the ElementRegion. - // FIXME: We really need to think about this for the general case - // as sometimes we are reasoning about arrays and other times - // about (char*), etc., is just a form of passing raw bytes. - // e.g., void *p = alloca(); foo((char*)p); - if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { - // Checking for 'integral type' is probably too promiscuous, but - // we'll leave it in for now until we have a systematic way of - // handling all of these cases. Eventually we need to come up - // with an interface to StoreManager so that this logic can be - // appropriately delegated to the respective StoreManagers while - // still allowing us to do checker-specific logic (e.g., - // invalidating reference counts), probably via callbacks. - if (ER->getElementType()->isIntegralOrEnumerationType()) { - const MemRegion *superReg = ER->getSuperRegion(); - if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) || - isa<ObjCIvarRegion>(superReg)) - R = cast<TypedRegion>(superReg); - } - // FIXME: What about layers of ElementRegions? - } - - // Mark this region for invalidation. We batch invalidate regions - // below for efficiency. - RegionsToInvalidate.push_back(R); - } + ConstValues.push_back(getArgSVal(Idx)); + else + ValuesToInvalidate.push_back(getArgSVal(Idx)); } // Invalidate designated regions using the batch invalidation API. // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate // global variables. - return Result->invalidateRegions(RegionsToInvalidate, getOriginExpr(), + return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(), BlockCount, getLocationContext(), /*CausedByPointerEscape*/ true, - /*Symbols=*/0, this); + /*Symbols=*/0, this, ConstValues); } ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit, @@ -275,8 +239,20 @@ QualType CallEvent::getDeclaredResultType(const Decl *D) { assert(D); if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) return FD->getResultType(); - else if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D)) + if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D)) return MD->getResultType(); + if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + // Blocks are difficult because the return type may not be stored in the + // BlockDecl itself. The AST should probably be enhanced, but for now we + // just do what we can. + QualType Ty = BD->getSignatureAsWritten()->getType(); + if (const FunctionType *FT = Ty->getAs<FunctionType>()) + if (!FT->getResultType()->isDependentType()) + return FT->getResultType(); + + return QualType(); + } + return QualType(); } @@ -407,9 +383,8 @@ const FunctionDecl *CXXInstanceCall::getDecl() const { return getSVal(CE->getCallee()).getAsFunctionDecl(); } -void CXXInstanceCall::getExtraInvalidatedRegions(RegionList &Regions) const { - if (const MemRegion *R = getCXXThisVal().getAsRegion()) - Regions.push_back(R); +void CXXInstanceCall::getExtraInvalidatedValues(ValueList &Values) const { + Values.push_back(getCXXThisVal()); } SVal CXXInstanceCall::getCXXThisVal() const { @@ -562,10 +537,10 @@ CallEvent::param_iterator BlockCall::param_end() const { return D->param_end(); } -void BlockCall::getExtraInvalidatedRegions(RegionList &Regions) const { +void BlockCall::getExtraInvalidatedValues(ValueList &Values) const { // FIXME: This also needs to invalidate captured globals. if (const MemRegion *R = getBlockRegion()) - Regions.push_back(R); + Values.push_back(loc::MemRegionVal(R)); } void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx, @@ -583,9 +558,9 @@ SVal CXXConstructorCall::getCXXThisVal() const { return UnknownVal(); } -void CXXConstructorCall::getExtraInvalidatedRegions(RegionList &Regions) const { +void CXXConstructorCall::getExtraInvalidatedValues(ValueList &Values) const { if (Data) - Regions.push_back(static_cast<const MemRegion *>(Data)); + Values.push_back(loc::MemRegionVal(static_cast<const MemRegion *>(Data))); } void CXXConstructorCall::getInitialStackFrameContents( @@ -637,9 +612,8 @@ CallEvent::param_iterator ObjCMethodCall::param_end() const { } void -ObjCMethodCall::getExtraInvalidatedRegions(RegionList &Regions) const { - if (const MemRegion *R = getReceiverSVal().getAsRegion()) - Regions.push_back(R); +ObjCMethodCall::getExtraInvalidatedValues(ValueList &Values) const { + Values.push_back(getReceiverSVal()); } SVal ObjCMethodCall::getSelfSVal() const { diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index a383799788..8adf3262b3 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -489,19 +489,19 @@ ProgramStateRef CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, - PointerEscapeKind Kind) { + PointerEscapeKind Kind, + bool IsConst) { assert((Call != NULL || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && "Call must not be NULL when escaping on call"); - - for (unsigned i = 0, e = PointerEscapeCheckers.size(); i != e; ++i) { - // If any checker declares the state infeasible (or if it starts that way), - // bail out. - if (!State) - return NULL; - State = PointerEscapeCheckers[i](State, Escaped, Call, Kind); - } + for (unsigned i = 0, e = PointerEscapeCheckers.size(); i != e; ++i) { + // If any checker declares the state infeasible (or if it starts that + // way), bail out. + if (!State) + return NULL; + State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, IsConst); + } return State; } @@ -666,6 +666,11 @@ void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){ PointerEscapeCheckers.push_back(checkfn); } +void CheckerManager::_registerForConstPointerEscape( + CheckPointerEscapeFunc checkfn) { + PointerEscapeCheckers.push_back(checkfn); +} + void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { EvalAssumeCheckers.push_back(checkfn); } diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp index c61bcf7d41..b09b2c2ddf 100644 --- a/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -346,6 +346,11 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { default: llvm_unreachable("Analysis for this terminator not implemented."); + // Model static initializers. + case Stmt::DeclStmtClass: + HandleStaticInit(cast<DeclStmt>(Term), B, Pred); + return; + case Stmt::BinaryOperatorClass: // '&&' and '||' HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred); return; @@ -456,6 +461,19 @@ void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term, enqueue(Dst); } + +void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B, + ExplodedNode *Pred) { + assert(B->succ_size() == 2); + NodeBuilderContext Ctx(*this, B, Pred); + ExplodedNodeSet Dst; + SubEng.processStaticInitializer(DS, Ctx, Pred, Dst, + *(B->succ_begin()), *(B->succ_begin()+1)); + // Enqueue the new frontier onto the worklist. + enqueue(Dst); +} + + void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred) { assert(B); diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp index fe352aa8b4..7b133f6bf6 100644 --- a/lib/StaticAnalyzer/Core/Environment.cpp +++ b/lib/StaticAnalyzer/Core/Environment.cpp @@ -80,43 +80,17 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry, llvm_unreachable("Should have been handled by ignoreTransparentExprs"); case Stmt::AddrLabelExprClass: - return svalBuilder.makeLoc(cast<AddrLabelExpr>(S)); - - case Stmt::CharacterLiteralClass: { - const CharacterLiteral *C = cast<CharacterLiteral>(S); - return svalBuilder.makeIntVal(C->getValue(), C->getType()); - } - + case Stmt::CharacterLiteralClass: case Stmt::CXXBoolLiteralExprClass: - return svalBuilder.makeBoolVal(cast<CXXBoolLiteralExpr>(S)); - case Stmt::CXXScalarValueInitExprClass: - case Stmt::ImplicitValueInitExprClass: { - QualType Ty = cast<Expr>(S)->getType(); - return svalBuilder.makeZeroVal(Ty); - } - + case Stmt::ImplicitValueInitExprClass: case Stmt::IntegerLiteralClass: - return svalBuilder.makeIntVal(cast<IntegerLiteral>(S)); - case Stmt::ObjCBoolLiteralExprClass: - return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(S)); - - // For special C0xx nullptr case, make a null pointer SVal. case Stmt::CXXNullPtrLiteralExprClass: - return svalBuilder.makeNull(); - - case Stmt::ObjCStringLiteralClass: { - MemRegionManager &MRMgr = svalBuilder.getRegionManager(); - const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(S); - return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL)); - } - - case Stmt::StringLiteralClass: { - MemRegionManager &MRMgr = svalBuilder.getRegionManager(); - const StringLiteral *SL = cast<StringLiteral>(S); - return svalBuilder.makeLoc(MRMgr.getStringRegion(SL)); - } + case Stmt::ObjCStringLiteralClass: + case Stmt::StringLiteralClass: + // Known constants; defer to SValBuilder. + return svalBuilder.getConstantVal(cast<Expr>(S)).getValue(); case Stmt::ReturnStmtClass: { const ReturnStmt *RS = cast<ReturnStmt>(S); @@ -127,10 +101,8 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry, // Handle all other Stmt* using a lookup. default: - break; + return lookupExpr(EnvironmentEntry(S, LCtx)); } - - return lookupExpr(EnvironmentEntry(S, LCtx)); } Environment EnvironmentManager::bindExpr(Environment Env, diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index 2210b4e2d7..af9518acc7 100644 --- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -117,8 +117,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { return false; // Condition 4. - PostStmt ps = progPoint.castAs<PostStmt>(); - if (ps.getTag()) + if (progPoint.getTag()) return false; // Conditions 5, 6, and 7. @@ -128,8 +127,9 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { progPoint.getLocationContext() != pred->getLocationContext()) return false; - // All further checks require expressions. - const Expr *Ex = dyn_cast<Expr>(ps.getStmt()); + // All further checks require expressions. As per #3, we know that we have + // a PostStmt. + const Expr *Ex = dyn_cast<Expr>(progPoint.castAs<PostStmt>().getStmt()); if (!Ex) return false; @@ -331,45 +331,31 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L, return V; } -std::pair<ExplodedGraph*, InterExplodedGraphMap*> -ExplodedGraph::Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd, - llvm::DenseMap<const void*, const void*> *InverseMap) const { +ExplodedGraph * +ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, + InterExplodedGraphMap *ForwardMap, + InterExplodedGraphMap *InverseMap) const{ - if (NBeg == NEnd) - return std::make_pair((ExplodedGraph*) 0, - (InterExplodedGraphMap*) 0); - - assert (NBeg < NEnd); - - OwningPtr<InterExplodedGraphMap> M(new InterExplodedGraphMap()); - - ExplodedGraph* G = TrimInternal(NBeg, NEnd, M.get(), InverseMap); - - return std::make_pair(static_cast<ExplodedGraph*>(G), M.take()); -} - -ExplodedGraph* -ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, - const ExplodedNode* const* EndSources, - InterExplodedGraphMap* M, - llvm::DenseMap<const void*, const void*> *InverseMap) const { + if (Nodes.empty()) + return 0; typedef llvm::DenseSet<const ExplodedNode*> Pass1Ty; Pass1Ty Pass1; - typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> Pass2Ty; - Pass2Ty& Pass2 = M->M; + typedef InterExplodedGraphMap Pass2Ty; + InterExplodedGraphMap Pass2Scratch; + Pass2Ty &Pass2 = ForwardMap ? *ForwardMap : Pass2Scratch; SmallVector<const ExplodedNode*, 10> WL1, WL2; // ===- Pass 1 (reverse DFS) -=== - for (const ExplodedNode* const* I = BeginSources; I != EndSources; ++I) { + for (ArrayRef<const NodeTy *>::iterator I = Sinks.begin(), E = Sinks.end(); + I != E; ++I) { if (*I) WL1.push_back(*I); } - // Process the first worklist until it is empty. Because it is a std::list - // it acts like a FIFO queue. + // Process the first worklist until it is empty. while (!WL1.empty()) { const ExplodedNode *N = WL1.back(); WL1.pop_back(); @@ -432,7 +418,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, if (PI == Pass2.end()) continue; - NewN->addPredecessor(PI->second, *G); + NewN->addPredecessor(const_cast<ExplodedNode *>(PI->second), *G); } // In the case that some of the intended successors of NewN have already @@ -443,7 +429,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, I != E; ++I) { Pass2Ty::iterator PI = Pass2.find(*I); if (PI != Pass2.end()) { - PI->second->addPredecessor(NewN, *G); + const_cast<ExplodedNode *>(PI->second)->addPredecessor(NewN, *G); continue; } @@ -456,13 +442,3 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, return G; } -void InterExplodedGraphMap::anchor() { } - -ExplodedNode* -InterExplodedGraphMap::getMappedNode(const ExplodedNode *N) const { - llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I = - M.find(N); - - return I == M.end() ? 0 : I->second; -} - diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 437af86ccf..bfe4e15a71 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -106,7 +106,8 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { const ParmVarDecl *PD = FD->getParamDecl(0); QualType T = PD->getType(); - if (!T->isIntegerType()) + const BuiltinType *BT = dyn_cast<BuiltinType>(T); + if (!BT || !BT->isInteger()) break; const MemRegion *R = state->getRegion(PD, InitLoc); @@ -171,18 +172,29 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, const Expr *Ex, const Expr *Result) { SVal V = State->getSVal(Ex, LC); - if (!Result && !V.getAs<NonLoc>()) - return State; + if (!Result) { + // If we don't have an explicit result expression, we're in "if needed" + // mode. Only create a region if the current value is a NonLoc. + if (!V.getAs<NonLoc>()) + return State; + Result = Ex; + } else { + // We need to create a region no matter what. For sanity, make sure we don't + // try to stuff a Loc into a non-pointer temporary region. + assert(!V.getAs<Loc>() || Loc::isLocType(Result->getType()) || + Result->getType()->isMemberPointerType()); + } ProgramStateManager &StateMgr = State->getStateManager(); MemRegionManager &MRMgr = StateMgr.getRegionManager(); StoreManager &StoreMgr = StateMgr.getStoreManager(); // We need to be careful about treating a derived type's value as - // bindings for a base type. Start by stripping and recording base casts. + // bindings for a base type. Unless we're creating a temporary pointer region, + // start by stripping and recording base casts. SmallVector<const CastExpr *, 4> Casts; const Expr *Inner = Ex->IgnoreParens(); - if (V.getAs<NonLoc>()) { + if (!Loc::isLocType(Result->getType())) { while (const CastExpr *CE = dyn_cast<CastExpr>(Inner)) { if (CE->getCastKind() == CK_DerivedToBase || CE->getCastKind() == CK_UncheckedDerivedToBase) @@ -195,8 +207,13 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, } // Create a temporary object region for the inner expression (which may have - // a more derived type) and bind the NonLoc value into it. - SVal Reg = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(Inner, LC)); + // a more derived type) and bind the value into it. + const TypedValueRegion *TR = MRMgr.getCXXTempObjectRegion(Inner, LC); + SVal Reg = loc::MemRegionVal(TR); + + if (V.isUnknown()) + V = getSValBuilder().conjureSymbolVal(Result, LC, TR->getValueType(), + currBldrCtx->blockCount()); State = State->bindLoc(Reg, V); // Re-apply the casts (from innermost to outermost) for type sanity. @@ -206,7 +223,7 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, Reg = StoreMgr.evalDerivedToBase(Reg, *I); } - State = State->BindExpr(Result ? Result : Ex, LC, Reg); + State = State->BindExpr(Result, LC, Reg); return State; } @@ -423,8 +440,8 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, ProgramStateRef State = Pred->getState(); SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame)); - PostInitializer PP(BMI, stackFrame); ExplodedNodeSet Tmp(Pred); + SVal FieldLoc; // Evaluate the initializer, if necessary if (BMI->isAnyMemberInitializer()) { @@ -432,15 +449,43 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, // but non-objects must be copied in from the initializer. const Expr *Init = BMI->getInit()->IgnoreImplicit(); if (!isa<CXXConstructExpr>(Init)) { - SVal FieldLoc; - if (BMI->isIndirectMemberInitializer()) + const ValueDecl *Field; + if (BMI->isIndirectMemberInitializer()) { + Field = BMI->getIndirectMember(); FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal); - else + } else { + Field = BMI->getMember(); FieldLoc = State->getLValue(BMI->getMember(), thisVal); + } - SVal InitVal = State->getSVal(BMI->getInit(), stackFrame); + SVal InitVal; + if (BMI->getNumArrayIndices() > 0) { + // Handle arrays of trivial type. We can represent this with a + // primitive load/copy from the base array region. + const ArraySubscriptExpr *ASE; + while ((ASE = dyn_cast<ArraySubscriptExpr>(Init))) + Init = ASE->getBase()->IgnoreImplicit(); + + SVal LValue = State->getSVal(Init, stackFrame); + if (Optional<Loc> LValueLoc = LValue.getAs<Loc>()) + InitVal = State->getSVal(*LValueLoc); + + // If we fail to get the value for some reason, use a symbolic value. + if (InitVal.isUnknownOrUndef()) { + SValBuilder &SVB = getSValBuilder(); + InitVal = SVB.conjureSymbolVal(BMI->getInit(), stackFrame, + Field->getType(), + currBldrCtx->blockCount()); + } + } else { + InitVal = State->getSVal(BMI->getInit(), stackFrame); + } + assert(Tmp.size() == 1 && "have not generated any new nodes yet"); + assert(*Tmp.begin() == Pred && "have not generated any new nodes yet"); Tmp.clear(); + + PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame); evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP); } } else { @@ -450,6 +495,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, // Construct PostInitializer nodes whether the state changed or not, // so that the diagnostics don't get confused. + PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame); ExplodedNodeSet Dst; NodeBuilder Bldr(Tmp, Dst, *currBldrCtx); for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { @@ -488,18 +534,20 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - ProgramStateRef state = Pred->getState(); const VarDecl *varDecl = Dtor.getVarDecl(); - QualType varType = varDecl->getType(); - if (const ReferenceType *refType = varType->getAs<ReferenceType>()) - varType = refType->getPointeeType(); + ProgramStateRef state = Pred->getState(); + SVal dest = state->getLValue(varDecl, Pred->getLocationContext()); + const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion(); - Loc dest = state->getLValue(varDecl, Pred->getLocationContext()); + if (const ReferenceType *refType = varType->getAs<ReferenceType>()) { + varType = refType->getPointeeType(); + Region = state->getSVal(Region).getAsRegion(); + } - VisitCXXDestructor(varType, dest.castAs<loc::MemRegionVal>().getRegion(), - Dtor.getTriggerStmt(), /*IsBase=*/ false, Pred, Dst); + VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(), /*IsBase=*/ false, + Pred, Dst); } void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D, @@ -556,11 +604,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, switch (S->getStmtClass()) { // C++ and ARC stuff we don't support yet. case Expr::ObjCIndirectCopyRestoreExprClass: + case Stmt::CXXDefaultInitExprClass: case Stmt::CXXDependentScopeMemberExprClass: case Stmt::CXXPseudoDestructorExprClass: case Stmt::CXXTryStmtClass: case Stmt::CXXTypeidExprClass: case Stmt::CXXUuidofExprClass: + case Stmt::MSPropertyRefExprClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::DependentScopeDeclRefExprClass: case Stmt::UnaryTypeTraitExprClass: @@ -607,6 +657,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::SwitchStmtClass: case Stmt::WhileStmtClass: case Expr::MSDependentExistsStmtClass: + case Stmt::CapturedStmtClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ObjCSubscriptRefExprClass: @@ -690,21 +741,22 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, const CXXDefaultArgExpr *DefaultE = cast<CXXDefaultArgExpr>(S); const Expr *ArgE = DefaultE->getExpr(); - // Avoid creating and destroying a lot of APSInts. - SVal V; - llvm::APSInt Result; + bool IsTemporary = false; + if (const MaterializeTemporaryExpr *MTE = + dyn_cast<MaterializeTemporaryExpr>(ArgE)) { + ArgE = MTE->GetTemporaryExpr(); + IsTemporary = true; + } + + Optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE); + if (!ConstantVal) + ConstantVal = UnknownVal(); for (ExplodedNodeSet::iterator I = PreVisit.begin(), E = PreVisit.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); - - if (ArgE->EvaluateAsInt(Result, getContext())) - V = svalBuilder.makeIntVal(Result); - else - V = State->getSVal(ArgE, LCtx); - - State = State->BindExpr(DefaultE, LCtx, V); - if (DefaultE->isGLValue()) + State = State->BindExpr(DefaultE, LCtx, *ConstantVal); + if (IsTemporary) State = createTemporaryRegionIfNeeded(State, LCtx, DefaultE, DefaultE); Bldr2.generateNode(S, *I, State); @@ -814,9 +866,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef NewState = createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0)); - if (NewState != State) + if (NewState != State) { Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/0, ProgramPoint::PreStmtKind); + // Did we cache out? + if (!Pred) + break; + } } } // FALLTHROUGH @@ -1189,7 +1245,7 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr, while (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) { QualType T = CE->getType(); - if (!T->isIntegerType()) + if (!T->isIntegralOrEnumerationType()) return UnknownVal(); uint64_t newBits = Ctx.getTypeSize(T); @@ -1204,7 +1260,8 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr, // We reached a non-cast. Is it a symbolic value? QualType T = Ex->getType(); - if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits) + if (!bitsInit || !T->isIntegralOrEnumerationType() || + Ctx.getTypeSize(T) > bits) return UnknownVal(); return state->getSVal(Ex, LCtx); @@ -1296,7 +1353,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, if (X.isUnknownOrUndef()) { // Give it a chance to recover from unknown. if (const Expr *Ex = dyn_cast<Expr>(Condition)) { - if (Ex->getType()->isIntegerType()) { + if (Ex->getType()->isIntegralOrEnumerationType()) { // Try to recover some path-sensitivity. Right now casts of symbolic // integers that promote their values are currently not tracked well. // If 'Condition' is such an expression, try and recover the @@ -1344,6 +1401,34 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, currBldrCtx = 0; } +/// The GDM component containing the set of global variables which have been +/// previously initialized with explicit initializers. +REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet, + llvm::ImmutableSet<const VarDecl *>) + +void ExprEngine::processStaticInitializer(const DeclStmt *DS, + NodeBuilderContext &BuilderCtx, + ExplodedNode *Pred, + clang::ento::ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF) { + currBldrCtx = &BuilderCtx; + + const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); + ProgramStateRef state = Pred->getState(); + bool initHasRun = state->contains<InitializedGlobalsSet>(VD); + BranchNodeBuilder builder(Pred, Dst, BuilderCtx, DstT, DstF); + + if (!initHasRun) { + state = state->add<InitializedGlobalsSet>(VD); + } + + builder.generateNode(state, initHasRun, Pred); + builder.markInfeasible(!initHasRun); + + currBldrCtx = 0; +} + /// processIndirectGoto - Called by CoreEngine. Used to generate successor /// nodes by processing the 'effects' of a computed goto jump. void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { @@ -1692,12 +1777,6 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, if (StoredVal != Val) escapes = (State == (State->bindLoc(*regionLoc, Val))); } - if (!escapes) { - // Case 4: We do not currently model what happens when a symbol is - // assigned to a struct field, so be conservative here and let the symbol - // go. TODO: This could definitely be improved upon. - escapes = !isa<VarRegion>(regionLoc->getRegion()); - } } // If our store can represent the binding and we aren't storing to something @@ -1720,11 +1799,12 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, } ProgramStateRef -ExprEngine::processPointerEscapedOnInvalidateRegions(ProgramStateRef State, +ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State, const InvalidatedSymbols *Invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, - const CallEvent *Call) { + const CallEvent *Call, + bool IsConst) { if (!Invalidated || Invalidated->empty()) return State; @@ -1733,8 +1813,19 @@ ExprEngine::processPointerEscapedOnInvalidateRegions(ProgramStateRef State, return getCheckerManager().runCheckersForPointerEscape(State, *Invalidated, 0, - PSK_EscapeOther); - + PSK_EscapeOther, + IsConst); + + // Note: Due to current limitations of RegionStore, we only process the top + // level const pointers correctly. The lower level const pointers are + // currently treated as non-const. + if (IsConst) + return getCheckerManager().runCheckersForPointerEscape(State, + *Invalidated, + Call, + PSK_DirectEscapeOnCall, + true); + // If the symbols were invalidated by a call, we want to find out which ones // were invalidated directly due to being arguments to the call. InvalidatedSymbols SymbolsDirectlyInvalidated; @@ -2161,54 +2252,27 @@ struct DOTGraphTraits<ExplodedNode*> : break; } - default: { - if (Optional<StmtPoint> L = Loc.getAs<StmtPoint>()) { - const Stmt *S = L->getStmt(); - - Out << S->getStmtClassName() << ' ' << (const void*) S << ' '; + case ProgramPoint::PostInitializerKind: { + Out << "PostInitializer: "; + const CXXCtorInitializer *Init = + Loc.castAs<PostInitializer>().getInitializer(); + if (const FieldDecl *FD = Init->getAnyMember()) + Out << *FD; + else { + QualType Ty = Init->getTypeSourceInfo()->getType(); + Ty = Ty.getLocalUnqualifiedType(); LangOptions LO; // FIXME. - S->printPretty(Out, 0, PrintingPolicy(LO)); - printLocation(Out, S->getLocStart()); - - if (Loc.getAs<PreStmt>()) - Out << "\\lPreStmt\\l;"; - else if (Loc.getAs<PostLoad>()) - Out << "\\lPostLoad\\l;"; - else if (Loc.getAs<PostStore>()) - Out << "\\lPostStore\\l"; - else if (Loc.getAs<PostLValue>()) - Out << "\\lPostLValue\\l"; - -#if 0 - // FIXME: Replace with a general scheme to determine - // the name of the check. - if (GraphPrintCheckerState->isImplicitNullDeref(N)) - Out << "\\|Implicit-Null Dereference.\\l"; - else if (GraphPrintCheckerState->isExplicitNullDeref(N)) - Out << "\\|Explicit-Null Dereference.\\l"; - else if (GraphPrintCheckerState->isUndefDeref(N)) - Out << "\\|Dereference of undefialied value.\\l"; - else if (GraphPrintCheckerState->isUndefStore(N)) - Out << "\\|Store to Undefined Loc."; - else if (GraphPrintCheckerState->isUndefResult(N)) - Out << "\\|Result of operation is undefined."; - else if (GraphPrintCheckerState->isNoReturnCall(N)) - Out << "\\|Call to function marked \"noreturn\"."; - else if (GraphPrintCheckerState->isBadCall(N)) - Out << "\\|Call to NULL/Undefined."; - else if (GraphPrintCheckerState->isUndefArg(N)) - Out << "\\|Argument in call is undefined"; -#endif - - break; + Ty.print(Out, LO); } + break; + } + case ProgramPoint::BlockEdgeKind: { const BlockEdge &E = Loc.castAs<BlockEdge>(); Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B" << E.getDst()->getBlockID() << ')'; if (const Stmt *T = E.getSrc()->getTerminator()) { - SourceLocation SLoc = T->getLocStart(); Out << "\\|Terminator: "; @@ -2267,6 +2331,48 @@ struct DOTGraphTraits<ExplodedNode*> : Out << "\\|Control-flow based on\\lUndefined value.\\l"; } #endif + break; + } + + default: { + const Stmt *S = Loc.castAs<StmtPoint>().getStmt(); + + Out << S->getStmtClassName() << ' ' << (const void*) S << ' '; + LangOptions LO; // FIXME. + S->printPretty(Out, 0, PrintingPolicy(LO)); + printLocation(Out, S->getLocStart()); + + if (Loc.getAs<PreStmt>()) + Out << "\\lPreStmt\\l;"; + else if (Loc.getAs<PostLoad>()) + Out << "\\lPostLoad\\l;"; + else if (Loc.getAs<PostStore>()) + Out << "\\lPostStore\\l"; + else if (Loc.getAs<PostLValue>()) + Out << "\\lPostLValue\\l"; + +#if 0 + // FIXME: Replace with a general scheme to determine + // the name of the check. + if (GraphPrintCheckerState->isImplicitNullDeref(N)) + Out << "\\|Implicit-Null Dereference.\\l"; + else if (GraphPrintCheckerState->isExplicitNullDeref(N)) + Out << "\\|Explicit-Null Dereference.\\l"; + else if (GraphPrintCheckerState->isUndefDeref(N)) + Out << "\\|Dereference of undefialied value.\\l"; + else if (GraphPrintCheckerState->isUndefStore(N)) + Out << "\\|Store to Undefined Loc."; + else if (GraphPrintCheckerState->isUndefResult(N)) + Out << "\\|Result of operation is undefined."; + else if (GraphPrintCheckerState->isNoReturnCall(N)) + Out << "\\|Call to function marked \"noreturn\"."; + else if (GraphPrintCheckerState->isBadCall(N)) + Out << "\\|Call to NULL/Undefined."; + else if (GraphPrintCheckerState->isUndefArg(N)) + Out << "\\|Argument in call is undefined"; +#endif + + break; } } @@ -2301,7 +2407,7 @@ GetGraphNode<llvm::DenseMap<ExplodedNode*, Expr*>::iterator> void ExprEngine::ViewGraph(bool trim) { #ifndef NDEBUG if (trim) { - std::vector<ExplodedNode*> Src; + std::vector<const ExplodedNode*> Src; // Flush any outstanding reports to make sure we cover all the nodes. // This does not cause them to get displayed. @@ -2315,7 +2421,7 @@ void ExprEngine::ViewGraph(bool trim) { if (N) Src.push_back(N); } - ViewGraph(&Src[0], &Src[0]+Src.size()); + ViewGraph(Src); } else { GraphPrintCheckerState = this; @@ -2329,12 +2435,12 @@ void ExprEngine::ViewGraph(bool trim) { #endif } -void ExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) { +void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) { #ifndef NDEBUG GraphPrintCheckerState = this; GraphPrintSourceManager = &getContext().getSourceManager(); - std::auto_ptr<ExplodedGraph> TrimmedG(G.Trim(Beg, End).first); + OwningPtr<ExplodedGraph> TrimmedG(G.trim(Nodes)); if (!TrimmedG.get()) llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 2f2eb8628a..67aeab6003 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -68,12 +68,14 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // SymSymExpr. unsigned Count = currBldrCtx->blockCount(); if (LeftV.getAs<Loc>() && - RHS->getType()->isIntegerType() && RightV.isUnknown()) { + RHS->getType()->isIntegralOrEnumerationType() && + RightV.isUnknown()) { RightV = svalBuilder.conjureSymbolVal(RHS, LCtx, RHS->getType(), Count); } if (RightV.getAs<Loc>() && - LHS->getType()->isIntegerType() && LeftV.isUnknown()) { + LHS->getType()->isIntegralOrEnumerationType() && + LeftV.isUnknown()) { LeftV = svalBuilder.conjureSymbolVal(LHS, LCtx, LHS->getType(), Count); } @@ -401,32 +403,33 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, ExplodedNodeSet &Dst) { StmtNodeBuilder B(Pred, Dst, *currBldrCtx); - const InitListExpr *ILE - = cast<InitListExpr>(CL->getInitializer()->IgnoreParens()); + ProgramStateRef State = Pred->getState(); + const LocationContext *LCtx = Pred->getLocationContext(); + + const Expr *Init = CL->getInitializer(); + SVal V = State->getSVal(CL->getInitializer(), LCtx); - ProgramStateRef state = Pred->getState(); - SVal ILV = state->getSVal(ILE, Pred->getLocationContext()); - const LocationContext *LC = Pred->getLocationContext(); - state = state->bindCompoundLiteral(CL, LC, ILV); - - // Compound literal expressions are a GNU extension in C++. - // Unlike in C, where CLs are lvalues, in C++ CLs are prvalues, - // and like temporary objects created by the functional notation T() - // CLs are destroyed at the end of the containing full-expression. - // HOWEVER, an rvalue of array type is not something the analyzer can - // reason about, since we expect all regions to be wrapped in Locs. - // So we treat array CLs as lvalues as well, knowing that they will decay - // to pointers as soon as they are used. - if (CL->isGLValue() || CL->getType()->isArrayType()) - B.generateNode(CL, Pred, state->BindExpr(CL, LC, state->getLValue(CL, LC))); - else - B.generateNode(CL, Pred, state->BindExpr(CL, LC, ILV)); -} + if (isa<CXXConstructExpr>(Init)) { + // No work needed. Just pass the value up to this expression. + } else { + assert(isa<InitListExpr>(Init)); + Loc CLLoc = State->getLValue(CL, LCtx); + State = State->bindLoc(CLLoc, V); + + // Compound literal expressions are a GNU extension in C++. + // Unlike in C, where CLs are lvalues, in C++ CLs are prvalues, + // and like temporary objects created by the functional notation T() + // CLs are destroyed at the end of the containing full-expression. + // HOWEVER, an rvalue of array type is not something the analyzer can + // reason about, since we expect all regions to be wrapped in Locs. + // So we treat array CLs as lvalues as well, knowing that they will decay + // to pointers as soon as they are used. + if (CL->isGLValue() || CL->getType()->isArrayType()) + V = CLLoc; + } -/// The GDM component containing the set of global variables which have been -/// previously initialized with explicit initializers. -REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet, - llvm::ImmutableSet<const VarDecl *> ) + B.generateNode(CL, Pred, State->BindExpr(CL, LCtx, V)); +} void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { @@ -438,15 +441,6 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, Dst.insert(Pred); return; } - - // Check if a value has been previously initialized. There will be an entry in - // the set for variables with global storage which have been previously - // initialized. - if (VD->hasGlobalStorage()) - if (Pred->getState()->contains<InitializedGlobalsSet>(VD)) { - Dst.insert(Pred); - return; - } // FIXME: all pre/post visits should eventually be handled by ::Visit(). ExplodedNodeSet dstPreVisit; @@ -464,11 +458,6 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, // Note in the state that the initialization has occurred. ExplodedNode *UpdatedN = N; - if (VD->hasGlobalStorage()) { - state = state->add<InitializedGlobalsSet>(VD); - UpdatedN = B.generateNode(DS, N, state); - } - SVal InitVal = state->getSVal(InitEx, LC); if (isa<CXXConstructExpr>(InitEx->IgnoreImplicit())) { @@ -634,11 +623,15 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, const Expr *R, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + assert(L && R); + StmtNodeBuilder B(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); const CFGBlock *SrcBlock = 0; + // Find the predecessor block. + ProgramStateRef SrcState = state; for (const ExplodedNode *N = Pred ; N ; N = *N->pred_begin()) { ProgramPoint PP = N->getLocation(); if (PP.getAs<PreStmtPurgeDeadSymbols>() || PP.getAs<BlockEntrance>()) { @@ -646,6 +639,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, continue; } SrcBlock = PP.castAs<BlockEdge>().getSrc(); + SrcState = N->getState(); break; } @@ -661,14 +655,25 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, CFGElement CE = *I; if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) { const Expr *ValEx = cast<Expr>(CS->getStmt()); - hasValue = true; - V = state->getSVal(ValEx, LCtx); + ValEx = ValEx->IgnoreParens(); + + // For GNU extension '?:' operator, the left hand side will be an + // OpaqueValueExpr, so get the underlying expression. + if (const OpaqueValueExpr *OpaqueEx = dyn_cast<OpaqueValueExpr>(L)) + L = OpaqueEx->getSourceExpr(); + + // If the last expression in the predecessor block matches true or false + // subexpression, get its the value. + if (ValEx == L->IgnoreParens() || ValEx == R->IgnoreParens()) { + hasValue = true; + V = SrcState->getSVal(ValEx, LCtx); + } break; } } - assert(hasValue); - (void) hasValue; + if (!hasValue) + V = svalBuilder.conjureSymbolVal(0, Ex, LCtx, currBldrCtx->blockCount()); // Generate a new node with the binding from the appropriate path. B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V, true)); @@ -681,8 +686,9 @@ VisitOffsetOfExpr(const OffsetOfExpr *OOE, APSInt IV; if (OOE->EvaluateAsInt(IV, getContext())) { assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType())); - assert(OOE->getType()->isIntegerType()); - assert(IV.isSigned() == OOE->getType()->isSignedIntegerOrEnumerationType()); + assert(OOE->getType()->isBuiltinType()); + assert(OOE->getType()->getAs<BuiltinType>()->isInteger()); + assert(IV.isSigned() == OOE->getType()->isSignedIntegerType()); SVal X = svalBuilder.makeIntVal(IV); B.generateNode(OOE, Pred, Pred->getState()->BindExpr(OOE, Pred->getLocationContext(), diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 32b522cbd5..ed90dc5891 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -48,13 +48,25 @@ void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, Bldr.generateNode(ME, Pred, state); } +// FIXME: This is the sort of code that should eventually live in a Core +// checker rather than as a special case in ExprEngine. void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, - const CXXConstructorCall &Call) { - const CXXConstructExpr *CtorExpr = Call.getOriginExpr(); - assert(CtorExpr->getConstructor()->isCopyOrMoveConstructor()); - assert(CtorExpr->getConstructor()->isTrivial()); + const CallEvent &Call) { + SVal ThisVal; + bool AlwaysReturnsLValue; + if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { + assert(Ctor->getDecl()->isTrivial()); + assert(Ctor->getDecl()->isCopyOrMoveConstructor()); + ThisVal = Ctor->getCXXThisVal(); + AlwaysReturnsLValue = false; + } else { + assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial()); + assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() == + OO_Equal); + ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal(); + AlwaysReturnsLValue = true; + } - SVal ThisVal = Call.getCXXThisVal(); const LocationContext *LCtx = Pred->getLocationContext(); ExplodedNodeSet Dst; @@ -62,21 +74,48 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, SVal V = Call.getArgSVal(0); - // Make sure the value being copied is not unknown. + // If the value being copied is not unknown, load from its location to get + // an aggregate rvalue. if (Optional<Loc> L = V.getAs<Loc>()) V = Pred->getState()->getSVal(*L); + else + assert(V.isUnknown()); - evalBind(Dst, CtorExpr, Pred, ThisVal, V, true); + const Expr *CallExpr = Call.getOriginExpr(); + evalBind(Dst, CallExpr, Pred, ThisVal, V, true); - PostStmt PS(CtorExpr, LCtx); + PostStmt PS(CallExpr, LCtx); for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); - State = bindReturnValue(Call, LCtx, State); + if (AlwaysReturnsLValue) + State = State->BindExpr(CallExpr, LCtx, ThisVal); + else + State = bindReturnValue(Call, LCtx, State); Bldr.generateNode(PS, State, *I); } } + +/// Returns a region representing the first element of a (possibly +/// multi-dimensional) array. +/// +/// On return, \p Ty will be set to the base type of the array. +/// +/// If the type is not an array type at all, the original value is returned. +static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue, + QualType &Ty) { + SValBuilder &SVB = State->getStateManager().getSValBuilder(); + ASTContext &Ctx = SVB.getContext(); + + while (const ArrayType *AT = Ctx.getAsArrayType(Ty)) { + Ty = AT->getElementType(); + LValue = State->getLValue(Ty, SVB.makeZeroArrayIndex(), LValue); + } + + return LValue; +} + void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &destNodes) { @@ -84,7 +123,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ProgramStateRef State = Pred->getState(); const MemRegion *Target = 0; - bool IsArray = false; + + // FIXME: Handle arrays, which run the same constructor for every element. + // For now, we just run the first constructor (which should still invalidate + // the entire array). switch (CE->getConstructionKind()) { case CXXConstructExpr::CK_Complete: { @@ -99,19 +141,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) { if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) { if (Var->getInit()->IgnoreImplicit() == CE) { + SVal LValue = State->getLValue(Var, LCtx); QualType Ty = Var->getType(); - if (const ArrayType *AT = getContext().getAsArrayType(Ty)) { - // FIXME: Handle arrays, which run the same constructor for - // every element. This workaround will just run the first - // constructor (which should still invalidate the entire array). - SVal Base = State->getLValue(Var, LCtx); - Target = State->getLValue(AT->getElementType(), - getSValBuilder().makeZeroArrayIndex(), - Base).getAsRegion(); - IsArray = true; - } else { - Target = State->getLValue(Var, LCtx).getAsRegion(); - } + LValue = makeZeroElementRegion(State, LValue, Ty); + Target = LValue.getAsRegion(); } } } @@ -127,13 +160,19 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, LCtx->getCurrentStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); + const ValueDecl *Field; + SVal FieldVal; if (Init->isIndirectMemberInitializer()) { - SVal Field = State->getLValue(Init->getIndirectMember(), ThisVal); - Target = Field.getAsRegion(); + Field = Init->getIndirectMember(); + FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal); } else { - SVal Field = State->getLValue(Init->getMember(), ThisVal); - Target = Field.getAsRegion(); + Field = Init->getMember(); + FieldVal = State->getLValue(Init->getMember(), ThisVal); } + + QualType Ty = Field->getType(); + FieldVal = makeZeroElementRegion(State, FieldVal, Ty); + Target = FieldVal.getAsRegion(); } // FIXME: This will eventually need to handle new-expressions as well. @@ -183,6 +222,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNodeSet DstEvaluated; StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx); + bool IsArray = isa<ElementRegion>(Target); if (CE->getConstructor()->isTrivial() && CE->getConstructor()->isCopyOrMoveConstructor() && !IsArray) { @@ -215,12 +255,9 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType, // FIXME: We need to run the same destructor on every element of the array. // This workaround will just run the first destructor (which will still // invalidate the entire array). - // This is a loop because of multidimensional arrays. - while (const ArrayType *AT = getContext().getAsArrayType(ObjectType)) { - ObjectType = AT->getElementType(); - Dest = State->getLValue(ObjectType, getSValBuilder().makeZeroArrayIndex(), - loc::MemRegionVal(Dest)).getAsRegion(); - } + SVal DestVal = loc::MemRegionVal(Dest); + DestVal = makeZeroElementRegion(State, DestVal, ObjectType); + Dest = DestVal.getAsRegion(); const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl(); assert(RecordDecl && "Only CXXRecordDecls should have destructors"); @@ -255,15 +292,35 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // Also, we need to decide how allocators actually work -- they're not // really part of the CXXNewExpr because they happen BEFORE the // CXXConstructExpr subexpression. See PR12014 for some discussion. - StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); unsigned blockCount = currBldrCtx->blockCount(); const LocationContext *LCtx = Pred->getLocationContext(); - DefinedOrUnknownSVal symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, - CNE->getType(), - blockCount); - ProgramStateRef State = Pred->getState(); + DefinedOrUnknownSVal symVal = UnknownVal(); + FunctionDecl *FD = CNE->getOperatorNew(); + bool IsStandardGlobalOpNewFunction = false; + if (FD && !isa<CXXMethodDecl>(FD) && !FD->isVariadic()) { + if (FD->getNumParams() == 2) { + QualType T = FD->getParamDecl(1)->getType(); + if (const IdentifierInfo *II = T.getBaseTypeIdentifier()) + // NoThrow placement new behaves as a standard new. + IsStandardGlobalOpNewFunction = II->getName().equals("nothrow_t"); + } + else + // Placement forms are considered non-standard. + IsStandardGlobalOpNewFunction = (FD->getNumParams() == 1); + } + + // We assume all standard global 'operator new' functions allocate memory in + // heap. We realize this is an approximation that might not correctly model + // a custom global allocator. + if (IsStandardGlobalOpNewFunction) + symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); + else + symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, CNE->getType(), + blockCount); + + ProgramStateRef State = Pred->getState(); CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXAllocatorCall> Call = CEMgr.getCXXAllocatorCall(CNE, State, LCtx); @@ -272,12 +329,13 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // FIXME: Once we figure out how we want allocators to work, // we should be using the usual pre-/(default-)eval-/post-call checks here. State = Call->invalidateRegions(blockCount); + if (!State) + return; // If we're compiling with exceptions enabled, and this allocation function // is not declared as non-throwing, failures /must/ be signalled by // exceptions, and thus the return value will never be NULL. // C++11 [basic.stc.dynamic.allocation]p3. - FunctionDecl *FD = CNE->getOperatorNew(); if (FD && getContext().getLangOpts().CXXExceptions) { QualType Ty = FD->getType(); if (const FunctionProtoType *ProtoType = Ty->getAs<FunctionProtoType>()) @@ -285,6 +343,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, State = State->assume(symVal, true); } + StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); + if (CNE->isArray()) { // FIXME: allocating an array requires simulating the constructors. // For now, just return a symbolicated region. @@ -302,30 +362,32 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // CXXNewExpr, we need to make sure that the constructed object is not // immediately invalidated here. (The placement call should happen before // the constructor call anyway.) + SVal Result = symVal; if (FD && FD->isReservedGlobalPlacementOperator()) { // Non-array placement new should always return the placement location. SVal PlacementLoc = State->getSVal(CNE->getPlacementArg(0), LCtx); - SVal Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(), - CNE->getPlacementArg(0)->getType()); - State = State->BindExpr(CNE, LCtx, Result); - } else { - State = State->BindExpr(CNE, LCtx, symVal); + Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(), + CNE->getPlacementArg(0)->getType()); } + // Bind the address of the object, then check to see if we cached out. + State = State->BindExpr(CNE, LCtx, Result); + ExplodedNode *NewN = Bldr.generateNode(CNE, Pred, State); + if (!NewN) + return; + // If the type is not a record, we won't have a CXXConstructExpr as an // initializer. Copy the value over. if (const Expr *Init = CNE->getInitializer()) { if (!isa<CXXConstructExpr>(Init)) { - QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType(); - (void)ObjTy; - assert(!ObjTy->isRecordType()); - SVal Location = State->getSVal(CNE, LCtx); - if (Optional<Loc> LV = Location.getAs<Loc>()) - State = State->bindLoc(*LV, State->getSVal(Init, LCtx)); + assert(Bldr.getResults().size() == 1); + Bldr.takeNodes(NewN); + + assert(!CNE->getType()->getPointeeCXXRecordDecl()); + evalBind(Dst, CNE, NewN, Result, State->getSVal(Init, LCtx), + /*FirstInit=*/IsStandardGlobalOpNewFunction); } } - - Bldr.generateNode(CNE, Pred, State); } void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 44803dc477..06570a4b4a 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -578,9 +578,15 @@ void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr, Bldr.generateNode(Call.getProgramPoint(), State, Pred); } -static bool shouldInlineCallKind(const CallEvent &Call, - const ExplodedNode *Pred, - AnalyzerOptions &Opts) { +enum CallInlinePolicy { + CIP_Allowed, + CIP_DisallowedOnce, + CIP_DisallowedAlways +}; + +static CallInlinePolicy mayInlineCallKind(const CallEvent &Call, + const ExplodedNode *Pred, + AnalyzerOptions &Opts) { const LocationContext *CurLC = Pred->getLocationContext(); const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame(); switch (Call.getKind()) { @@ -590,18 +596,20 @@ static bool shouldInlineCallKind(const CallEvent &Call, case CE_CXXMember: case CE_CXXMemberOperator: if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions)) - return false; + return CIP_DisallowedAlways; break; case CE_CXXConstructor: { if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors)) - return false; + return CIP_DisallowedAlways; const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call); // FIXME: We don't handle constructors or destructors for arrays properly. + // Even once we do, we still need to be careful about implicitly-generated + // initializers for array fields in default move/copy constructors. const MemRegion *Target = Ctor.getCXXThisVal().getAsRegion(); if (Target && isa<ElementRegion>(Target)) - return false; + return CIP_DisallowedOnce; // FIXME: This is a hack. We don't use the correct region for a new // expression, so if we inline the constructor its result will just be @@ -610,7 +618,7 @@ static bool shouldInlineCallKind(const CallEvent &Call, const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr(); if (const Stmt *Parent = CurLC->getParentMap().getParent(CtorExpr)) if (isa<CXXNewExpr>(Parent)) - return false; + return CIP_DisallowedOnce; // Inlining constructors requires including initializers in the CFG. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); @@ -624,19 +632,19 @@ static bool shouldInlineCallKind(const CallEvent &Call, // For other types, only inline constructors if destructor inlining is // also enabled. if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) - return false; + return CIP_DisallowedAlways; // FIXME: This is a hack. We don't handle temporary destructors // right now, so we shouldn't inline their constructors. if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete) if (!Target || !isa<DeclRegion>(Target)) - return false; + return CIP_DisallowedOnce; break; } case CE_CXXDestructor: { if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) - return false; + return CIP_DisallowedAlways; // Inlining destructors requires building the CFG correctly. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); @@ -648,22 +656,117 @@ static bool shouldInlineCallKind(const CallEvent &Call, // FIXME: We don't handle constructors or destructors for arrays properly. const MemRegion *Target = Dtor.getCXXThisVal().getAsRegion(); if (Target && isa<ElementRegion>(Target)) - return false; + return CIP_DisallowedOnce; break; } case CE_CXXAllocator: // Do not inline allocators until we model deallocators. // This is unfortunate, but basically necessary for smart pointers and such. - return false; + return CIP_DisallowedAlways; case CE_ObjCMessage: if (!Opts.mayInlineObjCMethod()) - return false; + return CIP_DisallowedAlways; if (!(Opts.getIPAMode() == IPAK_DynamicDispatch || Opts.getIPAMode() == IPAK_DynamicDispatchBifurcate)) - return false; + return CIP_DisallowedAlways; break; } + + return CIP_Allowed; +} + +/// Returns true if the given C++ class contains a member with the given name. +static bool hasMember(const ASTContext &Ctx, const CXXRecordDecl *RD, + StringRef Name) { + const IdentifierInfo &II = Ctx.Idents.get(Name); + DeclarationName DeclName = Ctx.DeclarationNames.getIdentifier(&II); + if (!RD->lookup(DeclName).empty()) + return true; + + CXXBasePaths Paths(false, false, false); + if (RD->lookupInBases(&CXXRecordDecl::FindOrdinaryMember, + DeclName.getAsOpaquePtr(), + Paths)) + return true; + + return false; +} + +/// Returns true if the given C++ class is a container or iterator. +/// +/// Our heuristic for this is whether it contains a method named 'begin()' or a +/// nested type named 'iterator' or 'iterator_category'. +static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD) { + return hasMember(Ctx, RD, "begin") || + hasMember(Ctx, RD, "iterator") || + hasMember(Ctx, RD, "iterator_category"); +} + +/// Returns true if the given function refers to a constructor or destructor of +/// a C++ container or iterator. +/// +/// We generally do a poor job modeling most containers right now, and would +/// prefer not to inline their setup and teardown. +static bool isContainerCtorOrDtor(const ASTContext &Ctx, + const FunctionDecl *FD) { + if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD))) + return false; + + const CXXRecordDecl *RD = cast<CXXMethodDecl>(FD)->getParent(); + return isContainerClass(Ctx, RD); +} + +/// Returns true if the function in \p CalleeADC may be inlined in general. +/// +/// This checks static properties of the function, such as its signature and +/// CFG, to determine whether the analyzer should ever consider inlining it, +/// in any context. +static bool mayInlineDecl(const CallEvent &Call, AnalysisDeclContext *CalleeADC, + AnalyzerOptions &Opts) { + // FIXME: Do not inline variadic calls. + if (Call.isVariadic()) + return false; + + // Check certain C++-related inlining policies. + ASTContext &Ctx = CalleeADC->getASTContext(); + if (Ctx.getLangOpts().CPlusPlus) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeADC->getDecl())) { + // Conditionally control the inlining of template functions. + if (!Opts.mayInlineTemplateFunctions()) + if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate) + return false; + + // Conditionally control the inlining of C++ standard library functions. + if (!Opts.mayInlineCXXStandardLibrary()) + if (Ctx.getSourceManager().isInSystemHeader(FD->getLocation())) + if (IsInStdNamespace(FD)) + return false; + + // Conditionally control the inlining of methods on objects that look + // like C++ containers. + if (!Opts.mayInlineCXXContainerCtorsAndDtors()) + if (!Ctx.getSourceManager().isFromMainFile(FD->getLocation())) + if (isContainerCtorOrDtor(Ctx, FD)) + return false; + } + } + + // It is possible that the CFG cannot be constructed. + // Be safe, and check if the CalleeCFG is valid. + const CFG *CalleeCFG = CalleeADC->getCFG(); + if (!CalleeCFG) + return false; + + // Do not inline large functions. + if (CalleeCFG->getNumBlockIDs() > Opts.getMaxInlinableSize()) + return false; + + // It is possible that the live variables analysis cannot be + // run. If so, bail out. + if (!CalleeADC->getAnalysis<RelaxedLiveVariables>()) + return false; + return true; } @@ -683,18 +786,40 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D, if (CalleeADC->isBodyAutosynthesized()) return true; - if (HowToInline == Inline_None) + if (!AMgr.shouldInlineCall()) return false; + // Check if this function has been marked as non-inlinable. + Optional<bool> MayInline = Engine.FunctionSummaries->mayInline(D); + if (MayInline.hasValue()) { + if (!MayInline.getValue()) + return false; + + } else { + // We haven't actually checked the static properties of this function yet. + // Do that now, and record our decision in the function summaries. + if (mayInlineDecl(Call, CalleeADC, Opts)) { + Engine.FunctionSummaries->markMayInline(D); + } else { + Engine.FunctionSummaries->markShouldNotInline(D); + return false; + } + } + // Check if we should inline a call based on its kind. - if (!shouldInlineCallKind(Call, Pred, Opts)) + // FIXME: this checks both static and dynamic properties of the call, which + // means we're redoing a bit of work that could be cached in the function + // summary. + CallInlinePolicy CIP = mayInlineCallKind(Call, Pred, Opts); + if (CIP != CIP_Allowed) { + if (CIP == CIP_DisallowedAlways) { + assert(!MayInline.hasValue() || MayInline.getValue()); + Engine.FunctionSummaries->markShouldNotInline(D); + } return false; + } - // It is possible that the CFG cannot be constructed. - // Be safe, and check if the CalleeCFG is valid. const CFG *CalleeCFG = CalleeADC->getCFG(); - if (!CalleeCFG) - return false; // Do not inline if recursive or we've reached max stack frame count. bool IsRecursive = false; @@ -705,39 +830,6 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D, || IsRecursive)) return false; - // Do not inline if it took too long to inline previously. - if (Engine.FunctionSummaries->hasReachedMaxBlockCount(D)) - return false; - - // Or if the function is too big. - if (CalleeCFG->getNumBlockIDs() > Opts.getMaxInlinableSize()) - return false; - - // Do not inline variadic calls (for now). - if (Call.isVariadic()) - return false; - - // Check our template policy. - if (getContext().getLangOpts().CPlusPlus) { - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // Conditionally allow the inlining of template functions. - if (!Opts.mayInlineTemplateFunctions()) - if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate) - return false; - - // Conditionally allow the inlining of C++ standard library functions. - if (!Opts.mayInlineCXXStandardLibrary()) - if (getContext().getSourceManager().isInSystemHeader(FD->getLocation())) - if (IsInStdNamespace(FD)) - return false; - } - } - - // It is possible that the live variables analysis cannot be - // run. If so, bail out. - if (!CalleeADC->getAnalysis<RelaxedLiveVariables>()) - return false; - // Do not inline large functions too many times. if ((Engine.FunctionSummaries->getNumTimesInlined(D) > Opts.getMaxTimesInlineLarge()) && @@ -745,17 +837,43 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D, NumReachedInlineCountMax++; return false; } + + if (HowToInline == Inline_Minimal && + (CalleeCFG->getNumBlockIDs() > Opts.getAlwaysInlineSize() + || IsRecursive)) + return false; + Engine.FunctionSummaries->bumpNumTimesInlined(D); return true; } +static bool isTrivialObjectAssignment(const CallEvent &Call) { + const CXXInstanceCall *ICall = dyn_cast<CXXInstanceCall>(&Call); + if (!ICall) + return false; + + const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(ICall->getDecl()); + if (!MD) + return false; + if (!(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())) + return false; + + return MD->isTrivial(); +} + void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, const CallEvent &CallTemplate) { // Make sure we have the most recent state attached to the call. ProgramStateRef State = Pred->getState(); CallEventRef<> Call = CallTemplate.cloneWithState(State); + // Special-case trivial assignment operators. + if (isTrivialObjectAssignment(*Call)) { + performTrivialCopy(Bldr, Pred, *Call); + return; + } + // Try to inline the call. // The origin expression here is just used as a kind of checksum; // this should still be safe even for CallEvents that don't come from exprs. diff --git a/lib/StaticAnalyzer/Core/FunctionSummary.cpp b/lib/StaticAnalyzer/Core/FunctionSummary.cpp index c227aac2b4..c21735b8b8 100644 --- a/lib/StaticAnalyzer/Core/FunctionSummary.cpp +++ b/lib/StaticAnalyzer/Core/FunctionSummary.cpp @@ -1,4 +1,4 @@ -//== FunctionSummary.h - Stores summaries of functions. ------------*- C++ -*-// +//== FunctionSummary.cpp - Stores summaries of functions. ----------*- C++ -*-// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines a summary of a function gathered/used by static analyzes. +// This file defines a summary of a function gathered/used by static analysis. // //===----------------------------------------------------------------------===// @@ -15,16 +15,10 @@ using namespace clang; using namespace ento; -FunctionSummariesTy::~FunctionSummariesTy() { - for (MapTy::iterator I = Map.begin(), E = Map.end(); I != E; ++I) { - delete(I->second); - } -} - unsigned FunctionSummariesTy::getTotalNumBasicBlocks() { unsigned Total = 0; for (MapTy::iterator I = Map.begin(), E = Map.end(); I != E; ++I) { - Total += I->second->TotalBasicBlocks; + Total += I->second.TotalBasicBlocks; } return Total; } @@ -32,7 +26,7 @@ unsigned FunctionSummariesTy::getTotalNumBasicBlocks() { unsigned FunctionSummariesTy::getTotalNumVisitedBasicBlocks() { unsigned Total = 0; for (MapTy::iterator I = Map.begin(), E = Map.end(); I != E; ++I) { - Total += I->second->VisitedBasicBlocks.count(); + Total += I->second.VisitedBasicBlocks.count(); } return Total; } diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index b3a1e65b19..42073d4841 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -555,38 +555,75 @@ void StackLocalsSpaceRegion::dumpToStream(raw_ostream &os) const { } bool MemRegion::canPrintPretty() const { + return canPrintPrettyAsExpr(); +} + +bool MemRegion::canPrintPrettyAsExpr() const { return false; } void MemRegion::printPretty(raw_ostream &os) const { + assert(canPrintPretty() && "This region cannot be printed pretty."); + os << "'"; + printPrettyAsExpr(os); + os << "'"; + return; +} + +void MemRegion::printPrettyAsExpr(raw_ostream &os) const { + llvm_unreachable("This region cannot be printed pretty."); return; } -bool VarRegion::canPrintPretty() const { +bool VarRegion::canPrintPrettyAsExpr() const { return true; } -void VarRegion::printPretty(raw_ostream &os) const { +void VarRegion::printPrettyAsExpr(raw_ostream &os) const { os << getDecl()->getName(); } -bool ObjCIvarRegion::canPrintPretty() const { +bool ObjCIvarRegion::canPrintPrettyAsExpr() const { return true; } -void ObjCIvarRegion::printPretty(raw_ostream &os) const { +void ObjCIvarRegion::printPrettyAsExpr(raw_ostream &os) const { os << getDecl()->getName(); } bool FieldRegion::canPrintPretty() const { - return superRegion->canPrintPretty(); + return true; } -void FieldRegion::printPretty(raw_ostream &os) const { - superRegion->printPretty(os); +bool FieldRegion::canPrintPrettyAsExpr() const { + return superRegion->canPrintPrettyAsExpr(); +} + +void FieldRegion::printPrettyAsExpr(raw_ostream &os) const { + assert(canPrintPrettyAsExpr()); + superRegion->printPrettyAsExpr(os); os << "." << getDecl()->getName(); } +void FieldRegion::printPretty(raw_ostream &os) const { + if (canPrintPrettyAsExpr()) { + os << "\'"; + printPrettyAsExpr(os); + os << "'"; + } else { + os << "field " << "\'" << getDecl()->getName() << "'"; + } + return; +} + +bool CXXBaseObjectRegion::canPrintPrettyAsExpr() const { + return superRegion->canPrintPrettyAsExpr(); +} + +void CXXBaseObjectRegion::printPrettyAsExpr(raw_ostream &os) const { + superRegion->printPrettyAsExpr(os); +} + //===----------------------------------------------------------------------===// // MemRegionManager methods. //===----------------------------------------------------------------------===// @@ -1043,6 +1080,17 @@ const MemRegion *MemRegion::StripCasts(bool StripBaseCasts) const { } } +const SymbolicRegion *MemRegion::getSymbolicBase() const { + const SubRegion *SubR = dyn_cast<SubRegion>(this); + + while (SubR) { + if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SubR)) + return SymR; + SubR = dyn_cast<SubRegion>(SubR->getSuperRegion()); + } + return 0; +} + // FIXME: Merge with the implementation of the same method in Store.cpp static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { if (const RecordType *RT = Ty->getAs<RecordType>()) { diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 686540b60e..03513106ec 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -297,11 +297,16 @@ static Optional<bool> comparePiece(const PathDiagnosticPiece &X, static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { if (X.size() != Y.size()) return X.size() < Y.size(); - for (unsigned i = 0, n = X.size(); i != n; ++i) { - Optional<bool> b = comparePiece(*X[i], *Y[i]); + + PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); + PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); + + for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) { + Optional<bool> b = comparePiece(**X_I, **Y_I); if (b.hasValue()) return b.getValue(); } + return None; } @@ -588,6 +593,9 @@ PathDiagnosticLocation S = SP->getStmt(); if (P.getAs<PostStmtPurgeDeadSymbols>()) return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); + } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { + return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), + SMng); } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { return PathDiagnosticLocation(PIE->getLocation(), SMng); } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { @@ -605,31 +613,73 @@ PathDiagnosticLocation return PathDiagnosticLocation(S, SMng, P.getLocationContext()); } +const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { + ProgramPoint P = N->getLocation(); + if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) + return SP->getStmt(); + if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) + return BE->getSrc()->getTerminator(); + if (Optional<CallEnter> CE = P.getAs<CallEnter>()) + return CE->getCallExpr(); + if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) + return CEE->getCalleeContext()->getCallSite(); + if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>()) + return PIPP->getInitializer()->getInit(); + + return 0; +} + +const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { + for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) { + if (const Stmt *S = getStmt(N)) { + // Check if the statement is '?' or '&&'/'||'. These are "merges", + // not actual statement points. + switch (S->getStmtClass()) { + case Stmt::ChooseExprClass: + case Stmt::BinaryConditionalOperatorClass: + case Stmt::ConditionalOperatorClass: + continue; + case Stmt::BinaryOperatorClass: { + BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode(); + if (Op == BO_LAnd || Op == BO_LOr) + continue; + break; + } + default: + break; + } + // We found the statement, so return it. + return S; + } + } + + return 0; +} + PathDiagnosticLocation - PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N, + PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N, const SourceManager &SM) { assert(N && "Cannot create a location with a null node."); + const Stmt *S = getStmt(N); - const ExplodedNode *NI = N; - const Stmt *S = 0; - - while (NI) { - ProgramPoint P = NI->getLocation(); - if (Optional<StmtPoint> PS = P.getAs<StmtPoint>()) { - S = PS->getStmt(); - if (P.getAs<PostStmtPurgeDeadSymbols>()) - return PathDiagnosticLocation::createEnd(S, SM, - NI->getLocationContext()); - break; - } else if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { - S = BE->getSrc()->getTerminator(); - break; - } - NI = NI->succ_empty() ? 0 : *(NI->succ_begin()); - } + if (!S) + S = getNextStmt(N); if (S) { - const LocationContext *LC = NI->getLocationContext(); + ProgramPoint P = N->getLocation(); + const LocationContext *LC = N->getLocationContext(); + + // For member expressions, return the location of the '.' or '->'. + if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) + return PathDiagnosticLocation::createMemberLoc(ME, SM); + + // For binary operators, return the location of the operator. + if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) + return PathDiagnosticLocation::createOperatorLoc(B, SM); + + if (P.getAs<PostStmtPurgeDeadSymbols>()) + return PathDiagnosticLocation::createEnd(S, SM, LC); + if (S->getLocStart().isValid()) return PathDiagnosticLocation(S, SM, LC); return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM); diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index 7dcc088d18..850955561e 100644 --- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -296,6 +296,8 @@ static void ReportCall(raw_ostream &o, for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I) ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, true); + + --depth; IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit = P.getCallExitEvent(); diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index 64205f8d99..653b69bf48 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -111,14 +111,6 @@ ProgramStateManager::removeDeadBindings(ProgramStateRef state, return ConstraintMgr->removeDeadBindings(Result, SymReaper); } -ProgramStateRef ProgramState::bindCompoundLiteral(const CompoundLiteralExpr *CL, - const LocationContext *LC, - SVal V) const { - const StoreRef &newStore = - getStateManager().StoreMgr->bindCompoundLiteral(getStore(), CL, LC, V); - return makeWithStore(newStore); -} - ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V, bool notifyChanges) const { ProgramStateManager &Mgr = getStateManager(); ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(), @@ -140,51 +132,103 @@ ProgramStateRef ProgramState::bindDefault(SVal loc, SVal V) const { new_state; } +typedef ArrayRef<const MemRegion *> RegionList; +typedef ArrayRef<SVal> ValueList; + ProgramStateRef -ProgramState::invalidateRegions(ArrayRef<const MemRegion *> Regions, +ProgramState::invalidateRegions(RegionList Regions, const Expr *E, unsigned Count, const LocationContext *LCtx, bool CausedByPointerEscape, InvalidatedSymbols *IS, - const CallEvent *Call) const { + const CallEvent *Call, + RegionList ConstRegions) const { + SmallVector<SVal, 8> Values; + for (RegionList::const_iterator I = Regions.begin(), + End = Regions.end(); I != End; ++I) + Values.push_back(loc::MemRegionVal(*I)); + + SmallVector<SVal, 8> ConstValues; + for (RegionList::const_iterator I = ConstRegions.begin(), + End = ConstRegions.end(); I != End; ++I) + ConstValues.push_back(loc::MemRegionVal(*I)); + if (!IS) { InvalidatedSymbols invalidated; - return invalidateRegionsImpl(Regions, E, Count, LCtx, + return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape, - invalidated, Call); + invalidated, Call, ConstValues); } - return invalidateRegionsImpl(Regions, E, Count, LCtx, CausedByPointerEscape, - *IS, Call); + return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape, + *IS, Call, ConstValues); } -ProgramStateRef -ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions, +ProgramStateRef +ProgramState::invalidateRegions(ValueList Values, + const Expr *E, unsigned Count, + const LocationContext *LCtx, + bool CausedByPointerEscape, + InvalidatedSymbols *IS, + const CallEvent *Call, + ValueList ConstValues) const { + if (!IS) { + InvalidatedSymbols invalidated; + return invalidateRegionsImpl(Values, E, Count, LCtx, + CausedByPointerEscape, + invalidated, Call, ConstValues); + } + return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape, + *IS, Call, ConstValues); +} + +ProgramStateRef +ProgramState::invalidateRegionsImpl(ValueList Values, const Expr *E, unsigned Count, const LocationContext *LCtx, bool CausedByPointerEscape, InvalidatedSymbols &IS, - const CallEvent *Call) const { + const CallEvent *Call, + ValueList ConstValues) const { ProgramStateManager &Mgr = getStateManager(); SubEngine* Eng = Mgr.getOwningEngine(); - + InvalidatedSymbols ConstIS; + if (Eng) { + StoreManager::InvalidatedRegions TopLevelInvalidated; + StoreManager::InvalidatedRegions TopLevelConstInvalidated; StoreManager::InvalidatedRegions Invalidated; const StoreRef &newStore - = Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS, - Call, &Invalidated); + = Mgr.StoreMgr->invalidateRegions(getStore(), Values, ConstValues, + E, Count, LCtx, Call, + IS, ConstIS, + &TopLevelInvalidated, + &TopLevelConstInvalidated, + &Invalidated); ProgramStateRef newState = makeWithStore(newStore); - if (CausedByPointerEscape) - newState = Eng->processPointerEscapedOnInvalidateRegions(newState, - &IS, Regions, Invalidated, Call); + if (CausedByPointerEscape) { + newState = Eng->notifyCheckersOfPointerEscape(newState, &IS, + TopLevelInvalidated, + Invalidated, Call); + if (!ConstValues.empty()) { + StoreManager::InvalidatedRegions Empty; + newState = Eng->notifyCheckersOfPointerEscape(newState, &ConstIS, + TopLevelConstInvalidated, + Empty, Call, + true); + } + } - return Eng->processRegionChanges(newState, &IS, Regions, Invalidated, Call); + return Eng->processRegionChanges(newState, &IS, + TopLevelInvalidated, Invalidated, + Call); } const StoreRef &newStore = - Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS, - Call, NULL); + Mgr.StoreMgr->invalidateRegions(getStore(), Values, ConstValues, + E, Count, LCtx, Call, + IS, ConstIS, NULL, NULL, NULL); return makeWithStore(newStore); } @@ -218,7 +262,7 @@ SVal ProgramState::getSValAsScalarOrLoc(const MemRegion *R) const { if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { QualType T = TR->getValueType(); - if (Loc::isLocType(T) || T->isIntegerType()) + if (Loc::isLocType(T) || T->isIntegralOrEnumerationType()) return getSVal(R); } @@ -328,9 +372,13 @@ ConditionTruthVal ProgramState::isNull(SVal V) const { if (V.isZeroConstant()) return true; - SymbolRef Sym = V.getAsSymbol(); - if (!Sym) + if (V.isConstant()) return false; + + SymbolRef Sym = V.getAsSymbol(/* IncludeBaseRegion */ true); + if (!Sym) + return ConditionTruthVal(); + return getStateManager().ConstraintMgr->isNull(this, Sym); } diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index d397e47224..3606e099ce 100644 --- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -153,8 +153,8 @@ private: // The function returns false if the described range is entirely outside // the range of values for the associated symbol. APSIntType Type(getMinValue()); - APSIntType::RangeTestResultKind LowerTest = Type.testInRange(Lower); - APSIntType::RangeTestResultKind UpperTest = Type.testInRange(Upper); + APSIntType::RangeTestResultKind LowerTest = Type.testInRange(Lower, true); + APSIntType::RangeTestResultKind UpperTest = Type.testInRange(Upper, true); switch (LowerTest) { case APSIntType::RTR_Below: @@ -285,8 +285,8 @@ namespace { class RangeConstraintManager : public SimpleConstraintManager{ RangeSet GetRange(ProgramStateRef state, SymbolRef sym); public: - RangeConstraintManager(SubEngine *subengine, BasicValueFactory &BVF) - : SimpleConstraintManager(subengine, BVF) {} + RangeConstraintManager(SubEngine *subengine, SValBuilder &SVB) + : SimpleConstraintManager(subengine, SVB) {} ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, @@ -328,7 +328,7 @@ private: ConstraintManager * ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) { - return new RangeConstraintManager(Eng, StMgr.getBasicVals()); + return new RangeConstraintManager(Eng, StMgr.getSValBuilder()); } const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St, @@ -419,7 +419,7 @@ RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym, const llvm::APSInt &Adjustment) { // Before we do any real work, see if the value can even show up. APSIntType AdjustmentType(Adjustment); - if (AdjustmentType.testInRange(Int) != APSIntType::RTR_Within) + if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within) return St; llvm::APSInt Lower = AdjustmentType.convert(Int) - Adjustment; @@ -439,7 +439,7 @@ RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym, const llvm::APSInt &Adjustment) { // Before we do any real work, see if the value can even show up. APSIntType AdjustmentType(Adjustment); - if (AdjustmentType.testInRange(Int) != APSIntType::RTR_Within) + if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within) return NULL; // [Int-Adjustment, Int-Adjustment] @@ -454,7 +454,7 @@ RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym, const llvm::APSInt &Adjustment) { // Before we do any real work, see if the value can even show up. APSIntType AdjustmentType(Adjustment); - switch (AdjustmentType.testInRange(Int)) { + switch (AdjustmentType.testInRange(Int, true)) { case APSIntType::RTR_Below: return NULL; case APSIntType::RTR_Within: @@ -483,7 +483,7 @@ RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym, const llvm::APSInt &Adjustment) { // Before we do any real work, see if the value can even show up. APSIntType AdjustmentType(Adjustment); - switch (AdjustmentType.testInRange(Int)) { + switch (AdjustmentType.testInRange(Int, true)) { case APSIntType::RTR_Below: return St; case APSIntType::RTR_Within: @@ -512,7 +512,7 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym, const llvm::APSInt &Adjustment) { // Before we do any real work, see if the value can even show up. APSIntType AdjustmentType(Adjustment); - switch (AdjustmentType.testInRange(Int)) { + switch (AdjustmentType.testInRange(Int, true)) { case APSIntType::RTR_Below: return St; case APSIntType::RTR_Within: @@ -541,7 +541,7 @@ RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym, const llvm::APSInt &Adjustment) { // Before we do any real work, see if the value can even show up. APSIntType AdjustmentType(Adjustment); - switch (AdjustmentType.testInRange(Int)) { + switch (AdjustmentType.testInRange(Int, true)) { case APSIntType::RTR_Below: return NULL; case APSIntType::RTR_Within: diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index 82db23dd6b..88c4eee4bb 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -19,10 +19,12 @@ #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Basic/TargetInfo.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" #include "llvm/ADT/ImmutableList.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/Optional.h" @@ -318,10 +320,12 @@ public: //===----------------------------------------------------------------------===// namespace { +class invalidateRegionsWorker; class RegionStoreManager : public StoreManager { public: const RegionStoreFeatures Features; + RegionBindings::Factory RBFactory; mutable ClusterBindings::Factory CBFactory; @@ -331,10 +335,34 @@ private: SValListTy> LazyBindingsMapTy; LazyBindingsMapTy LazyBindingsMap; + /// The largest number of fields a struct can have and still be + /// considered "small". + /// + /// This is currently used to decide whether or not it is worth "forcing" a + /// LazyCompoundVal on bind. + /// + /// This is controlled by 'region-store-small-struct-limit' option. + /// To disable all small-struct-dependent behavior, set the option to "0". + unsigned SmallStructLimit; + + /// \brief A helper used to populate the work list with the given set of + /// regions. + void populateWorkList(invalidateRegionsWorker &W, + ArrayRef<SVal> Values, + bool IsArrayOfConstRegions, + InvalidatedRegions *TopLevelRegions); + public: RegionStoreManager(ProgramStateManager& mgr, const RegionStoreFeatures &f) : StoreManager(mgr), Features(f), - RBFactory(mgr.getAllocator()), CBFactory(mgr.getAllocator()) {} + RBFactory(mgr.getAllocator()), CBFactory(mgr.getAllocator()), + SmallStructLimit(0) { + if (SubEngine *Eng = StateMgr.getOwningEngine()) { + AnalyzerOptions &Options = Eng->getAnalysisManager().options; + SmallStructLimit = + Options.getOptionAsInteger("region-store-small-struct-limit", 2); + } + } /// setImplicitDefaultValue - Set the default binding for the provided @@ -365,12 +393,17 @@ public: RegionBindingsRef B, InvalidatedRegions *Invalidated); - StoreRef invalidateRegions(Store store, ArrayRef<const MemRegion *> Regions, + StoreRef invalidateRegions(Store store, + ArrayRef<SVal> Values, + ArrayRef<SVal> ConstValues, const Expr *E, unsigned Count, const LocationContext *LCtx, - InvalidatedSymbols &IS, const CallEvent *Call, - InvalidatedRegions *Invalidated); + InvalidatedSymbols &IS, + InvalidatedSymbols &ConstIS, + InvalidatedRegions *Invalidated, + InvalidatedRegions *InvalidatedTopLevel, + InvalidatedRegions *InvalidatedTopLevelConst); bool scanReachableSymbols(Store S, const MemRegion *R, ScanReachableSymbols &Callbacks); @@ -396,19 +429,20 @@ public: // Part of public interface to class. .getRootWithoutRetain(), *this); } - /// \brief Create a new store that binds a value to a compound literal. - /// - /// \param ST The original store whose bindings are the basis for the new - /// store. + /// Attempt to extract the fields of \p LCV and bind them to the struct region + /// \p R. /// - /// \param CL The compound literal to bind (the binding key). + /// This path is used when it seems advantageous to "force" loading the values + /// within a LazyCompoundVal to bind memberwise to the struct region, rather + /// than using a Default binding at the base of the entire region. This is a + /// heuristic attempting to avoid building long chains of LazyCompoundVals. /// - /// \param LC The LocationContext for the binding. - /// - /// \param V The value to bind to the compound literal. - StoreRef bindCompoundLiteral(Store ST, - const CompoundLiteralExpr *CL, - const LocationContext *LC, SVal V); + /// \returns The updated store bindings, or \c None if binding non-lazily + /// would be too expensive. + Optional<RegionBindingsRef> tryBindSmallStruct(RegionBindingsConstRef B, + const TypedValueRegion *R, + const RecordDecl *RD, + nonloc::LazyCompoundVal LCV); /// BindStruct - Bind a compound value to a structure. RegionBindingsRef bindStruct(RegionBindingsConstRef B, @@ -477,8 +511,7 @@ public: // Part of public interface to class. SVal getBindingForFieldOrElementCommon(RegionBindingsConstRef B, const TypedValueRegion *R, - QualType Ty, - const MemRegion *superR); + QualType Ty); SVal getLazyBinding(const SubRegion *LazyBindingRegion, RegionBindingsRef LazyBinding); @@ -591,11 +624,23 @@ ento::CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr) { //===----------------------------------------------------------------------===// namespace { +/// Used to determine which global regions are automatically included in the +/// initial worklist of a ClusterAnalysis. +enum GlobalsFilterKind { + /// Don't include any global regions. + GFK_None, + /// Only include system globals. + GFK_SystemOnly, + /// Include all global regions. + GFK_All +}; + template <typename DERIVED> class ClusterAnalysis { protected: typedef llvm::DenseMap<const MemRegion *, const ClusterBindings *> ClusterMap; - typedef SmallVector<const MemRegion *, 10> WorkList; + typedef llvm::PointerIntPair<const MemRegion *, 1, bool> WorkListElement; + typedef SmallVector<WorkListElement, 10> WorkList; llvm::SmallPtrSet<const ClusterBindings *, 16> Visited; @@ -606,19 +651,36 @@ protected: SValBuilder &svalBuilder; RegionBindingsRef B; - - const bool includeGlobals; +private: + GlobalsFilterKind GlobalsFilter; + +protected: const ClusterBindings *getCluster(const MemRegion *R) { return B.lookup(R); } + /// Returns true if the memory space of the given region is one of the global + /// regions specially included at the start of analysis. + bool isInitiallyIncludedGlobalRegion(const MemRegion *R) { + switch (GlobalsFilter) { + case GFK_None: + return false; + case GFK_SystemOnly: + return isa<GlobalSystemSpaceRegion>(R->getMemorySpace()); + case GFK_All: + return isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace()); + } + + llvm_unreachable("unknown globals filter"); + } + public: ClusterAnalysis(RegionStoreManager &rm, ProgramStateManager &StateMgr, - RegionBindingsRef b, const bool includeGlobals) + RegionBindingsRef b, GlobalsFilterKind GFK) : RM(rm), Ctx(StateMgr.getContext()), svalBuilder(StateMgr.getSValBuilder()), - B(b), includeGlobals(includeGlobals) {} + B(b), GlobalsFilter(GFK) {} RegionBindingsRef getRegionBindings() const { return B; } @@ -636,41 +698,41 @@ public: assert(!Cluster.isEmpty() && "Empty clusters should be removed"); static_cast<DERIVED*>(this)->VisitAddedToCluster(Base, Cluster); - if (includeGlobals) - if (isa<NonStaticGlobalSpaceRegion>(Base->getMemorySpace())) - AddToWorkList(Base, &Cluster); + // If this is an interesting global region, add it the work list up front. + if (isInitiallyIncludedGlobalRegion(Base)) + AddToWorkList(WorkListElement(Base), &Cluster); } } - bool AddToWorkList(const MemRegion *R, const ClusterBindings *C) { + bool AddToWorkList(WorkListElement E, const ClusterBindings *C) { if (C && !Visited.insert(C)) return false; - WL.push_back(R); + WL.push_back(E); return true; } - bool AddToWorkList(const MemRegion *R) { - const MemRegion *baseR = R->getBaseRegion(); - return AddToWorkList(baseR, getCluster(baseR)); + bool AddToWorkList(const MemRegion *R, bool Flag = false) { + const MemRegion *BaseR = R->getBaseRegion(); + return AddToWorkList(WorkListElement(BaseR, Flag), getCluster(BaseR)); } void RunWorkList() { while (!WL.empty()) { - const MemRegion *baseR = WL.pop_back_val(); + WorkListElement E = WL.pop_back_val(); + const MemRegion *BaseR = E.getPointer(); - // First visit the cluster. - if (const ClusterBindings *Cluster = getCluster(baseR)) - static_cast<DERIVED*>(this)->VisitCluster(baseR, *Cluster); - - // Next, visit the base region. - static_cast<DERIVED*>(this)->VisitBaseRegion(baseR); + static_cast<DERIVED*>(this)->VisitCluster(BaseR, getCluster(BaseR), + E.getInt()); } } -public: void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C) {} - void VisitCluster(const MemRegion *baseR, const ClusterBindings &C) {} - void VisitBaseRegion(const MemRegion *baseR) {} + void VisitCluster(const MemRegion *baseR, const ClusterBindings *C) {} + + void VisitCluster(const MemRegion *BaseR, const ClusterBindings *C, + bool Flag) { + static_cast<DERIVED*>(this)->VisitCluster(BaseR, C); + } }; } @@ -831,14 +893,22 @@ RegionStoreManager::removeSubRegionBindings(RegionBindingsConstRef B, const SubRegion *Top) { BindingKey TopKey = BindingKey::Make(Top, BindingKey::Default); const MemRegion *ClusterHead = TopKey.getBaseRegion(); + if (Top == ClusterHead) { // We can remove an entire cluster's bindings all in one go. return B.remove(Top); } const ClusterBindings *Cluster = B.lookup(ClusterHead); - if (!Cluster) + if (!Cluster) { + // If we're invalidating a region with a symbolic offset, we need to make + // sure we don't treat the base region as uninitialized anymore. + if (TopKey.hasSymbolicOffset()) { + const SubRegion *Concrete = TopKey.getConcreteOffsetRegion(); + return B.addBinding(Concrete, BindingKey::Default, UnknownVal()); + } return B; + } SmallVector<BindingPair, 32> Bindings; collectSubRegionBindings(Bindings, svalBuilder, *Cluster, Top, TopKey, @@ -852,7 +922,8 @@ RegionStoreManager::removeSubRegionBindings(RegionBindingsConstRef B, // If we're invalidating a region with a symbolic offset, we need to make sure // we don't treat the base region as uninitialized anymore. - // FIXME: This isn't very precise; see the example in the loop. + // FIXME: This isn't very precise; see the example in + // collectSubRegionBindings. if (TopKey.hasSymbolicOffset()) { const SubRegion *Concrete = TopKey.getConcreteOffsetRegion(); Result = Result.add(BindingKey::Make(Concrete, BindingKey::Default), @@ -871,6 +942,7 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker> unsigned Count; const LocationContext *LCtx; InvalidatedSymbols &IS; + InvalidatedSymbols &ConstIS; StoreManager::InvalidatedRegions *Regions; public: invalidateRegionsWorker(RegionStoreManager &rm, @@ -879,15 +951,16 @@ public: const Expr *ex, unsigned count, const LocationContext *lctx, InvalidatedSymbols &is, + InvalidatedSymbols &inConstIS, StoreManager::InvalidatedRegions *r, - bool includeGlobals) - : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals), - Ex(ex), Count(count), LCtx(lctx), IS(is), Regions(r) {} - - void VisitCluster(const MemRegion *baseR, const ClusterBindings &C); - void VisitBaseRegion(const MemRegion *baseR); - -private: + GlobalsFilterKind GFK) + : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, GFK), + Ex(ex), Count(count), LCtx(lctx), IS(is), ConstIS(inConstIS), Regions(r){} + + /// \param IsConst Specifies if the region we are invalidating is constant. + /// If it is, we invalidate all subregions, but not the base region itself. + void VisitCluster(const MemRegion *baseR, const ClusterBindings *C, + bool IsConst); void VisitBinding(SVal V); }; } @@ -917,18 +990,17 @@ void invalidateRegionsWorker::VisitBinding(SVal V) { } } -void invalidateRegionsWorker::VisitCluster(const MemRegion *BaseR, - const ClusterBindings &C) { - for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I) - VisitBinding(I.getData()); - - B = B.remove(BaseR); -} +void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, + const ClusterBindings *C, + bool IsConst) { + if (C) { + for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I) + VisitBinding(I.getData()); -void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { - // Symbolic region? Mark that symbol touched by the invalidation. - if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) - IS.insert(SR->getSymbol()); + // Invalidate the contents of a non-const base region. + if (!IsConst) + B = B.remove(baseR); + } // BlockDataRegion? If so, invalidate captured variables that are passed // by reference. @@ -957,6 +1029,21 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { return; } + // Symbolic region? + if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) { + SymbolRef RegionSym = SR->getSymbol(); + + // Mark that symbol touched by the invalidation. + if (IsConst) + ConstIS.insert(RegionSym); + else + IS.insert(RegionSym); + } + + // Nothing else should be done for a const region. + if (IsConst) + return; + // Otherwise, we have a normal data region. Record that we touched the region. if (Regions) Regions->push_back(baseR); @@ -976,7 +1063,13 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { const TypedValueRegion *TR = cast<TypedValueRegion>(baseR); QualType T = TR->getValueType(); - // Invalidate the binding. + if (isInitiallyIncludedGlobalRegion(baseR)) { + // If the region is a global and we are invalidating all globals, + // erasing the entry is good enough. This causes all globals to be lazily + // symbolicated from the same base symbol. + return; + } + if (T->isStructureOrClassType()) { // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelavant. @@ -994,16 +1087,6 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { B = B.addBinding(baseR, BindingKey::Default, V); return; } - - if (includeGlobals && - isa<NonStaticGlobalSpaceRegion>(baseR->getMemorySpace())) { - // If the region is a global and we are invalidating all globals, - // just erase the entry. This causes all globals to be lazily - // symbolicated from the same base symbol. - B = B.removeBinding(baseR); - return; - } - DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, T,Count); @@ -1036,45 +1119,92 @@ RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K, return B; } +void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W, + ArrayRef<SVal> Values, + bool IsArrayOfConstRegions, + InvalidatedRegions *TopLevelRegions) { + for (ArrayRef<SVal>::iterator I = Values.begin(), + E = Values.end(); I != E; ++I) { + SVal V = *I; + if (Optional<nonloc::LazyCompoundVal> LCS = + V.getAs<nonloc::LazyCompoundVal>()) { + + const SValListTy &Vals = getInterestingValues(*LCS); + + for (SValListTy::const_iterator I = Vals.begin(), + E = Vals.end(); I != E; ++I) { + // Note: the last argument is false here because these are + // non-top-level regions. + if (const MemRegion *R = (*I).getAsRegion()) + W.AddToWorkList(R, /*IsConst=*/ false); + } + continue; + } + + if (const MemRegion *R = V.getAsRegion()) { + if (TopLevelRegions) + TopLevelRegions->push_back(R); + W.AddToWorkList(R, /*IsConst=*/ IsArrayOfConstRegions); + continue; + } + } +} + StoreRef RegionStoreManager::invalidateRegions(Store store, - ArrayRef<const MemRegion *> Regions, + ArrayRef<SVal> Values, + ArrayRef<SVal> ConstValues, const Expr *Ex, unsigned Count, const LocationContext *LCtx, - InvalidatedSymbols &IS, const CallEvent *Call, + InvalidatedSymbols &IS, + InvalidatedSymbols &ConstIS, + InvalidatedRegions *TopLevelRegions, + InvalidatedRegions *TopLevelConstRegions, InvalidatedRegions *Invalidated) { - invalidateRegionsWorker W(*this, StateMgr, - RegionStoreManager::getRegionBindings(store), - Ex, Count, LCtx, IS, Invalidated, false); + GlobalsFilterKind GlobalsFilter; + if (Call) { + if (Call->isInSystemHeader()) + GlobalsFilter = GFK_SystemOnly; + else + GlobalsFilter = GFK_All; + } else { + GlobalsFilter = GFK_None; + } + + RegionBindingsRef B = getRegionBindings(store); + invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ConstIS, + Invalidated, GlobalsFilter); // Scan the bindings and generate the clusters. W.GenerateClusters(); // Add the regions to the worklist. - for (ArrayRef<const MemRegion *>::iterator - I = Regions.begin(), E = Regions.end(); I != E; ++I) - W.AddToWorkList(*I); + populateWorkList(W, Values, /*IsArrayOfConstRegions*/ false, + TopLevelRegions); + populateWorkList(W, ConstValues, /*IsArrayOfConstRegions*/ true, + TopLevelConstRegions); W.RunWorkList(); // Return the new bindings. - RegionBindingsRef B = W.getRegionBindings(); + B = W.getRegionBindings(); - // For all globals which are not static nor immutable: determine which global - // regions should be invalidated and invalidate them. + // For calls, determine which global regions should be invalidated and + // invalidate them. (Note that function-static and immutable globals are never + // invalidated by this.) // TODO: This could possibly be more precise with modules. - // - // System calls invalidate only system globals. - if (Call && Call->isInSystemHeader()) { - B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, + switch (GlobalsFilter) { + case GFK_All: + B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, Ex, Count, LCtx, B, Invalidated); - // Internal calls might invalidate both system and internal globals. - } else { + // FALLTHROUGH + case GFK_SystemOnly: B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, Ex, Count, LCtx, B, Invalidated); - B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, - Ex, Count, LCtx, B, Invalidated); + // FALLTHROUGH + case GFK_None: + break; } return StoreRef(B.asStore(), *this); @@ -1265,6 +1395,17 @@ SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T) return svalBuilder.getRegionValueSymbolVal(R); } +static QualType getUnderlyingType(const SubRegion *R) { + QualType RegionTy; + if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R)) + RegionTy = TVR->getValueType(); + + if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) + RegionTy = SR->getSymbol()->getType(); + + return RegionTy; +} + /// Checks to see if store \p B has a lazy binding for region \p R. /// /// If \p AllowSubregionBindings is \c false, a lazy binding will be rejected @@ -1283,11 +1424,11 @@ getExistingLazyBinding(SValBuilder &SVB, RegionBindingsConstRef B, if (!LCV) return None; - // If the LCV is for a subregion, the types won't match, and we shouldn't - // reuse the binding. Unfortuately we can only check this if the destination - // region is a TypedValueRegion. - if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R)) { - QualType RegionTy = TVR->getValueType(); + // If the LCV is for a subregion, the types might not match, and we shouldn't + // reuse the binding. + QualType RegionTy = getUnderlyingType(R); + if (!RegionTy.isNull() && + !RegionTy->isVoidPointerType()) { QualType SourceRegionTy = LCV->getRegion()->getValueType(); if (!SVB.getContext().hasSameUnqualifiedType(RegionTy, SourceRegionTy)) return None; @@ -1424,8 +1565,7 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B, } } } - return getBindingForFieldOrElementCommon(B, R, R->getElementType(), - superR); + return getBindingForFieldOrElementCommon(B, R, R->getElementType()); } SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B, @@ -1436,7 +1576,7 @@ SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B, return *V; QualType Ty = R->getValueType(); - return getBindingForFieldOrElementCommon(B, R, Ty, R->getSuperRegion()); + return getBindingForFieldOrElementCommon(B, R, Ty); } Optional<SVal> @@ -1499,8 +1639,7 @@ SVal RegionStoreManager::getLazyBinding(const SubRegion *LazyBindingRegion, SVal RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B, const TypedValueRegion *R, - QualType Ty, - const MemRegion *superR) { + QualType Ty) { // At this point we have already checked in either getBindingForElement or // getBindingForField if 'R' has a direct binding. @@ -1533,8 +1672,9 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B, // quickly result in a warning. bool hasPartialLazyBinding = false; - const SubRegion *Base = dyn_cast<SubRegion>(superR); - while (Base) { + const SubRegion *SR = dyn_cast<SubRegion>(R); + while (SR) { + const MemRegion *Base = SR->getSuperRegion(); if (Optional<SVal> D = getBindingForDerivedDefaultValue(B, Base, R, Ty)) { if (D->getAs<nonloc::LazyCompoundVal>()) { hasPartialLazyBinding = true; @@ -1552,7 +1692,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B, // If our super region is a field or element itself, walk up the region // hierarchy to see if there is a default value installed in an ancestor. - Base = dyn_cast<SubRegion>(Base->getSuperRegion()); + SR = dyn_cast<SubRegion>(Base); } if (R->hasStackNonParametersStorage()) { @@ -1560,7 +1700,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B, // Currently we don't reason specially about Clang-style vectors. Check // if superR is a vector and if so return Unknown. if (const TypedValueRegion *typedSuperR = - dyn_cast<TypedValueRegion>(superR)) { + dyn_cast<TypedValueRegion>(R->getSuperRegion())) { if (typedSuperR->getValueType()->isVectorType()) return UnknownVal(); } @@ -1601,26 +1741,6 @@ SVal RegionStoreManager::getBindingForObjCIvar(RegionBindingsConstRef B, return getBindingForLazySymbol(R); } -static Optional<SVal> getConstValue(SValBuilder &SVB, const VarDecl *VD) { - ASTContext &Ctx = SVB.getContext(); - if (!VD->getType().isConstQualified()) - return None; - - const Expr *Init = VD->getInit(); - if (!Init) - return None; - - llvm::APSInt Result; - if (!Init->isGLValue() && Init->EvaluateAsInt(Result, Ctx)) - return SVB.makeIntVal(Result); - - if (Init->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull)) - return SVB.makeNull(); - - // FIXME: Handle other possible constant expressions. - return None; -} - SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B, const VarRegion *R) { @@ -1637,8 +1757,10 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B, return svalBuilder.getRegionValueSymbolVal(R); // Is 'VD' declared constant? If so, retrieve the constant value. - if (Optional<SVal> V = getConstValue(svalBuilder, VD)) - return *V; + if (VD->getType().isConstQualified()) + if (const Expr *Init = VD->getInit()) + if (Optional<SVal> V = svalBuilder.getConstantVal(Init)) + return *V; // This must come after the check for constants because closure-captured // constant variables may appear in UnknownSpaceRegion. @@ -1810,14 +1932,6 @@ RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) { return NewB.addBinding(BindingKey::Make(R, BindingKey::Direct), V); } -// FIXME: this method should be merged into Bind(). -StoreRef RegionStoreManager::bindCompoundLiteral(Store ST, - const CompoundLiteralExpr *CL, - const LocationContext *LC, - SVal V) { - return Bind(ST, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), V); -} - RegionBindingsRef RegionStoreManager::setImplicitDefaultValue(RegionBindingsConstRef B, const MemRegion *R, @@ -1826,7 +1940,7 @@ RegionStoreManager::setImplicitDefaultValue(RegionBindingsConstRef B, if (Loc::isLocType(T)) V = svalBuilder.makeNull(); - else if (T->isIntegerType()) + else if (T->isIntegralOrEnumerationType()) V = svalBuilder.makeZeroVal(T); else if (T->isStructureOrClassType() || T->isArrayType()) { // Set the default value to a zero constant when it is a structure @@ -1896,7 +2010,7 @@ RegionStoreManager::bindArray(RegionBindingsConstRef B, else if (ElementTy->isArrayType()) NewB = bindArray(NewB, ER, *VI); else - NewB = bind(NewB, svalBuilder.makeLoc(ER), *VI); + NewB = bind(NewB, loc::MemRegionVal(ER), *VI); } // If the init list is shorter than the array length, set the @@ -1937,14 +2051,56 @@ RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B, NonLoc Idx = svalBuilder.makeArrayIndex(index); const ElementRegion *ER = MRMgr.getElementRegion(ElemType, Idx, R, Ctx); - + if (ElemType->isArrayType()) NewB = bindArray(NewB, ER, *VI); else if (ElemType->isStructureOrClassType()) NewB = bindStruct(NewB, ER, *VI); else - NewB = bind(NewB, svalBuilder.makeLoc(ER), *VI); + NewB = bind(NewB, loc::MemRegionVal(ER), *VI); + } + return NewB; +} + +Optional<RegionBindingsRef> +RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B, + const TypedValueRegion *R, + const RecordDecl *RD, + nonloc::LazyCompoundVal LCV) { + FieldVector Fields; + + if (const CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(RD)) + if (Class->getNumBases() != 0 || Class->getNumVBases() != 0) + return None; + + for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I) { + const FieldDecl *FD = *I; + if (FD->isUnnamedBitfield()) + continue; + + // If there are too many fields, or if any of the fields are aggregates, + // just use the LCV as a default binding. + if (Fields.size() == SmallStructLimit) + return None; + + QualType Ty = FD->getType(); + if (!(Ty->isScalarType() || Ty->isReferenceType())) + return None; + + Fields.push_back(*I); } + + RegionBindingsRef NewB = B; + + for (FieldVector::iterator I = Fields.begin(), E = Fields.end(); I != E; ++I){ + const FieldRegion *SourceFR = MRMgr.getFieldRegion(*I, LCV.getRegion()); + SVal V = getBindingForField(getRegionBindings(LCV.getStore()), SourceFR); + + const FieldRegion *DestFR = MRMgr.getFieldRegion(*I, R); + NewB = bind(NewB, loc::MemRegionVal(DestFR), V); + } + return NewB; } @@ -1958,13 +2114,19 @@ RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B, assert(T->isStructureOrClassType()); const RecordType* RT = T->getAs<RecordType>(); - RecordDecl *RD = RT->getDecl(); + const RecordDecl *RD = RT->getDecl(); if (!RD->isCompleteDefinition()) return B; // Handle lazy compound values and symbolic values. - if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::SymbolVal>()) + if (Optional<nonloc::LazyCompoundVal> LCV = + V.getAs<nonloc::LazyCompoundVal>()) { + if (Optional<RegionBindingsRef> NewB = tryBindSmallStruct(B, R, RD, *LCV)) + return *NewB; + return bindAggregate(B, R, V); + } + if (V.getAs<nonloc::SymbolVal>()) return bindAggregate(B, R, V); // We may get non-CompoundVal accidentally due to imprecise cast logic or @@ -1996,7 +2158,7 @@ RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B, else if (FTy->isStructureOrClassType()) NewB = bindStruct(NewB, FR, *VI); else - NewB = bind(NewB, svalBuilder.makeLoc(FR), *VI); + NewB = bind(NewB, loc::MemRegionVal(FR), *VI); ++VI; } @@ -2034,13 +2196,13 @@ public: ProgramStateManager &stateMgr, RegionBindingsRef b, SymbolReaper &symReaper, const StackFrameContext *LCtx) - : ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b, - /* includeGlobals = */ false), + : ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b, GFK_None), SymReaper(symReaper), CurrentLCtx(LCtx) {} // Called by ClusterAnalysis. void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C); - void VisitCluster(const MemRegion *baseR, const ClusterBindings &C); + void VisitCluster(const MemRegion *baseR, const ClusterBindings *C); + using ClusterAnalysis<removeDeadBindingsWorker>::VisitCluster; bool UpdatePostponed(); void VisitBinding(SVal V); @@ -2083,13 +2245,16 @@ void removeDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR, } void removeDeadBindingsWorker::VisitCluster(const MemRegion *baseR, - const ClusterBindings &C) { + const ClusterBindings *C) { + if (!C) + return; + // Mark the symbol for any SymbolicRegion with live bindings as live itself. // This means we should continue to track that symbol. if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(baseR)) SymReaper.markLive(SymR->getSymbol()); - for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I) + for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I) VisitBinding(I.getData()); } diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp index c72e780801..9d77a3ef58 100644 --- a/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -33,7 +33,7 @@ DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType type) { if (Loc::isLocType(type)) return makeNull(); - if (type->isIntegerType()) + if (type->isIntegralOrEnumerationType()) return makeIntVal(0, type); // FIXME: Handle floats. @@ -106,12 +106,19 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) { return nonloc::SymbolVal(sym); } -DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, - const Expr *expr, +DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag, + const Expr *Ex, const LocationContext *LCtx, - unsigned count) { - QualType T = expr->getType(); - return conjureSymbolVal(symbolTag, expr, LCtx, T, count); + unsigned Count) { + QualType T = Ex->getType(); + + // Compute the type of the result. If the expression is not an R-value, the + // result should be a location. + QualType ExType = Ex->getType(); + if (Ex->isGLValue()) + T = LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType); + + return conjureSymbolVal(SymbolTag, Ex, LCtx, T, Count); } DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, @@ -217,6 +224,68 @@ loc::MemRegionVal SValBuilder::getCXXThis(const CXXRecordDecl *D, return loc::MemRegionVal(getRegionManager().getCXXThisRegion(PT, SFC)); } +Optional<SVal> SValBuilder::getConstantVal(const Expr *E) { + E = E->IgnoreParens(); + + switch (E->getStmtClass()) { + // Handle expressions that we treat differently from the AST's constant + // evaluator. + case Stmt::AddrLabelExprClass: + return makeLoc(cast<AddrLabelExpr>(E)); + + case Stmt::CXXScalarValueInitExprClass: + case Stmt::ImplicitValueInitExprClass: + return makeZeroVal(E->getType()); + + case Stmt::ObjCStringLiteralClass: { + const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(E); + return makeLoc(getRegionManager().getObjCStringRegion(SL)); + } + + case Stmt::StringLiteralClass: { + const StringLiteral *SL = cast<StringLiteral>(E); + return makeLoc(getRegionManager().getStringRegion(SL)); + } + + // Fast-path some expressions to avoid the overhead of going through the AST's + // constant evaluator + case Stmt::CharacterLiteralClass: { + const CharacterLiteral *C = cast<CharacterLiteral>(E); + return makeIntVal(C->getValue(), C->getType()); + } + + case Stmt::CXXBoolLiteralExprClass: + return makeBoolVal(cast<CXXBoolLiteralExpr>(E)); + + case Stmt::IntegerLiteralClass: + return makeIntVal(cast<IntegerLiteral>(E)); + + case Stmt::ObjCBoolLiteralExprClass: + return makeBoolVal(cast<ObjCBoolLiteralExpr>(E)); + + case Stmt::CXXNullPtrLiteralExprClass: + return makeNull(); + + // If we don't have a special case, fall back to the AST's constant evaluator. + default: { + // Don't try to come up with a value for materialized temporaries. + if (E->isGLValue()) + return None; + + ASTContext &Ctx = getContext(); + llvm::APSInt Result; + if (E->EvaluateAsInt(Result, Ctx)) + return makeIntVal(Result); + + if (Loc::isLocType(E->getType())) + if (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull)) + return makeNull(); + + return None; + } + } +} + //===----------------------------------------------------------------------===// SVal SValBuilder::makeSymExprValNN(ProgramStateRef State, @@ -320,6 +389,22 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { if (val.isUnknownOrUndef() || castTy == originalTy) return val; + if (castTy->isBooleanType()) { + if (val.isUnknownOrUndef()) + return val; + if (val.isConstant()) + return makeTruthVal(!val.isZeroConstant(), castTy); + if (SymbolRef Sym = val.getAsSymbol()) { + BasicValueFactory &BVF = getBasicValueFactory(); + // FIXME: If we had a state here, we could see if the symbol is known to + // be zero, but we don't. + return makeNonLoc(Sym, BO_NE, BVF.getValue(0, Sym->getType()), castTy); + } + + assert(val.getAs<Loc>()); + return makeTruthVal(true, castTy); + } + // For const casts, casts to void, just propagate the value. if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType()) if (shouldBeModeledWithNoOp(Context, Context.getPointerType(castTy), @@ -327,11 +412,11 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { return val; // Check for casts from pointers to integers. - if (castTy->isIntegerType() && Loc::isLocType(originalTy)) + if (castTy->isIntegralOrEnumerationType() && Loc::isLocType(originalTy)) return evalCastFromLoc(val.castAs<Loc>(), castTy); // Check for casts from integers to pointers. - if (Loc::isLocType(castTy) && originalTy->isIntegerType()) { + if (Loc::isLocType(castTy) && originalTy->isIntegralOrEnumerationType()) { if (Optional<nonloc::LocAsInteger> LV = val.getAs<nonloc::LocAsInteger>()) { if (const MemRegion *R = LV->getLoc().getAsRegion()) { StoreManager &storeMgr = StateMgr.getStoreManager(); @@ -361,7 +446,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { // Are we casting from an array to an integer? If so, cast the decayed // pointer value to an integer. - assert(castTy->isIntegerType()); + assert(castTy->isIntegralOrEnumerationType()); // FIXME: Keep these here for now in case we decide soon that we // need the original decayed type. @@ -373,7 +458,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { // Check for casts from a region to a specific type. if (const MemRegion *R = val.getAsRegion()) { // Handle other casts of locations to integers. - if (castTy->isIntegerType()) + if (castTy->isIntegralOrEnumerationType()) return evalCastFromLoc(loc::MemRegionVal(R), castTy); // FIXME: We should handle the case where we strip off view layers to get diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp index da52a90ec5..650691535f 100644 --- a/lib/StaticAnalyzer/Core/SVals.cpp +++ b/lib/StaticAnalyzer/Core/SVals.cpp @@ -64,14 +64,18 @@ const FunctionDecl *SVal::getAsFunctionDecl() const { /// /// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element /// region. If that is the case, gets the underlining region. -SymbolRef SVal::getAsLocSymbol() const { +/// When IncludeBaseRegions is set to true and the SubRegion is non-symbolic, +/// the first symbolic parent region is returned. +SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const { // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>()) return X->getLoc().getAsLocSymbol(); if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) { - const MemRegion *R = X->stripCasts(); - if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R)) + const MemRegion *R = X->getRegion(); + if (const SymbolicRegion *SymR = IncludeBaseRegions ? + R->getSymbolicBase() : + dyn_cast<SymbolicRegion>(R->StripCasts())) return SymR->getSymbol(); } return 0; @@ -99,13 +103,17 @@ SymbolRef SVal::getLocSymbolInBase() const { // TODO: The next 3 functions have to be simplified. /// \brief If this SVal wraps a symbol return that SymbolRef. -/// Otherwise return 0. -SymbolRef SVal::getAsSymbol() const { +/// Otherwise, return 0. +/// +/// Casts are ignored during lookup. +/// \param IncludeBaseRegions The boolean that controls whether the search +/// should continue to the base regions if the region is not symbolic. +SymbolRef SVal::getAsSymbol(bool IncludeBaseRegion) const { // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>()) return X->getSymbol(); - return getAsLocSymbol(); + return getAsLocSymbol(IncludeBaseRegion); } /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then @@ -214,13 +222,12 @@ SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, const loc::ConcreteInt& R) const { - assert (Op == BO_Add || Op == BO_Sub || - (Op >= BO_LT && Op <= BO_NE)); + assert(BinaryOperator::isComparisonOp(Op) || Op == BO_Sub); - const llvm::APSInt* X = BasicVals.evalAPSInt(Op, getValue(), R.getValue()); + const llvm::APSInt *X = BasicVals.evalAPSInt(Op, getValue(), R.getValue()); if (X) - return loc::ConcreteInt(*X); + return nonloc::ConcreteInt(*X); else return UndefinedVal(); } diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp index de13241cac..a06268dd33 100644 --- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp +++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp @@ -49,6 +49,16 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const { } } + if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) { + if (BinaryOperator::isComparisonOp(SSE->getOpcode())) { + // We handle Loc <> Loc comparisons, but not (yet) NonLoc <> NonLoc. + if (Loc::isLocType(SSE->getLHS()->getType())) { + assert(Loc::isLocType(SSE->getRHS()->getType())); + return true; + } + } + } + return false; } @@ -80,20 +90,15 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state, case loc::MemRegionKind: { // FIXME: Should this go into the storemanager? - const MemRegion *R = Cond.castAs<loc::MemRegionVal>().getRegion(); - const SubRegion *SubR = dyn_cast<SubRegion>(R); - - while (SubR) { - // FIXME: now we only find the first symbolic region. - if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SubR)) { - const llvm::APSInt &zero = getBasicVals().getZeroWithPtrWidth(); - if (Assumption) - return assumeSymNE(state, SymR->getSymbol(), zero, zero); - else - return assumeSymEQ(state, SymR->getSymbol(), zero, zero); - } - SubR = dyn_cast<SubRegion>(SubR->getSuperRegion()); + + // FIXME: now we only find the first symbolic region. + if (const SymbolicRegion *SymR = R->getSymbolicBase()) { + const llvm::APSInt &zero = getBasicVals().getZeroWithPtrWidth(); + if (Assumption) + return assumeSymNE(state, SymR->getSymbol(), zero, zero); + else + return assumeSymEQ(state, SymR->getSymbol(), zero, zero); } // FALL-THROUGH. @@ -119,21 +124,6 @@ ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state, return state; } -static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) { - // FIXME: This should probably be part of BinaryOperator, since this isn't - // the only place it's used. (This code was copied from SimpleSValBuilder.cpp.) - switch (op) { - default: - llvm_unreachable("Invalid opcode."); - case BO_LT: return BO_GE; - case BO_GT: return BO_LE; - case BO_LE: return BO_GT; - case BO_GE: return BO_LT; - case BO_EQ: return BO_NE; - case BO_NE: return BO_EQ; - } -} - ProgramStateRef SimpleConstraintManager::assumeAuxForSymbol(ProgramStateRef State, @@ -142,7 +132,7 @@ SimpleConstraintManager::assumeAuxForSymbol(ProgramStateRef State, QualType T = Sym->getType(); // None of the constraint solvers currently support non-integer types. - if (!T->isIntegerType()) + if (!T->isIntegralOrEnumerationType()) return State; const llvm::APSInt &zero = BVF.getValue(0, T); @@ -164,8 +154,6 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state, return assumeAuxForSymbol(state, sym, Assumption); } - BasicValueFactory &BasicVals = getBasicVals(); - switch (Cond.getSubKind()) { default: llvm_unreachable("'Assume' not implemented for this NonLoc"); @@ -180,26 +168,45 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state, return assumeAuxForSymbol(state, sym, Assumption); // Handle symbolic expression. - } else { + } else if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(sym)) { // We can only simplify expressions whose RHS is an integer. - const SymIntExpr *SE = dyn_cast<SymIntExpr>(sym); - if (!SE) - return assumeAuxForSymbol(state, sym, Assumption); BinaryOperator::Opcode op = SE->getOpcode(); - // Implicitly compare non-comparison expressions to 0. - if (!BinaryOperator::isComparisonOp(op)) { - QualType T = SE->getType(); - const llvm::APSInt &zero = BasicVals.getValue(0, T); - op = (Assumption ? BO_NE : BO_EQ); - return assumeSymRel(state, SE, op, zero); + if (BinaryOperator::isComparisonOp(op)) { + if (!Assumption) + op = BinaryOperator::negateComparisonOp(op); + + return assumeSymRel(state, SE->getLHS(), op, SE->getRHS()); } - // From here on out, op is the real comparison we'll be testing. - if (!Assumption) - op = NegateComparison(op); - return assumeSymRel(state, SE->getLHS(), op, SE->getRHS()); + } else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(sym)) { + // Translate "a != b" to "(b - a) != 0". + // We invert the order of the operands as a heuristic for how loop + // conditions are usually written ("begin != end") as compared to length + // calculations ("end - begin"). The more correct thing to do would be to + // canonicalize "a - b" and "b - a", which would allow us to treat + // "a != b" and "b != a" the same. + SymbolManager &SymMgr = getSymbolManager(); + BinaryOperator::Opcode Op = SSE->getOpcode(); + assert(BinaryOperator::isComparisonOp(Op)); + + // For now, we only support comparing pointers. + assert(Loc::isLocType(SSE->getLHS()->getType())); + assert(Loc::isLocType(SSE->getRHS()->getType())); + QualType DiffTy = SymMgr.getContext().getPointerDiffType(); + SymbolRef Subtraction = SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub, + SSE->getLHS(), DiffTy); + + const llvm::APSInt &Zero = getBasicVals().getValue(0, DiffTy); + Op = BinaryOperator::reverseComparisonOp(Op); + if (!Assumption) + Op = BinaryOperator::negateComparisonOp(Op); + return assumeSymRel(state, Subtraction, Op, Zero); } + + // If we get here, there's nothing else we can do but treat the symbol as + // opaque. + return assumeAuxForSymbol(state, sym, Assumption); } case nonloc::ConcreteIntKind: { @@ -257,10 +264,14 @@ ProgramStateRef SimpleConstraintManager::assumeSymRel(ProgramStateRef state, APSIntType ComparisonType = std::max(WraparoundType, APSIntType(Int)); llvm::APSInt ConvertedInt = ComparisonType.convert(Int); + // Prefer unsigned comparisons. + if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() && + ComparisonType.isUnsigned() && !WraparoundType.isUnsigned()) + Adjustment.setIsSigned(false); + switch (op) { default: - // No logic yet for other operators. assume the constraint is feasible. - return state; + llvm_unreachable("invalid operation not caught by assertion above"); case BO_EQ: return assumeSymEQ(state, Sym, ConvertedInt, Adjustment); diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h index 01f0b4e446..10ddef1341 100644 --- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h +++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h @@ -23,10 +23,10 @@ namespace ento { class SimpleConstraintManager : public ConstraintManager { SubEngine *SU; - BasicValueFactory &BVF; + SValBuilder &SVB; public: - SimpleConstraintManager(SubEngine *subengine, BasicValueFactory &BV) - : SU(subengine), BVF(BV) {} + SimpleConstraintManager(SubEngine *subengine, SValBuilder &SB) + : SU(subengine), SVB(SB) {} virtual ~SimpleConstraintManager(); //===------------------------------------------------------------------===// @@ -81,7 +81,8 @@ protected: // Internal implementation. //===------------------------------------------------------------------===// - BasicValueFactory &getBasicVals() const { return BVF; } + BasicValueFactory &getBasicVals() const { return SVB.getBasicValueFactory(); } + SymbolManager &getSymbolManager() const { return SVB.getSymbolManager(); } bool canReasonAbout(SVal X) const; diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 3e50c33000..ee627f2baa 100644 --- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -109,7 +109,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { // Only handle casts from integers to integers - if val is an integer constant // being cast to a non integer type, produce unknown. - if (!isLocType && !castTy->isIntegerType()) + if (!isLocType && !castTy->isIntegralOrEnumerationType()) return UnknownVal(); llvm::APSInt i = val.castAs<nonloc::ConcreteInt>().getValue(); @@ -137,7 +137,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) { if (castTy->isUnionType()) return UnknownVal(); - if (castTy->isIntegerType()) { + if (castTy->isIntegralOrEnumerationType()) { unsigned BitWidth = Context.getTypeSize(castTy); if (!val.getAs<loc::ConcreteInt>()) @@ -180,33 +180,6 @@ SVal SimpleSValBuilder::evalComplement(NonLoc X) { // Transfer function for binary operators. //===----------------------------------------------------------------------===// -static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) { - switch (op) { - default: - llvm_unreachable("Invalid opcode."); - case BO_LT: return BO_GE; - case BO_GT: return BO_LE; - case BO_LE: return BO_GT; - case BO_GE: return BO_LT; - case BO_EQ: return BO_NE; - case BO_NE: return BO_EQ; - } -} - -static BinaryOperator::Opcode ReverseComparison(BinaryOperator::Opcode op) { - switch (op) { - default: - llvm_unreachable("Invalid opcode."); - case BO_LT: return BO_GT; - case BO_GT: return BO_LT; - case BO_LE: return BO_GE; - case BO_GE: return BO_LE; - case BO_EQ: - case BO_NE: - return op; - } -} - SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op, const llvm::APSInt &RHS, @@ -398,7 +371,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, case BO_GT: case BO_LE: case BO_GE: - op = ReverseComparison(op); + op = BinaryOperator::reverseComparisonOp(op); // FALL-THROUGH case BO_EQ: case BO_NE: @@ -465,9 +438,13 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, case BO_GE: case BO_EQ: case BO_NE: + assert(resultTy->isBooleanType() || + resultTy == getConditionType()); + assert(symIntExpr->getType()->isBooleanType() || + getContext().hasSameUnqualifiedType(symIntExpr->getType(), + getConditionType())); // Negate the comparison and make a value. - opc = NegateComparison(opc); - assert(symIntExpr->getType() == resultTy); + opc = BinaryOperator::negateComparisonOp(opc); return makeNonLoc(symIntExpr->getLHS(), opc, symIntExpr->getRHS(), resultTy); } @@ -508,22 +485,21 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, // Otherwise, make a SymIntExpr out of the expression. return MakeSymIntVal(symIntExpr, op, *RHSValue, resultTy); } + } - - } else if (isa<SymbolData>(Sym)) { - // Does the symbol simplify to a constant? If so, "fold" the constant - // by setting 'lhs' to a ConcreteInt and try again. - if (const llvm::APSInt *Constant = state->getConstraintManager() - .getSymVal(state, Sym)) { - lhs = nonloc::ConcreteInt(*Constant); - continue; - } - - // Is the RHS a constant? - if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs)) - return MakeSymIntVal(Sym, op, *RHSValue, resultTy); + // Does the symbolic expression simplify to a constant? + // If so, "fold" the constant by setting 'lhs' to a ConcreteInt + // and try again. + ConstraintManager &CMgr = state->getConstraintManager(); + if (const llvm::APSInt *Constant = CMgr.getSymVal(state, Sym)) { + lhs = nonloc::ConcreteInt(*Constant); + continue; } + // Is the RHS a constant? + if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs)) + return MakeSymIntVal(Sym, op, *RHSValue, resultTy); + // Give up -- this is not a symbolic expression we can handle. return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy); } @@ -602,17 +578,19 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state, return UnknownVal(); const llvm::APSInt &lVal = lhs.castAs<loc::ConcreteInt>().getValue(); - return makeNonLoc(rSym, ReverseComparison(op), lVal, resultTy); + op = BinaryOperator::reverseComparisonOp(op); + return makeNonLoc(rSym, op, lVal, resultTy); } // If both operands are constants, just perform the operation. if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) { SVal ResultVal = lhs.castAs<loc::ConcreteInt>().evalBinOp(BasicVals, op, *rInt); - if (Optional<Loc> Result = ResultVal.getAs<Loc>()) - return evalCastFromLoc(*Result, resultTy); - else - return UnknownVal(); + if (Optional<NonLoc> Result = ResultVal.getAs<NonLoc>()) + return evalCastFromNonLoc(*Result, resultTy); + + assert(!ResultVal.getAs<Loc>() && "Loc-Loc ops should not produce Locs"); + return UnknownVal(); } // Special case comparisons against NULL. @@ -682,11 +660,11 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state, // regions, though. return UnknownVal(); - const MemSpaceRegion *LeftMS = LeftMR->getMemorySpace(); - const MemSpaceRegion *RightMS = RightMR->getMemorySpace(); - const MemSpaceRegion *UnknownMS = MemMgr.getUnknownRegion(); const MemRegion *LeftBase = LeftMR->getBaseRegion(); const MemRegion *RightBase = RightMR->getBaseRegion(); + const MemSpaceRegion *LeftMS = LeftBase->getMemorySpace(); + const MemSpaceRegion *RightMS = RightBase->getMemorySpace(); + const MemSpaceRegion *UnknownMS = MemMgr.getUnknownRegion(); // If the two regions are from different known memory spaces they cannot be // equal. Also, assume that no symbolic region (whose memory space is @@ -789,7 +767,6 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state, } // If we get here, we have no way of comparing the ElementRegions. - return UnknownVal(); } // See if both regions are fields of the same structure. @@ -842,6 +819,13 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state, llvm_unreachable("Fields not found in parent record's definition"); } + // At this point we're not going to get a good answer, but we can try + // conjuring an expression instead. + SymbolRef LHSSym = lhs.getAsLocSymbol(); + SymbolRef RHSSym = rhs.getAsLocSymbol(); + if (LHSSym && RHSSym) + return makeNonLoc(LHSSym, op, RHSSym, resultTy); + // If we get here, we have no way of comparing the regions. return UnknownVal(); } diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp index a0c24fedcf..690ed08ffc 100644 --- a/lib/StaticAnalyzer/Core/Store.cpp +++ b/lib/StaticAnalyzer/Core/Store.cpp @@ -289,62 +289,82 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType, return loc::MemRegionVal(BaseReg); } -SVal StoreManager::evalDynamicCast(SVal Base, QualType DerivedType, +/// Returns the static type of the given region, if it represents a C++ class +/// object. +/// +/// This handles both fully-typed regions, where the dynamic type is known, and +/// symbolic regions, where the dynamic type is merely bounded (and even then, +/// only ostensibly!), but does not take advantage of any dynamic type info. +static const CXXRecordDecl *getCXXRecordType(const MemRegion *MR) { + if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR)) + return TVR->getValueType()->getAsCXXRecordDecl(); + if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) + return SR->getSymbol()->getType()->getPointeeCXXRecordDecl(); + return 0; +} + +SVal StoreManager::evalDynamicCast(SVal Base, QualType TargetType, bool &Failed) { Failed = false; - Optional<loc::MemRegionVal> BaseRegVal = Base.getAs<loc::MemRegionVal>(); - if (!BaseRegVal) + const MemRegion *MR = Base.getAsRegion(); + if (!MR) return UnknownVal(); - const MemRegion *BaseRegion = BaseRegVal->stripCasts(/*StripBases=*/false); // Assume the derived class is a pointer or a reference to a CXX record. - DerivedType = DerivedType->getPointeeType(); - assert(!DerivedType.isNull()); - const CXXRecordDecl *DerivedDecl = DerivedType->getAsCXXRecordDecl(); - if (!DerivedDecl && !DerivedType->isVoidType()) + TargetType = TargetType->getPointeeType(); + assert(!TargetType.isNull()); + const CXXRecordDecl *TargetClass = TargetType->getAsCXXRecordDecl(); + if (!TargetClass && !TargetType->isVoidType()) return UnknownVal(); // Drill down the CXXBaseObject chains, which represent upcasts (casts from // derived to base). - const MemRegion *SR = BaseRegion; - while (const TypedRegion *TSR = dyn_cast_or_null<TypedRegion>(SR)) { - QualType BaseType = TSR->getLocationType()->getPointeeType(); - assert(!BaseType.isNull()); - const CXXRecordDecl *SRDecl = BaseType->getAsCXXRecordDecl(); - if (!SRDecl) - return UnknownVal(); - + while (const CXXRecordDecl *MRClass = getCXXRecordType(MR)) { // If found the derived class, the cast succeeds. - if (SRDecl == DerivedDecl) - return loc::MemRegionVal(TSR); + if (MRClass == TargetClass) + return loc::MemRegionVal(MR); - if (!DerivedType->isVoidType()) { + if (!TargetType->isVoidType()) { // Static upcasts are marked as DerivedToBase casts by Sema, so this will // only happen when multiple or virtual inheritance is involved. CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (SRDecl->isDerivedFrom(DerivedDecl, Paths)) - return evalDerivedToBase(loc::MemRegionVal(TSR), Paths.front()); + if (MRClass->isDerivedFrom(TargetClass, Paths)) + return evalDerivedToBase(loc::MemRegionVal(MR), Paths.front()); } - if (const CXXBaseObjectRegion *R = dyn_cast<CXXBaseObjectRegion>(TSR)) + if (const CXXBaseObjectRegion *BaseR = dyn_cast<CXXBaseObjectRegion>(MR)) { // Drill down the chain to get the derived classes. - SR = R->getSuperRegion(); - else { - // We reached the bottom of the hierarchy. - - // If this is a cast to void*, return the region. - if (DerivedType->isVoidType()) - return loc::MemRegionVal(TSR); + MR = BaseR->getSuperRegion(); + continue; + } - // We did not find the derived class. We we must be casting the base to - // derived, so the cast should fail. - Failed = true; - return UnknownVal(); + // If this is a cast to void*, return the region. + if (TargetType->isVoidType()) + return loc::MemRegionVal(MR); + + // Strange use of reinterpret_cast can give us paths we don't reason + // about well, by putting in ElementRegions where we'd expect + // CXXBaseObjectRegions. If it's a valid reinterpret_cast (i.e. if the + // derived class has a zero offset from the base class), then it's safe + // to strip the cast; if it's invalid, -Wreinterpret-base-class should + // catch it. In the interest of performance, the analyzer will silently + // do the wrong thing in the invalid case (because offsets for subregions + // will be wrong). + const MemRegion *Uncasted = MR->StripCasts(/*IncludeBaseCasts=*/false); + if (Uncasted == MR) { + // We reached the bottom of the hierarchy and did not find the derived + // class. We we must be casting the base to derived, so the cast should + // fail. + break; } + + MR = Uncasted; } - + + // We failed if the region we ended up with has perfect type info. + Failed = isa<TypedValueRegion>(MR); return UnknownVal(); } diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp index 0c5098b1e7..7c75b6c3d2 100644 --- a/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -27,52 +27,33 @@ void SymExpr::dump() const { dumpToStream(llvm::errs()); } -static void print(raw_ostream &os, BinaryOperator::Opcode Op) { - switch (Op) { - default: - llvm_unreachable("operator printing not implemented"); - case BO_Mul: os << '*' ; break; - case BO_Div: os << '/' ; break; - case BO_Rem: os << '%' ; break; - case BO_Add: os << '+' ; break; - case BO_Sub: os << '-' ; break; - case BO_Shl: os << "<<" ; break; - case BO_Shr: os << ">>" ; break; - case BO_LT: os << "<" ; break; - case BO_GT: os << '>' ; break; - case BO_LE: os << "<=" ; break; - case BO_GE: os << ">=" ; break; - case BO_EQ: os << "==" ; break; - case BO_NE: os << "!=" ; break; - case BO_And: os << '&' ; break; - case BO_Xor: os << '^' ; break; - case BO_Or: os << '|' ; break; - } -} - void SymIntExpr::dumpToStream(raw_ostream &os) const { os << '('; getLHS()->dumpToStream(os); - os << ") "; - print(os, getOpcode()); - os << ' ' << getRHS().getZExtValue(); - if (getRHS().isUnsigned()) os << 'U'; + os << ") " + << BinaryOperator::getOpcodeStr(getOpcode()) << ' ' + << getRHS().getZExtValue(); + if (getRHS().isUnsigned()) + os << 'U'; } void IntSymExpr::dumpToStream(raw_ostream &os) const { - os << ' ' << getLHS().getZExtValue(); - if (getLHS().isUnsigned()) os << 'U'; - print(os, getOpcode()); - os << '('; + os << getLHS().getZExtValue(); + if (getLHS().isUnsigned()) + os << 'U'; + os << ' ' + << BinaryOperator::getOpcodeStr(getOpcode()) + << " ("; getRHS()->dumpToStream(os); - os << ") "; + os << ')'; } void SymSymExpr::dumpToStream(raw_ostream &os) const { os << '('; getLHS()->dumpToStream(os); - os << ") "; - os << '('; + os << ") " + << BinaryOperator::getOpcodeStr(getOpcode()) + << " ("; getRHS()->dumpToStream(os); os << ')'; } @@ -359,8 +340,8 @@ bool SymbolManager::canSymbolicate(QualType T) { if (Loc::isLocType(T)) return true; - if (T->isIntegerType()) - return T->isScalarType(); + if (T->isIntegralOrEnumerationType()) + return true; if (T->isRecordType() && !T->isUnionType()) return true; @@ -468,9 +449,7 @@ bool SymbolReaper::isLive(SymbolRef sym) { switch (sym->getKind()) { case SymExpr::RegionValueKind: - // FIXME: We should be able to use isLiveRegion here (this behavior - // predates isLiveRegion), but doing so causes test failures. Investigate. - KnownLive = true; + KnownLive = isLiveRegion(cast<SymbolRegionValue>(sym)->getRegion()); break; case SymExpr::ConjuredKind: KnownLive = false; diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index f3d545a026..d71e528848 100644 --- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -234,11 +234,11 @@ public: else if (Mode == AM_Path) { llvm::errs() << " (Path, "; switch (IMode) { - case ExprEngine::Inline_None: - llvm::errs() << " Inline_None"; + case ExprEngine::Inline_Minimal: + llvm::errs() << " Inline_Minimal"; break; - case ExprEngine::Inline_All: - llvm::errs() << " Inline_All"; + case ExprEngine::Inline_Regular: + llvm::errs() << " Inline_Regular"; break; } llvm::errs() << ")"; @@ -284,7 +284,8 @@ public: virtual void HandleTranslationUnit(ASTContext &C); /// \brief Determine which inlining mode should be used when this function is - /// analyzed. For example, determines if the callees should be inlined. + /// analyzed. This allows to redefine the default inlining policies when + /// analyzing a given function. ExprEngine::InliningModes getInliningModeForFunction(const Decl *D, SetOfConstDecls Visited); @@ -299,7 +300,7 @@ public: /// set of functions which should be considered analyzed after analyzing the /// given root function. void HandleCode(Decl *D, AnalysisMode Mode, - ExprEngine::InliningModes IMode = ExprEngine::Inline_None, + ExprEngine::InliningModes IMode = ExprEngine::Inline_Minimal, SetOfConstDecls *VisitedCallees = 0); void RunPathSensitiveChecks(Decl *D, @@ -410,22 +411,18 @@ static bool shouldSkipFunction(const Decl *D, ExprEngine::InliningModes AnalysisConsumer::getInliningModeForFunction(const Decl *D, SetOfConstDecls Visited) { - ExprEngine::InliningModes HowToInline = - (Mgr->shouldInlineCall()) ? ExprEngine::Inline_All : - ExprEngine::Inline_None; - // We want to reanalyze all ObjC methods as top level to report Retain - // Count naming convention errors more aggressively. But we can turn off + // Count naming convention errors more aggressively. But we should tune down // inlining when reanalyzing an already inlined function. if (Visited.count(D)) { assert(isa<ObjCMethodDecl>(D) && "We are only reanalyzing ObjCMethods."); const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D); if (ObjCM->getMethodFamily() != OMF_init) - HowToInline = ExprEngine::Inline_None; + return ExprEngine::Inline_Minimal; } - return HowToInline; + return ExprEngine::Inline_Regular; } void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) { @@ -595,7 +592,7 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, checkerMgr->runCheckersOnASTBody(D, *Mgr, BR); if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) { RunPathSensitiveChecks(D, IMode, VisitedCallees); - if (IMode != ExprEngine::Inline_None) + if (IMode != ExprEngine::Inline_Minimal) NumFunctionsAnalyzed++; } } diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp index 4fad5a8a7c..e7def08819 100644 --- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -100,11 +100,12 @@ void ClangCheckerRegistry::warnIncompatible(DiagnosticsEngine *diags, } -CheckerManager *ento::createCheckerManager(const AnalyzerOptions &opts, +CheckerManager *ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, ArrayRef<std::string> plugins, DiagnosticsEngine &diags) { - OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts)); + OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts, + &opts)); SmallVector<CheckerOptInfo, 8> checkerOpts; for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) { diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp index a9e7b84808..52855f657f 100644 --- a/lib/Tooling/Tooling.cpp +++ b/lib/Tooling/Tooling.cpp @@ -22,6 +22,7 @@ #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CompilationDatabase.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" #include "llvm/Support/raw_ostream.h" @@ -295,14 +296,19 @@ int ClangTool::run(FrontendActionFactory *ActionFactory) { ArgsAdjuster->Adjust(CompileCommands[I].second.CommandLine); assert(!CommandLine.empty()); CommandLine[0] = MainExecutable; - llvm::outs() << "Processing: " << File << ".\n"; + // FIXME: We need a callback mechanism for the tool writer to output a + // customized message for each file. + DEBUG({ + llvm::dbgs() << "Processing: " << File << ".\n"; + }); ToolInvocation Invocation(CommandLine, ActionFactory->create(), &Files); for (int I = 0, E = MappedFileContents.size(); I != E; ++I) { Invocation.mapVirtualFile(MappedFileContents[I].first, MappedFileContents[I].second); } if (!Invocation.run()) { - llvm::outs() << "Error while processing " << File << ".\n"; + // FIXME: Diagnostics should be used instead. + llvm::errs() << "Error while processing " << File << ".\n"; ProcessingFailed = true; } } |