diff options
Diffstat (limited to 'lib')
81 files changed, 3073 insertions, 890 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index fabfdc9ef7e5..a2ff176df11f 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5990,9 +5990,19 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S, // compatibility with GCC, although providing it breaks anything that // actually uses runtime introspection and wants to work on both runtimes... if (Ctx->getLangOpts().ObjCRuntime.isGNUFamily()) { - const RecordDecl *RD = FD->getParent(); - const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD); - S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex())); + uint64_t Offset; + + if (const auto *IVD = dyn_cast<ObjCIvarDecl>(FD)) { + Offset = Ctx->lookupFieldBitOffset(IVD->getContainingInterface(), nullptr, + IVD); + } else { + const RecordDecl *RD = FD->getParent(); + const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD); + Offset = RL.getFieldOffset(FD->getFieldIndex()); + } + + S += llvm::utostr(Offset); + if (const EnumType *ET = T->getAs<EnumType>()) S += ObjCEncodingForEnumType(Ctx, ET); else { diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp index eff1aa5e323d..ea7faab767ed 100644 --- a/lib/AST/ASTStructuralEquivalence.cpp +++ b/lib/AST/ASTStructuralEquivalence.cpp @@ -735,13 +735,28 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // Check for equivalent field names. IdentifierInfo *Name1 = Field1->getIdentifier(); IdentifierInfo *Name2 = Field2->getIdentifier(); - if (!::IsStructurallyEquivalent(Name1, Name2)) + if (!::IsStructurallyEquivalent(Name1, Name2)) { + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), + Context.ErrorOnTagTypeMismatch + ? diag::err_odr_tag_type_inconsistent + : diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(Owner2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field_name) + << Field2->getDeclName(); + Context.Diag1(Field1->getLocation(), diag::note_odr_field_name) + << Field1->getDeclName(); + } return false; + } if (!IsStructurallyEquivalent(Context, Field1->getType(), Field2->getType())) { if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + Context.Diag2(Owner2->getLocation(), + Context.ErrorOnTagTypeMismatch + ? diag::err_odr_tag_type_inconsistent + : diag::warn_odr_tag_type_inconsistent) << Context.ToCtx.getTypeDeclType(Owner2); Context.Diag2(Field2->getLocation(), diag::note_odr_field) << Field2->getDeclName() << Field2->getType(); @@ -753,7 +768,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Field1->isBitField() != Field2->isBitField()) { if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + Context.Diag2(Owner2->getLocation(), + Context.ErrorOnTagTypeMismatch + ? diag::err_odr_tag_type_inconsistent + : diag::warn_odr_tag_type_inconsistent) << Context.ToCtx.getTypeDeclType(Owner2); if (Field1->isBitField()) { Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) @@ -780,7 +798,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Bits1 != Bits2) { if (Context.Complain) { Context.Diag2(Owner2->getLocation(), - diag::warn_odr_tag_type_inconsistent) + Context.ErrorOnTagTypeMismatch + ? diag::err_odr_tag_type_inconsistent + : diag::warn_odr_tag_type_inconsistent) << Context.ToCtx.getTypeDeclType(Owner2); Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) << Field2->getDeclName() << Field2->getType() << Bits2; @@ -799,7 +819,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D1, RecordDecl *D2) { if (D1->isUnion() != D2->isUnion()) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), + Context.ErrorOnTagTypeMismatch + ? diag::err_odr_tag_type_inconsistent + : diag::warn_odr_tag_type_inconsistent) << Context.ToCtx.getTypeDeclType(D2); Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) << D1->getDeclName() << (unsigned)D1->getTagKind(); @@ -927,7 +950,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Field1 != Field1End; ++Field1, ++Field2) { if (Field2 == Field2End) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), + Context.ErrorOnTagTypeMismatch + ? diag::err_odr_tag_type_inconsistent + : diag::warn_odr_tag_type_inconsistent) << Context.ToCtx.getTypeDeclType(D2); Context.Diag1(Field1->getLocation(), diag::note_odr_field) << Field1->getDeclName() << Field1->getType(); @@ -942,7 +968,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Field2 != Field2End) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), + Context.ErrorOnTagTypeMismatch + ? diag::err_odr_tag_type_inconsistent + : diag::warn_odr_tag_type_inconsistent) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(Field2->getLocation(), diag::note_odr_field) << Field2->getDeclName() << Field2->getType(); @@ -964,7 +993,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, EC1 != EC1End; ++EC1, ++EC2) { if (EC2 == EC2End) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), + Context.ErrorOnTagTypeMismatch + ? diag::err_odr_tag_type_inconsistent + : diag::warn_odr_tag_type_inconsistent) << Context.ToCtx.getTypeDeclType(D2); Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) << EC1->getDeclName() << EC1->getInitVal().toString(10); @@ -978,7 +1010,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!llvm::APSInt::isSameValue(Val1, Val2) || !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), + Context.ErrorOnTagTypeMismatch + ? diag::err_odr_tag_type_inconsistent + : diag::warn_odr_tag_type_inconsistent) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) << EC2->getDeclName() << EC2->getInitVal().toString(10); @@ -991,7 +1026,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (EC2 != EC2End) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), + Context.ErrorOnTagTypeMismatch + ? diag::err_odr_tag_type_inconsistent + : diag::warn_odr_tag_type_inconsistent) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) << EC2->getDeclName() << EC2->getInitVal().toString(10); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 9862f4f26473..267c6992af89 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1251,7 +1251,9 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, case Decl::EnumConstant: // C++ [basic.link]p4: an enumerator has the linkage of its enumeration. - return getLVForDecl(cast<EnumDecl>(D->getDeclContext()), computation); + if (D->getASTContext().getLangOpts().CPlusPlus) + return getLVForDecl(cast<EnumDecl>(D->getDeclContext()), computation); + return LinkageInfo::visible_none(); case Decl::Typedef: case Decl::TypeAlias: @@ -2630,7 +2632,7 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const { return (proto->getParamType(1).getCanonicalType() == Context.VoidPtrTy); } -bool FunctionDecl::isReplaceableGlobalAllocationFunction() const { +bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const { if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName) return false; if (getDeclName().getCXXOverloadedOperator() != OO_New && @@ -2676,8 +2678,11 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const { // In C++17, the next parameter can be a 'std::align_val_t' for aligned // new/delete. - if (Ctx.getLangOpts().AlignedAllocation && !Ty.isNull() && Ty->isAlignValT()) + if (Ctx.getLangOpts().AlignedAllocation && !Ty.isNull() && Ty->isAlignValT()) { + if (IsAligned) + *IsAligned = true; Consume(); + } // Finally, if this is not a sized delete, the final parameter can // be a 'const std::nothrow_t&'. diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 9f87fe12a9cd..07d128ba555b 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1417,11 +1417,8 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const { Context.getCanonicalType(ClassType)); DeclContext::lookup_result R = lookup(Name); - if (R.empty()) - return nullptr; - CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(R.front()); - return Dtor; + return R.empty() ? nullptr : dyn_cast<CXXDestructorDecl>(R.front()); } bool CXXRecordDecl::isAnyDestructorNoReturn() const { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index c21cd3f65bd4..afc7fa8ea094 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1641,25 +1641,32 @@ const char *CastExpr::getCastKindName() const { llvm_unreachable("Unhandled cast kind!"); } +namespace { + Expr *skipImplicitTemporary(Expr *expr) { + // Skip through reference binding to temporary. + if (MaterializeTemporaryExpr *Materialize + = dyn_cast<MaterializeTemporaryExpr>(expr)) + expr = Materialize->GetTemporaryExpr(); + + // Skip any temporary bindings; they're implicit. + if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(expr)) + expr = Binder->getSubExpr(); + + return expr; + } +} + Expr *CastExpr::getSubExprAsWritten() { Expr *SubExpr = nullptr; CastExpr *E = this; do { - SubExpr = E->getSubExpr(); + SubExpr = skipImplicitTemporary(E->getSubExpr()); - // Skip through reference binding to temporary. - if (MaterializeTemporaryExpr *Materialize - = dyn_cast<MaterializeTemporaryExpr>(SubExpr)) - SubExpr = Materialize->GetTemporaryExpr(); - - // Skip any temporary bindings; they're implicit. - if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(SubExpr)) - SubExpr = Binder->getSubExpr(); - // Conversions by constructor and conversion functions have a // subexpression describing the call; strip it off. if (E->getCastKind() == CK_ConstructorConversion) - SubExpr = cast<CXXConstructExpr>(SubExpr)->getArg(0); + SubExpr = + skipImplicitTemporary(cast<CXXConstructExpr>(SubExpr)->getArg(0)); else if (E->getCastKind() == CK_UserDefinedConversion) { assert((isa<CXXMemberCallExpr>(SubExpr) || isa<BlockExpr>(SubExpr)) && diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 768947d00ac4..e836135cf2f9 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -6226,10 +6226,6 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // the initializer list. ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType()); const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE; - if (Init->isValueDependent()) { - Success = false; - continue; - } // Temporarily override This, in case there's a CXXDefaultInitExpr in here. ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, @@ -9940,8 +9936,7 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) { } static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, - const ASTContext &Ctx, bool &IsConst, - bool IsCheckingForOverflow) { + const ASTContext &Ctx, bool &IsConst) { // Fast-path evaluations of integer literals, since we sometimes see files // containing vast quantities of these. if (const IntegerLiteral *L = dyn_cast<IntegerLiteral>(Exp)) { @@ -9962,7 +9957,7 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, // performance problems. Only do so in C++11 for now. if (Exp->isRValue() && (Exp->getType()->isArrayType() || Exp->getType()->isRecordType()) && - !Ctx.getLangOpts().CPlusPlus11 && !IsCheckingForOverflow) { + !Ctx.getLangOpts().CPlusPlus11) { IsConst = false; return true; } @@ -9977,7 +9972,7 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, /// will be applied to the result. bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const { bool IsConst; - if (FastEvaluateAsRValue(this, Result, Ctx, IsConst, false)) + if (FastEvaluateAsRValue(this, Result, Ctx, IsConst)) return IsConst; EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); @@ -10102,7 +10097,7 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx, void Expr::EvaluateForOverflow(const ASTContext &Ctx) const { bool IsConst; EvalResult EvalResult; - if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst, true)) { + if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst)) { EvalInfo Info(Ctx, EvalResult, EvalInfo::EM_EvaluateForOverflow); (void)::EvaluateAsRValue(Info, this, EvalResult.Val); } diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index cc7a6941f63a..3a899bdbb6d2 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -966,16 +966,71 @@ void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) { } if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = - Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle a local inside this block yet"); - Diags.Report(BD->getLocation(), DiagID); - - // FIXME: This is completely, utterly, wrong; see ItaniumMangle - // for how this should be done. - Out << "__block_invoke" << Context.getBlockId(BD, false); - Out << '@'; + auto Discriminate = + [](StringRef Name, const unsigned Discriminator, + const unsigned ParameterDiscriminator) -> std::string { + std::string Buffer; + llvm::raw_string_ostream Stream(Buffer); + Stream << Name; + if (Discriminator) + Stream << '_' << Discriminator; + if (ParameterDiscriminator) + Stream << '_' << ParameterDiscriminator; + return Stream.str(); + }; + + unsigned Discriminator = BD->getBlockManglingNumber(); + if (!Discriminator) + Discriminator = Context.getBlockId(BD, /*Local=*/false); + + // Mangle the parameter position as a discriminator to deal with unnamed + // parameters. Rather than mangling the unqualified parameter name, + // always use the position to give a uniform mangling. + unsigned ParameterDiscriminator = 0; + if (const auto *MC = BD->getBlockManglingContextDecl()) + if (const auto *P = dyn_cast<ParmVarDecl>(MC)) + if (const auto *F = dyn_cast<FunctionDecl>(P->getDeclContext())) + ParameterDiscriminator = + F->getNumParams() - P->getFunctionScopeIndex(); + + DC = getEffectiveDeclContext(BD); + + Out << '?'; + mangleSourceName(Discriminate("_block_invoke", Discriminator, + ParameterDiscriminator)); + // If we have a block mangling context, encode that now. This allows us + // to discriminate between named static data initializers in the same + // scope. This is handled differently from parameters, which use + // positions to discriminate between multiple instances. + if (const auto *MC = BD->getBlockManglingContextDecl()) + if (!isa<ParmVarDecl>(MC)) + if (const auto *ND = dyn_cast<NamedDecl>(MC)) + mangleUnqualifiedName(ND); + // MS ABI and Itanium manglings are in inverted scopes. In the case of a + // RecordDecl, mangle the entire scope hierachy at this point rather than + // just the unqualified name to get the ordering correct. + if (const auto *RD = dyn_cast<RecordDecl>(DC)) + mangleName(RD); + else + Out << '@'; + // void __cdecl + Out << "YAX"; + // struct __block_literal * + Out << 'P'; + // __ptr64 + if (PointersAre64Bit) + Out << 'E'; + Out << 'A'; + mangleArtificalTagType(TTK_Struct, + Discriminate("__block_literal", Discriminator, + ParameterDiscriminator)); + Out << "@Z"; + + // If the effective context was a Record, we have fully mangled the + // qualified name and do not need to continue. + if (isa<RecordDecl>(DC)) + break; + continue; } else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) { mangleObjCMethodName(Method); } else if (isa<NamedDecl>(DC)) { diff --git a/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp index 05bed658f3fc..3f66e58eb868 100644 --- a/lib/AST/ODRHash.cpp +++ b/lib/AST/ODRHash.cpp @@ -82,25 +82,13 @@ void ODRHash::AddDeclarationName(DeclarationName Name) { } void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { - // Unlike the other pointer handling functions, allow null pointers here. - if (!NNS) { - AddBoolean(false); - return; + assert(NNS && "Expecting non-null pointer."); + const auto *Prefix = NNS->getPrefix(); + AddBoolean(Prefix); + if (Prefix) { + AddNestedNameSpecifier(Prefix); } - - // Skip inlined namespaces. auto Kind = NNS->getKind(); - if (Kind == NestedNameSpecifier::Namespace) { - if (NNS->getAsNamespace()->isInline()) { - return AddNestedNameSpecifier(NNS->getPrefix()); - } - } - - AddBoolean(true); - - // Process prefix - AddNestedNameSpecifier(NNS->getPrefix()); - ID.AddInteger(Kind); switch (Kind) { case NestedNameSpecifier::Identifier: @@ -146,7 +134,10 @@ void ODRHash::AddTemplateArgument(TemplateArgument TA) { switch (Kind) { case TemplateArgument::Null: + llvm_unreachable("Expected valid TemplateArgument"); case TemplateArgument::Type: + AddQualType(TA.getAsType()); + break; case TemplateArgument::Declaration: case TemplateArgument::NullPtr: case TemplateArgument::Integral: @@ -430,8 +421,18 @@ public: Hash.AddQualType(T); } + void AddType(const Type *T) { + Hash.AddBoolean(T); + if (T) { + Hash.AddType(T); + } + } + void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { - Hash.AddNestedNameSpecifier(NNS); + Hash.AddBoolean(NNS); + if (NNS) { + Hash.AddNestedNameSpecifier(NNS); + } } void AddIdentifierInfo(const IdentifierInfo *II) { @@ -517,7 +518,13 @@ public: void VisitTypedefType(const TypedefType *T) { AddDecl(T->getDecl()); - AddQualType(T->getDecl()->getUnderlyingType().getCanonicalType()); + QualType UnderlyingType = T->getDecl()->getUnderlyingType(); + VisitQualifiers(UnderlyingType.getQualifiers()); + while (const TypedefType *Underlying = + dyn_cast<TypedefType>(UnderlyingType.getTypePtr())) { + UnderlyingType = Underlying->getDecl()->getUnderlyingType(); + } + AddType(UnderlyingType.getTypePtr()); VisitType(T); } diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index cf981be0a4dd..c0b9cadca422 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -3073,6 +3073,41 @@ uint64_t ASTContext::getFieldOffset(const ValueDecl *VD) const { return OffsetInBits; } +uint64_t ASTContext::lookupFieldBitOffset(const ObjCInterfaceDecl *OID, + const ObjCImplementationDecl *ID, + const ObjCIvarDecl *Ivar) const { + const ObjCInterfaceDecl *Container = Ivar->getContainingInterface(); + + // FIXME: We should eliminate the need to have ObjCImplementationDecl passed + // in here; it should never be necessary because that should be the lexical + // decl context for the ivar. + + // If we know have an implementation (and the ivar is in it) then + // look up in the implementation layout. + const ASTRecordLayout *RL; + if (ID && declaresSameEntity(ID->getClassInterface(), Container)) + RL = &getASTObjCImplementationLayout(ID); + else + RL = &getASTObjCInterfaceLayout(Container); + + // Compute field index. + // + // FIXME: The index here is closely tied to how ASTContext::getObjCLayout is + // implemented. This should be fixed to get the information from the layout + // directly. + unsigned Index = 0; + + for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin(); + IVD; IVD = IVD->getNextIvar()) { + if (Ivar == IVD) + break; + ++Index; + } + assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!"); + + return RL->getFieldOffset(Index); +} + /// getObjCLayout - Get or compute information about the layout of the /// given interface. /// diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 99a25f342526..f1fbe2806b5d 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -186,7 +186,10 @@ namespace { Hash.AddTemplateName(Name); } void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override { - Hash.AddNestedNameSpecifier(NNS); + ID.AddBoolean(NNS); + if (NNS) { + Hash.AddNestedNameSpecifier(NNS); + } } }; } diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp index a58d0465a6f4..89ddbc946a49 100644 --- a/lib/Basic/SourceLocation.cpp +++ b/lib/Basic/SourceLocation.cpp @@ -92,6 +92,76 @@ FullSourceLoc FullSourceLoc::getSpellingLoc() const { return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr); } +FullSourceLoc FullSourceLoc::getFileLoc() const { + assert(isValid()); + return FullSourceLoc(SrcMgr->getFileLoc(*this), *SrcMgr); +} + +std::pair<FullSourceLoc, FullSourceLoc> +FullSourceLoc::getImmediateExpansionRange() const { + assert(isValid()); + std::pair<SourceLocation, SourceLocation> Range = + SrcMgr->getImmediateExpansionRange(*this); + return std::make_pair(FullSourceLoc(Range.first, *SrcMgr), + FullSourceLoc(Range.second, *SrcMgr)); +} + +PresumedLoc FullSourceLoc::getPresumedLoc(bool UseLineDirectives) const { + if (!isValid()) + return PresumedLoc(); + + return SrcMgr->getPresumedLoc(*this, UseLineDirectives); +} + +bool FullSourceLoc::isMacroArgExpansion(FullSourceLoc *StartLoc) const { + assert(isValid()); + return SrcMgr->isMacroArgExpansion(*this, StartLoc); +} + +FullSourceLoc FullSourceLoc::getImmediateMacroCallerLoc() const { + assert(isValid()); + return FullSourceLoc(SrcMgr->getImmediateMacroCallerLoc(*this), *SrcMgr); +} + +std::pair<FullSourceLoc, StringRef> FullSourceLoc::getModuleImportLoc() const { + if (!isValid()) + return std::make_pair(FullSourceLoc(), StringRef()); + + std::pair<SourceLocation, StringRef> ImportLoc = + SrcMgr->getModuleImportLoc(*this); + return std::make_pair(FullSourceLoc(ImportLoc.first, *SrcMgr), + ImportLoc.second); +} + +unsigned FullSourceLoc::getFileOffset() const { + assert(isValid()); + return SrcMgr->getFileOffset(*this); +} + +unsigned FullSourceLoc::getLineNumber(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getLineNumber(getFileID(), getFileOffset(), Invalid); +} + +unsigned FullSourceLoc::getColumnNumber(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getColumnNumber(getFileID(), getFileOffset(), Invalid); +} + +std::pair<FullSourceLoc, FullSourceLoc> +FullSourceLoc::getExpansionRange() const { + assert(isValid()); + std::pair<SourceLocation, SourceLocation> Range = + SrcMgr->getExpansionRange(*this); + return std::make_pair(FullSourceLoc(Range.first, *SrcMgr), + FullSourceLoc(Range.second, *SrcMgr)); +} + +const FileEntry *FullSourceLoc::getFileEntry() const { + assert(isValid()); + return SrcMgr->getFileEntryForID(getFileID()); +} + unsigned FullSourceLoc::getExpansionLineNumber(bool *Invalid) const { assert(isValid()); return SrcMgr->getExpansionLineNumber(*this, Invalid); diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 3936afab21a4..f0b53b4e48a5 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -2018,9 +2018,51 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, if (LOffs.first.isInvalid() || ROffs.first.isInvalid()) return LOffs.first.isInvalid() && !ROffs.first.isInvalid(); + std::pair<bool, bool> InSameTU = isInTheSameTranslationUnit(LOffs, ROffs); + if (InSameTU.first) + return InSameTU.second; + + // If we arrived here, the location is either in a built-ins buffer or + // associated with global inline asm. PR5662 and PR22576 are examples. + + StringRef LB = getBuffer(LOffs.first)->getBufferIdentifier(); + StringRef RB = getBuffer(ROffs.first)->getBufferIdentifier(); + bool LIsBuiltins = LB == "<built-in>"; + bool RIsBuiltins = RB == "<built-in>"; + // Sort built-in before non-built-in. + if (LIsBuiltins || RIsBuiltins) { + if (LIsBuiltins != RIsBuiltins) + return LIsBuiltins; + // Both are in built-in buffers, but from different files. We just claim that + // lower IDs come first. + return LOffs.first < ROffs.first; + } + bool LIsAsm = LB == "<inline asm>"; + bool RIsAsm = RB == "<inline asm>"; + // Sort assembler after built-ins, but before the rest. + if (LIsAsm || RIsAsm) { + if (LIsAsm != RIsAsm) + return RIsAsm; + assert(LOffs.first == ROffs.first); + return false; + } + bool LIsScratch = LB == "<scratch space>"; + bool RIsScratch = RB == "<scratch space>"; + // Sort scratch after inline asm, but before the rest. + if (LIsScratch || RIsScratch) { + if (LIsScratch != RIsScratch) + return LIsScratch; + return LOffs.second < ROffs.second; + } + llvm_unreachable("Unsortable locations found"); +} + +std::pair<bool, bool> SourceManager::isInTheSameTranslationUnit( + std::pair<FileID, unsigned> &LOffs, + std::pair<FileID, unsigned> &ROffs) const { // If the source locations are in the same file, just compare offsets. if (LOffs.first == ROffs.first) - return LOffs.second < ROffs.second; + return std::make_pair(true, LOffs.second < ROffs.second); // If we are comparing a source location with multiple locations in the same // file, we get a big win by caching the result. @@ -2030,7 +2072,8 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, // If we are comparing a source location with multiple locations in the same // file, we get a big win by caching the result. if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first)) - return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second); + return std::make_pair( + true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second)); // Okay, we missed in the cache, start updating the cache for this query. IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first, @@ -2060,44 +2103,12 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, // locations within the common file and cache them. if (LOffs.first == ROffs.first) { IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second); - return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second); + return std::make_pair( + true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second)); } - - // If we arrived here, the location is either in a built-ins buffer or - // associated with global inline asm. PR5662 and PR22576 are examples. - // Clear the lookup cache, it depends on a common location. IsBeforeInTUCache.clear(); - StringRef LB = getBuffer(LOffs.first)->getBufferIdentifier(); - StringRef RB = getBuffer(ROffs.first)->getBufferIdentifier(); - bool LIsBuiltins = LB == "<built-in>"; - bool RIsBuiltins = RB == "<built-in>"; - // Sort built-in before non-built-in. - if (LIsBuiltins || RIsBuiltins) { - if (LIsBuiltins != RIsBuiltins) - return LIsBuiltins; - // Both are in built-in buffers, but from different files. We just claim that - // lower IDs come first. - return LOffs.first < ROffs.first; - } - bool LIsAsm = LB == "<inline asm>"; - bool RIsAsm = RB == "<inline asm>"; - // Sort assembler after built-ins, but before the rest. - if (LIsAsm || RIsAsm) { - if (LIsAsm != RIsAsm) - return RIsAsm; - assert(LOffs.first == ROffs.first); - return false; - } - bool LIsScratch = LB == "<scratch space>"; - bool RIsScratch = RB == "<scratch space>"; - // Sort scratch after inline asm, but before the rest. - if (LIsScratch || RIsScratch) { - if (LIsScratch != RIsScratch) - return LIsScratch; - return LOffs.second < ROffs.second; - } - llvm_unreachable("Unsortable locations found"); + return std::make_pair(false, false); } void SourceManager::PrintStats() const { diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index c5af99e4b6af..4f04489a4a10 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -2706,7 +2706,7 @@ class X86TargetInfo : public TargetInfo { CK_C3_2, /// This enumerator is a bit odd, as GCC no longer accepts -march=yonah. - /// Clang however has some logic to suport this. + /// Clang however has some logic to support this. // FIXME: Warn, deprecate, and potentially remove this. CK_Yonah, //@} @@ -2737,6 +2737,7 @@ class X86TargetInfo : public TargetInfo { //@{ CK_Bonnell, CK_Silvermont, + CK_Goldmont, //@} /// \name Nehalem @@ -2878,6 +2879,7 @@ class X86TargetInfo : public TargetInfo { .Case("atom", CK_Bonnell) // Legacy name. .Case("silvermont", CK_Silvermont) .Case("slm", CK_Silvermont) // Legacy name. + .Case("goldmont", CK_Goldmont) .Case("nehalem", CK_Nehalem) .Case("corei7", CK_Nehalem) // Legacy name. .Case("westmere", CK_Westmere) @@ -3093,6 +3095,7 @@ public: case CK_Penryn: case CK_Bonnell: case CK_Silvermont: + case CK_Goldmont: case CK_Nehalem: case CK_Westmere: case CK_SandyBridge: @@ -3221,7 +3224,6 @@ bool X86TargetInfo::initFeatureMap( setFeatureEnabledImpl(Features, "cx16", true); break; case CK_Core2: - case CK_Bonnell: setFeatureEnabledImpl(Features, "ssse3", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); @@ -3276,7 +3278,6 @@ bool X86TargetInfo::initFeatureMap( setFeatureEnabledImpl(Features, "xsaveopt", true); LLVM_FALLTHROUGH; case CK_Westmere: - case CK_Silvermont: setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); LLVM_FALLTHROUGH; @@ -3285,6 +3286,28 @@ bool X86TargetInfo::initFeatureMap( setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; + case CK_Goldmont: + setFeatureEnabledImpl(Features, "sha", true); + setFeatureEnabledImpl(Features, "rdrnd", true); + setFeatureEnabledImpl(Features, "rdseed", true); + setFeatureEnabledImpl(Features, "xsave", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + setFeatureEnabledImpl(Features, "xsavec", true); + setFeatureEnabledImpl(Features, "xsaves", true); + setFeatureEnabledImpl(Features, "clflushopt", true); + setFeatureEnabledImpl(Features, "mpx", true); + LLVM_FALLTHROUGH; + case CK_Silvermont: + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "pclmul", true); + setFeatureEnabledImpl(Features, "sse4.2", true); + LLVM_FALLTHROUGH; + case CK_Bonnell: + setFeatureEnabledImpl(Features, "movbe", true); + setFeatureEnabledImpl(Features, "ssse3", true); + setFeatureEnabledImpl(Features, "fxsr", true); + setFeatureEnabledImpl(Features, "cx16", true); + break; case CK_KNL: setFeatureEnabledImpl(Features, "avx512f", true); setFeatureEnabledImpl(Features, "avx512cd", true); @@ -3524,6 +3547,7 @@ void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features, Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] = Features["avx512vl"] = Features["avx512vbmi"] = Features["avx512ifma"] = Features["avx512vpopcntdq"] = false; + break; } } @@ -3556,6 +3580,7 @@ void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features, LLVM_FALLTHROUGH; case AMD3DNowAthlon: Features["3dnowa"] = false; + break; } } @@ -3590,6 +3615,7 @@ void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level, LLVM_FALLTHROUGH; case XOP: Features["xop"] = false; + break; } } @@ -3893,6 +3919,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, case CK_Silvermont: defineCPUMacros(Builder, "slm"); break; + case CK_Goldmont: + defineCPUMacros(Builder, "goldmont"); + break; case CK_Nehalem: case CK_Westmere: case CK_SandyBridge: @@ -4156,6 +4185,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, break; default: Builder.defineMacro("_M_IX86_FP", Twine(0)); + break; } } @@ -5413,7 +5443,7 @@ public: if (Triple.getOS() == llvm::Triple::Linux || Triple.getOS() == llvm::Triple::UnknownOS) this->MCountName = - Opts.EABIVersion == "gnu" ? "\01__gnu_mcount_nc" : "\01mcount"; + Opts.EABIVersion == llvm::EABI::GNU ? "\01__gnu_mcount_nc" : "\01mcount"; } StringRef getABI() const override { return ABI; } @@ -5594,6 +5624,17 @@ public: bool setFPMath(StringRef Name) override; + void getTargetDefinesARMV81A(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); + } + + void getTargetDefinesARMV82A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the ARMv8.1-A defines + getTargetDefinesARMV81A(Opts, Builder); + } + void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { // Target identification. @@ -5792,8 +5833,15 @@ public: if (Opts.UnsafeFPMath) Builder.defineMacro("__ARM_FP_FAST", "1"); - if (ArchKind == llvm::ARM::AK_ARMV8_1A) - Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); + switch(ArchKind) { + default: break; + case llvm::ARM::AK_ARMV8_1A: + getTargetDefinesARMV81A(Opts, Builder); + break; + case llvm::ARM::AK_ARMV8_2A: + getTargetDefinesARMV82A(Opts, Builder); + break; + } } ArrayRef<Builtin::Info> getTargetBuiltins() const override { @@ -6186,9 +6234,8 @@ class AArch64TargetInfo : public TargetInfo { unsigned CRC; unsigned Crypto; unsigned Unaligned; - unsigned V8_1A; - unsigned V8_2A; unsigned HasFullFP16; + llvm::AArch64::ArchKind ArchKind; static const Builtin::Info BuiltinInfo[]; @@ -6236,7 +6283,7 @@ public: if (Triple.getOS() == llvm::Triple::Linux) this->MCountName = "\01_mcount"; else if (Triple.getOS() == llvm::Triple::UnknownOS) - this->MCountName = Opts.EABIVersion == "gnu" ? "\01_mcount" : "mcount"; + this->MCountName = Opts.EABIVersion == llvm::EABI::GNU ? "\01_mcount" : "mcount"; } StringRef getABI() const override { return ABI; } @@ -6254,6 +6301,20 @@ public: static_cast<unsigned>(llvm::AArch64::ArchKind::AK_INVALID); } + void getTargetDefinesARMV81A(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); + } + + void getTargetDefinesARMV82A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the ARMv8.1 defines + getTargetDefinesARMV81A(Opts, Builder); + + if (FPU == NeonMode && HasFullFP16) + Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1"); + } + void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { // Target identification. @@ -6318,10 +6379,15 @@ public: if (Unaligned) Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); - if (V8_1A) - Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); - if (V8_2A && FPU == NeonMode && HasFullFP16) - Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1"); + switch(ArchKind) { + default: break; + case llvm::AArch64::ArchKind::AK_ARMV8_1A: + getTargetDefinesARMV81A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::AK_ARMV8_2A: + getTargetDefinesARMV82A(Opts, Builder); + break; + } // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); @@ -6348,9 +6414,8 @@ public: CRC = 0; Crypto = 0; Unaligned = 1; - V8_1A = 0; - V8_2A = 0; HasFullFP16 = 0; + ArchKind = llvm::AArch64::ArchKind::AK_ARMV8A; for (const auto &Feature : Features) { if (Feature == "+neon") @@ -6362,9 +6427,9 @@ public: if (Feature == "+strict-align") Unaligned = 0; if (Feature == "+v8.1a") - V8_1A = 1; + ArchKind = llvm::AArch64::ArchKind::AK_ARMV8_1A; if (Feature == "+v8.2a") - V8_2A = 1; + ArchKind = llvm::AArch64::ArchKind::AK_ARMV8_2A; if (Feature == "+fullfp16") HasFullFP16 = 1; } @@ -6550,6 +6615,43 @@ public: } }; +class MicrosoftARM64TargetInfo + : public WindowsTargetInfo<AArch64leTargetInfo> { + const llvm::Triple Triple; + +public: + MicrosoftARM64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsTargetInfo<AArch64leTargetInfo>(Triple, Opts), Triple(Triple) { + WCharType = UnsignedShort; + SizeType = UnsignedLongLong; + TheCXXABI.set(TargetCXXABI::Microsoft); + } + + void setDataLayout() override { + resetDataLayout("e-m:w-i64:64-i128:128-n32:64-S128"); + } + + void getVisualStudioDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsTargetInfo<AArch64leTargetInfo>::getVisualStudioDefines(Opts, + Builder); + Builder.defineMacro("_WIN32", "1"); + Builder.defineMacro("_WIN64", "1"); + Builder.defineMacro("_M_ARM64", "1"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsTargetInfo::getTargetDefines(Opts, Builder); + getVisualStudioDefines(Opts, Builder); + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } +}; + class AArch64beTargetInfo : public AArch64TargetInfo { void setDataLayout() override { assert(!getTriple().isOSBinFormatMachO()); @@ -7727,6 +7829,148 @@ public: } }; +class Nios2TargetInfo : public TargetInfo { + void setDataLayout() { + if (BigEndian) + resetDataLayout("E-p:32:32:32-i8:8:32-i16:16:32-n32"); + else + resetDataLayout("e-p:32:32:32-i8:8:32-i16:16:32-n32"); + } + + static const Builtin::Info BuiltinInfo[]; + std::string CPU; + std::string ABI; + +public: + Nios2TargetInfo(const llvm::Triple &triple, const TargetOptions &opts) + : TargetInfo(triple), CPU(opts.CPU), ABI(opts.ABI) { + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + setDataLayout(); + } + + StringRef getABI() const override { return ABI; } + bool setABI(const std::string &Name) override { + if (Name == "o32" || Name == "eabi") { + ABI = Name; + return true; + } + return false; + } + + bool setCPU(const std::string &Name) override { + if (Name == "nios2r1" || Name == "nios2r2") { + CPU = Name; + return true; + } + return false; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + DefineStd(Builder, "nios2", Opts); + DefineStd(Builder, "NIOS2", Opts); + + Builder.defineMacro("__nios2"); + Builder.defineMacro("__NIOS2"); + Builder.defineMacro("__nios2__"); + Builder.defineMacro("__NIOS2__"); + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + return llvm::makeArrayRef(BuiltinInfo, clang::Nios2::LastTSBuiltin - + Builtin::FirstTSBuiltin); + } + + bool isFeatureSupportedByCPU(StringRef Feature, StringRef CPU) const { + const bool isR2 = CPU == "nios2r2"; + return llvm::StringSwitch<bool>(Feature) + .Case("nios2r2mandatory", isR2) + .Case("nios2r2bmx", isR2) + .Case("nios2r2mpx", isR2) + .Case("nios2r2cdx", isR2) + .Default(false); + } + + bool initFeatureMap(llvm::StringMap<bool> &Features, + DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeatureVec) const override { + static const char *allFeatures[] = { + "nios2r2mandatory", "nios2r2bmx", "nios2r2mpx", "nios2r2cdx" + }; + for (const char *feature : allFeatures) { + Features[feature] = isFeatureSupportedByCPU(feature, CPU); + } + return true; + } + + bool hasFeature(StringRef Feature) const override { + return isFeatureSupportedByCPU(Feature, CPU); + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + // CPU register names + // Must match second column of GCCRegAliases + "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", + // Floating point register names + "ctl0", "ctl1", "ctl2", "ctl3", "ctl4", "ctl5", "ctl6", "ctl7", "ctl8", + "ctl9", "ctl10", "ctl11", "ctl12", "ctl13", "ctl14", "ctl15" + }; + return llvm::makeArrayRef(GCCRegNames); + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + return false; + + case 'r': // CPU registers. + case 'd': // Equivalent to "r" unless generating MIPS16 code. + case 'y': // Equivalent to "r", backwards compatibility only. + case 'f': // floating-point registers. + case 'c': // $25 for indirect jumps + case 'l': // lo register + case 'x': // hilo register pair + Info.setAllowsRegister(); + return true; + } + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + static const TargetInfo::GCCRegAlias aliases[] = { + {{"zero"}, "r0"}, {{"at"}, "r1"}, {{"et"}, "r24"}, + {{"bt"}, "r25"}, {{"gp"}, "r26"}, {{"sp"}, "r27"}, + {{"fp"}, "r28"}, {{"ea"}, "r29"}, {{"ba"}, "r30"}, + {{"ra"}, "r31"}, {{"status"}, "ctl0"}, {{"estatus"}, "ctl1"}, + {{"bstatus"}, "ctl2"}, {{"ienable"}, "ctl3"}, {{"ipending"}, "ctl4"}, + {{"cpuid"}, "ctl5"}, {{"exception"}, "ctl7"}, {{"pteaddr"}, "ctl8"}, + {{"tlbacc"}, "ctl9"}, {{"tlbmisc"}, "ctl10"}, {{"badaddr"}, "ctl12"}, + {{"config"}, "ctl13"}, {{"mpubase"}, "ctl14"}, {{"mpuacc"}, "ctl15"}, + }; + return llvm::makeArrayRef(aliases); + } +}; + +const Builtin::Info Nios2TargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsNios2.def" +}; + class MipsTargetInfo : public TargetInfo { void setDataLayout() { StringRef Layout; @@ -9264,6 +9508,8 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple, return new NetBSDTargetInfo<AArch64leTargetInfo>(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo<AArch64leTargetInfo>(Triple, Opts); + case llvm::Triple::Win32: + return new MicrosoftARM64TargetInfo(Triple, Opts); default: return new AArch64leTargetInfo(Triple, Opts); } @@ -9353,6 +9599,9 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::msp430: return new MSP430TargetInfo(Triple, Opts); + case llvm::Triple::nios2: + return new LinuxTargetInfo<Nios2TargetInfo>(Triple, Opts); + case llvm::Triple::mips: switch (os) { case llvm::Triple::Linux: diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index bd01902a032b..9b3850abcce7 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -54,6 +54,7 @@ #include "llvm/Transforms/ObjCARC.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/GVN.h" +#include "llvm/Transforms/Utils/NameAnonGlobals.h" #include "llvm/Transforms/Utils/SymbolRewriter.h" #include <memory> using namespace clang; @@ -414,11 +415,7 @@ static void initTargetOptions(llvm::TargetOptions &Options, Options.RelaxELFRelocations = CodeGenOpts.RelaxELFRelocations; // Set EABI version. - Options.EABIVersion = llvm::StringSwitch<llvm::EABI>(TargetOpts.EABIVersion) - .Case("4", llvm::EABI::EABI4) - .Case("5", llvm::EABI::EABI5) - .Case("gnu", llvm::EABI::GNU) - .Default(llvm::EABI::Default); + Options.EABIVersion = TargetOpts.EABIVersion; if (LangOpts.SjLjExceptions) Options.ExceptionModel = llvm::ExceptionHandling::SjLj; @@ -491,7 +488,6 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM, PMBuilder.OptLevel = CodeGenOpts.OptimizationLevel; PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize; - PMBuilder.BBVectorize = CodeGenOpts.VectorizeBB; PMBuilder.SLPVectorize = CodeGenOpts.VectorizeSLP; PMBuilder.LoopVectorize = CodeGenOpts.VectorizeLoop; @@ -856,11 +852,15 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( if (CodeGenOpts.hasProfileIRUse()) PGOOpt.ProfileUseFile = CodeGenOpts.ProfileInstrumentUsePath; + if (!CodeGenOpts.SampleProfileFile.empty()) + PGOOpt.SampleProfileFile = CodeGenOpts.SampleProfileFile; + // Only pass a PGO options struct if -fprofile-generate or // -fprofile-use were passed on the cmdline. PassBuilder PB(TM.get(), (PGOOpt.RunProfileGen || - !PGOOpt.ProfileUseFile.empty()) ? + !PGOOpt.ProfileUseFile.empty() || + !PGOOpt.SampleProfileFile.empty()) ? Optional<PGOOptions>(PGOOpt) : None); LoopAnalysisManager LAM; @@ -878,20 +878,34 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( PB.registerLoopAnalyses(LAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - ModulePassManager MPM; + ModulePassManager MPM(CodeGenOpts.DebugPassManager); if (!CodeGenOpts.DisableLLVMPasses) { + bool IsThinLTO = CodeGenOpts.EmitSummaryIndex; + bool IsLTO = CodeGenOpts.PrepareForLTO; + if (CodeGenOpts.OptimizationLevel == 0) { // Build a minimal pipeline based on the semantics required by Clang, // which is just that always inlining occurs. MPM.addPass(AlwaysInlinerPass()); + if (IsThinLTO) + MPM.addPass(NameAnonGlobalPass()); } else { - // Otherwise, use the default pass pipeline. We also have to map our - // optimization levels into one of the distinct levels used to configure - // the pipeline. + // Map our optimization levels into one of the distinct levels used to + // configure the pipeline. PassBuilder::OptimizationLevel Level = mapToLevel(CodeGenOpts); - MPM = PB.buildPerModuleDefaultPipeline(Level); + if (IsThinLTO) { + MPM = PB.buildThinLTOPreLinkDefaultPipeline( + Level, CodeGenOpts.DebugPassManager); + MPM.addPass(NameAnonGlobalPass()); + } else if (IsLTO) { + MPM = PB.buildLTOPreLinkDefaultPipeline(Level, + CodeGenOpts.DebugPassManager); + } else { + MPM = PB.buildPerModuleDefaultPipeline(Level, + CodeGenOpts.DebugPassManager); + } } } diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index a6451b7fc3c1..2a6e92e7f3ce 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -9372,6 +9372,16 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_grow_memory, X->getType()); return Builder.CreateCall(Callee, X); } + case WebAssembly::BI__builtin_wasm_throw: { + Value *Tag = EmitScalarExpr(E->getArg(0)); + Value *Obj = EmitScalarExpr(E->getArg(1)); + Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_throw); + return Builder.CreateCall(Callee, {Tag, Obj}); + } + case WebAssembly::BI__builtin_wasm_rethrow: { + Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_rethrow); + return Builder.CreateCall(Callee); + } default: return nullptr; diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 38d520a2beb0..13a156c7bbd7 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -1297,7 +1297,7 @@ static void CreateCoercedStore(llvm::Value *Src, // If store is legal, just bitcast the src pointer. if (SrcSize <= DstSize) { - Dst = CGF.Builder.CreateBitCast(Dst, llvm::PointerType::getUnqual(SrcTy)); + Dst = CGF.Builder.CreateElementBitCast(Dst, SrcTy); BuildAggStore(CGF, Src, Dst, DstIsVolatile); } else { // Otherwise do coercion through memory. This is stupid, but @@ -2412,8 +2412,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, Address AddrToStoreInto = Address::invalid(); if (SrcSize <= DstSize) { - AddrToStoreInto = - Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy)); + AddrToStoreInto = Builder.CreateElementBitCast(Ptr, STy); } else { AddrToStoreInto = CreateTempAlloca(STy, Alloca.getAlignment(), "coerce"); @@ -3389,6 +3388,14 @@ void CodeGenFunction::EmitCallArgs( unsigned Idx = LeftToRight ? I : E - I - 1; CallExpr::const_arg_iterator Arg = ArgRange.begin() + Idx; unsigned InitialArgSize = Args.size(); + // If *Arg is an ObjCIndirectCopyRestoreExpr, check that either the types of + // the argument and parameter match or the objc method is parameterized. + assert((!isa<ObjCIndirectCopyRestoreExpr>(*Arg) || + getContext().hasSameUnqualifiedType((*Arg)->getType(), + ArgTypes[Idx]) || + (isa<ObjCMethodDecl>(AC.getDecl()) && + isObjCMethodWithTypeParams(cast<ObjCMethodDecl>(AC.getDecl())))) && + "Argument and parameter types don't match"); EmitCallArg(Args, *Arg, ArgTypes[Idx]); // In particular, we depend on it being the last arg in Args, and the // objectsize bits depend on there only being one arg if !LeftToRight. @@ -3449,7 +3456,6 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, if (const ObjCIndirectCopyRestoreExpr *CRE = dyn_cast<ObjCIndirectCopyRestoreExpr>(E)) { assert(getLangOpts().ObjCAutoRefCount); - assert(getContext().hasSameUnqualifiedType(E->getType(), type)); return emitWritebackArg(*this, args, CRE); } diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index ccd3b8d513b1..4b656ea4a879 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -1860,6 +1860,10 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, lt = Qualifiers::OCL_ExplicitNone; } + // Load objects passed indirectly. + if (Arg.isIndirect() && !ArgVal) + ArgVal = Builder.CreateLoad(DeclPtr); + if (lt == Qualifiers::OCL_Strong) { if (!isConsumed) { if (CGM.getCodeGenOpts().OptimizationLevel == 0) { diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 7976c53d9e98..98435fefbd2e 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -1678,7 +1678,10 @@ struct NullReturnState { /// Complete the null-return operation. It is valid to call this /// regardless of whether 'init' has been called. - RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType, + RValue complete(CodeGenFunction &CGF, + ReturnValueSlot returnSlot, + RValue result, + QualType resultType, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { // If we never had to do a null-check, just use the raw result. @@ -1745,7 +1748,8 @@ struct NullReturnState { // memory or (2) agg values in registers. if (result.isAggregate()) { assert(result.isAggregate() && "null init of non-aggregate result?"); - CGF.EmitNullInitialization(result.getAggregateAddress(), resultType); + if (!returnSlot.isUnused()) + CGF.EmitNullInitialization(result.getAggregateAddress(), resultType); if (contBB) CGF.EmitBlock(contBB); return result; } @@ -2117,11 +2121,11 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, } } - NullReturnState nullReturn; + bool RequiresNullCheck = false; llvm::Constant *Fn = nullptr; if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) { - if (ReceiverCanBeNull) nullReturn.init(CGF, Arg0); + if (ReceiverCanBeNull) RequiresNullCheck = true; Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper) : ObjCTypes.getSendStretFn(IsSuper); } else if (CGM.ReturnTypeUsesFPRet(ResultType)) { @@ -2134,23 +2138,30 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, // arm64 uses objc_msgSend for stret methods and yet null receiver check // must be made for it. if (ReceiverCanBeNull && CGM.ReturnTypeUsesSRet(MSI.CallInfo)) - nullReturn.init(CGF, Arg0); + RequiresNullCheck = true; Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper) : ObjCTypes.getSendFn(IsSuper); } + // We don't need to emit a null check to zero out an indirect result if the + // result is ignored. + if (Return.isUnused()) + RequiresNullCheck = false; + // Emit a null-check if there's a consumed argument other than the receiver. - bool RequiresNullCheck = false; - if (ReceiverCanBeNull && CGM.getLangOpts().ObjCAutoRefCount && Method) { + if (!RequiresNullCheck && CGM.getLangOpts().ObjCAutoRefCount && Method) { for (const auto *ParamDecl : Method->parameters()) { if (ParamDecl->hasAttr<NSConsumedAttr>()) { - if (!nullReturn.NullBB) - nullReturn.init(CGF, Arg0); RequiresNullCheck = true; break; } } } + + NullReturnState nullReturn; + if (RequiresNullCheck) { + nullReturn.init(CGF, Arg0); + } llvm::Instruction *CallSite; Fn = llvm::ConstantExpr::getBitCast(Fn, MSI.MessengerType); @@ -2164,7 +2175,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, llvm::CallSite(CallSite).setDoesNotReturn(); } - return nullReturn.complete(CGF, rvalue, ResultType, CallArgs, + return nullReturn.complete(CGF, Return, rvalue, ResultType, CallArgs, RequiresNullCheck ? Method : nullptr); } @@ -6381,16 +6392,15 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF, llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName); if (PTGV) return CGF.Builder.CreateAlignedLoad(PTGV, Align); - PTGV = new llvm::GlobalVariable( - CGM.getModule(), - Init->getType(), false, - llvm::GlobalValue::WeakAnyLinkage, - Init, - ProtocolName); + PTGV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, + llvm::GlobalValue::WeakAnyLinkage, Init, + ProtocolName); PTGV->setSection(GetSectionName("__objc_protorefs", "coalesced,no_dead_strip")); PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility); PTGV->setAlignment(Align.getQuantity()); + if (!CGM.getTriple().isOSBinFormatMachO()) + PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolName)); CGM.addCompilerUsedGlobal(PTGV); return CGF.Builder.CreateAlignedLoad(PTGV, Align); } @@ -7074,7 +7084,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF, CGCallee callee(CGCalleeInfo(), calleePtr); RValue result = CGF.EmitCall(MSI.CallInfo, callee, returnSlot, args); - return nullReturn.complete(CGF, result, resultType, formalArgs, + return nullReturn.complete(CGF, returnSlot, result, resultType, formalArgs, requiresnullCheck ? method : nullptr); } diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp index b5599dad3096..4cfddcb107cb 100644 --- a/lib/CodeGen/CGObjCRuntime.cpp +++ b/lib/CodeGen/CGObjCRuntime.cpp @@ -26,61 +26,27 @@ using namespace clang; using namespace CodeGen; -static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM, - const ObjCInterfaceDecl *OID, - const ObjCImplementationDecl *ID, - const ObjCIvarDecl *Ivar) { - const ObjCInterfaceDecl *Container = Ivar->getContainingInterface(); - - // FIXME: We should eliminate the need to have ObjCImplementationDecl passed - // in here; it should never be necessary because that should be the lexical - // decl context for the ivar. - - // If we know have an implementation (and the ivar is in it) then - // look up in the implementation layout. - const ASTRecordLayout *RL; - if (ID && declaresSameEntity(ID->getClassInterface(), Container)) - RL = &CGM.getContext().getASTObjCImplementationLayout(ID); - else - RL = &CGM.getContext().getASTObjCInterfaceLayout(Container); - - // Compute field index. - // - // FIXME: The index here is closely tied to how ASTContext::getObjCLayout is - // implemented. This should be fixed to get the information from the layout - // directly. - unsigned Index = 0; - - for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin(); - IVD; IVD = IVD->getNextIvar()) { - if (Ivar == IVD) - break; - ++Index; - } - assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!"); - - return RL->getFieldOffset(Index); -} - uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, const ObjCInterfaceDecl *OID, const ObjCIvarDecl *Ivar) { - return LookupFieldBitOffset(CGM, OID, nullptr, Ivar) / - CGM.getContext().getCharWidth(); + return CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar) / + CGM.getContext().getCharWidth(); } uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, const ObjCImplementationDecl *OID, const ObjCIvarDecl *Ivar) { - return LookupFieldBitOffset(CGM, OID->getClassInterface(), OID, Ivar) / - CGM.getContext().getCharWidth(); + return CGM.getContext().lookupFieldBitOffset(OID->getClassInterface(), OID, + Ivar) / + CGM.getContext().getCharWidth(); } unsigned CGObjCRuntime::ComputeBitfieldBitOffset( CodeGen::CodeGenModule &CGM, const ObjCInterfaceDecl *ID, const ObjCIvarDecl *Ivar) { - return LookupFieldBitOffset(CGM, ID, ID->getImplementation(), Ivar); + return CGM.getContext().lookupFieldBitOffset(ID, ID->getImplementation(), + Ivar); } LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, @@ -119,7 +85,8 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, // Note, there is a subtle invariant here: we can only call this routine on // non-synthesized ivars but we may be called for synthesized ivars. However, // a synthesized ivar can never be a bit-field, so this is safe. - uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, nullptr, Ivar); + uint64_t FieldBitOffset = + CGF.CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar); uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth(); uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign(); uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext()); diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 8d83255ac139..3df95a4e9b2a 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -5603,7 +5603,7 @@ public: // We have to process the component lists that relate with the same // declaration in a single chunk so that we can generate the map flags // correctly. Therefore, we organize all lists in a map. - llvm::DenseMap<const ValueDecl *, SmallVector<MapInfo, 8>> Info; + llvm::MapVector<const ValueDecl *, SmallVector<MapInfo, 8>> Info; // Helper function to fill the information map for the different supported // clauses. @@ -5927,16 +5927,11 @@ emitOffloadingArrays(CodeGenFunction &CGF, for (unsigned i = 0; i < Info.NumberOfPtrs; ++i) { llvm::Value *BPVal = *BasePointers[i]; - if (BPVal->getType()->isPointerTy()) - BPVal = CGF.Builder.CreateBitCast(BPVal, CGM.VoidPtrTy); - else { - assert(BPVal->getType()->isIntegerTy() && - "If not a pointer, the value type must be an integer."); - BPVal = CGF.Builder.CreateIntToPtr(BPVal, CGM.VoidPtrTy); - } llvm::Value *BP = CGF.Builder.CreateConstInBoundsGEP2_32( llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs), Info.BasePointersArray, 0, i); + BP = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + BP, BPVal->getType()->getPointerTo(/*AddrSpace=*/0)); Address BPAddr(BP, Ctx.getTypeAlignInChars(Ctx.VoidPtrTy)); CGF.Builder.CreateStore(BPVal, BPAddr); @@ -5945,16 +5940,11 @@ emitOffloadingArrays(CodeGenFunction &CGF, Info.CaptureDeviceAddrMap.insert(std::make_pair(DevVD, BPAddr)); llvm::Value *PVal = Pointers[i]; - if (PVal->getType()->isPointerTy()) - PVal = CGF.Builder.CreateBitCast(PVal, CGM.VoidPtrTy); - else { - assert(PVal->getType()->isIntegerTy() && - "If not a pointer, the value type must be an integer."); - PVal = CGF.Builder.CreateIntToPtr(PVal, CGM.VoidPtrTy); - } llvm::Value *P = CGF.Builder.CreateConstInBoundsGEP2_32( llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs), Info.PointersArray, 0, i); + P = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + P, PVal->getType()->getPointerTo(/*AddrSpace=*/0)); Address PAddr(P, Ctx.getTypeAlignInChars(Ctx.VoidPtrTy)); CGF.Builder.CreateStore(PVal, PAddr); diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 77f3c332a12f..493cd627e418 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -239,21 +239,47 @@ static QualType getCanonicalParamType(ASTContext &C, QualType T) { return C.getCanonicalParamType(T); } -llvm::Function * -CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) { - assert( - CapturedStmtInfo && - "CapturedStmtInfo should be set when generating the captured function"); - const CapturedDecl *CD = S.getCapturedDecl(); - const RecordDecl *RD = S.getCapturedRecordDecl(); +namespace { + /// Contains required data for proper outlined function codegen. + struct FunctionOptions { + /// Captured statement for which the function is generated. + const CapturedStmt *S = nullptr; + /// true if cast to/from UIntPtr is required for variables captured by + /// value. + bool UIntPtrCastRequired = true; + /// true if only casted argumefnts must be registered as local args or VLA + /// sizes. + bool RegisterCastedArgsOnly = false; + /// Name of the generated function. + StringRef FunctionName; + explicit FunctionOptions(const CapturedStmt *S, bool UIntPtrCastRequired, + bool RegisterCastedArgsOnly, + StringRef FunctionName) + : S(S), UIntPtrCastRequired(UIntPtrCastRequired), + RegisterCastedArgsOnly(UIntPtrCastRequired && RegisterCastedArgsOnly), + FunctionName(FunctionName) {} + }; +} + +static std::pair<llvm::Function *, bool> emitOutlinedFunctionPrologue( + CodeGenFunction &CGF, FunctionArgList &Args, + llvm::DenseMap<const Decl *, std::pair<const VarDecl *, Address>> + &LocalAddrs, + llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>> + &VLASizes, + llvm::Value *&CXXThisValue, const FunctionOptions &FO) { + const CapturedDecl *CD = FO.S->getCapturedDecl(); + const RecordDecl *RD = FO.S->getCapturedRecordDecl(); assert(CD->hasBody() && "missing CapturedDecl body"); + CXXThisValue = nullptr; // Build the argument list. + CodeGenModule &CGM = CGF.CGM; ASTContext &Ctx = CGM.getContext(); - FunctionArgList Args; + bool HasUIntPtrArgs = false; Args.append(CD->param_begin(), std::next(CD->param_begin(), CD->getContextParamPosition())); - auto I = S.captures().begin(); + auto I = FO.S->captures().begin(); for (auto *FD : RD->fields()) { QualType ArgType = FD->getType(); IdentifierInfo *II = nullptr; @@ -265,23 +291,24 @@ CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) { // deal with pointers. We can pass in the same way the VLA type sizes to the // outlined function. if ((I->capturesVariableByCopy() && !ArgType->isAnyPointerType()) || - I->capturesVariableArrayType()) - ArgType = Ctx.getUIntPtrType(); + I->capturesVariableArrayType()) { + HasUIntPtrArgs = true; + if (FO.UIntPtrCastRequired) + ArgType = Ctx.getUIntPtrType(); + } if (I->capturesVariable() || I->capturesVariableByCopy()) { CapVar = I->getCapturedVar(); II = CapVar->getIdentifier(); } else if (I->capturesThis()) - II = &getContext().Idents.get("this"); + II = &Ctx.Idents.get("this"); else { assert(I->capturesVariableArrayType()); - II = &getContext().Idents.get("vla"); + II = &Ctx.Idents.get("vla"); } - if (ArgType->isVariablyModifiedType()) { - ArgType = - getCanonicalParamType(getContext(), ArgType.getNonReferenceType()); - } - Args.push_back(ImplicitParamDecl::Create(getContext(), /*DC=*/nullptr, + if (ArgType->isVariablyModifiedType()) + ArgType = getCanonicalParamType(Ctx, ArgType.getNonReferenceType()); + Args.push_back(ImplicitParamDecl::Create(Ctx, /*DC=*/nullptr, FD->getLocation(), II, ArgType, ImplicitParamDecl::Other)); ++I; @@ -296,90 +323,166 @@ CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) { CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args); llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo); - llvm::Function *F = llvm::Function::Create( - FuncLLVMTy, llvm::GlobalValue::InternalLinkage, - CapturedStmtInfo->getHelperName(), &CGM.getModule()); + llvm::Function *F = + llvm::Function::Create(FuncLLVMTy, llvm::GlobalValue::InternalLinkage, + FO.FunctionName, &CGM.getModule()); CGM.SetInternalFunctionAttributes(CD, F, FuncInfo); if (CD->isNothrow()) F->addFnAttr(llvm::Attribute::NoUnwind); // Generate the function. - StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getLocation(), - CD->getBody()->getLocStart()); + CGF.StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getLocation(), + CD->getBody()->getLocStart()); unsigned Cnt = CD->getContextParamPosition(); - I = S.captures().begin(); + I = FO.S->captures().begin(); for (auto *FD : RD->fields()) { // If we are capturing a pointer by copy we don't need to do anything, just // use the value that we get from the arguments. if (I->capturesVariableByCopy() && FD->getType()->isAnyPointerType()) { const VarDecl *CurVD = I->getCapturedVar(); - Address LocalAddr = GetAddrOfLocalVar(Args[Cnt]); + Address LocalAddr = CGF.GetAddrOfLocalVar(Args[Cnt]); // If the variable is a reference we need to materialize it here. if (CurVD->getType()->isReferenceType()) { - Address RefAddr = CreateMemTemp(CurVD->getType(), getPointerAlign(), - ".materialized_ref"); - EmitStoreOfScalar(LocalAddr.getPointer(), RefAddr, /*Volatile=*/false, - CurVD->getType()); + Address RefAddr = CGF.CreateMemTemp( + CurVD->getType(), CGM.getPointerAlign(), ".materialized_ref"); + CGF.EmitStoreOfScalar(LocalAddr.getPointer(), RefAddr, + /*Volatile=*/false, CurVD->getType()); LocalAddr = RefAddr; } - setAddrOfLocalVar(CurVD, LocalAddr); + if (!FO.RegisterCastedArgsOnly) + LocalAddrs.insert({Args[Cnt], {CurVD, LocalAddr}}); ++Cnt; ++I; continue; } LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); - LValue ArgLVal = - MakeAddrLValue(GetAddrOfLocalVar(Args[Cnt]), Args[Cnt]->getType(), - BaseInfo); + LValue ArgLVal = CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(Args[Cnt]), + Args[Cnt]->getType(), BaseInfo); if (FD->hasCapturedVLAType()) { - LValue CastedArgLVal = - MakeAddrLValue(castValueFromUintptr(*this, FD->getType(), - Args[Cnt]->getName(), ArgLVal), - FD->getType(), BaseInfo); + if (FO.UIntPtrCastRequired) { + ArgLVal = CGF.MakeAddrLValue(castValueFromUintptr(CGF, FD->getType(), + Args[Cnt]->getName(), + ArgLVal), + FD->getType(), BaseInfo); + } auto *ExprArg = - EmitLoadOfLValue(CastedArgLVal, SourceLocation()).getScalarVal(); + CGF.EmitLoadOfLValue(ArgLVal, SourceLocation()).getScalarVal(); auto VAT = FD->getCapturedVLAType(); - VLASizeMap[VAT->getSizeExpr()] = ExprArg; + VLASizes.insert({Args[Cnt], {VAT->getSizeExpr(), ExprArg}}); } else if (I->capturesVariable()) { auto *Var = I->getCapturedVar(); QualType VarTy = Var->getType(); Address ArgAddr = ArgLVal.getAddress(); if (!VarTy->isReferenceType()) { if (ArgLVal.getType()->isLValueReferenceType()) { - ArgAddr = EmitLoadOfReference( + ArgAddr = CGF.EmitLoadOfReference( ArgAddr, ArgLVal.getType()->castAs<ReferenceType>()); } else if (!VarTy->isVariablyModifiedType() || !VarTy->isPointerType()) { assert(ArgLVal.getType()->isPointerType()); - ArgAddr = EmitLoadOfPointer( + ArgAddr = CGF.EmitLoadOfPointer( ArgAddr, ArgLVal.getType()->castAs<PointerType>()); } } - setAddrOfLocalVar( - Var, Address(ArgAddr.getPointer(), getContext().getDeclAlign(Var))); + if (!FO.RegisterCastedArgsOnly) { + LocalAddrs.insert( + {Args[Cnt], + {Var, Address(ArgAddr.getPointer(), Ctx.getDeclAlign(Var))}}); + } } else if (I->capturesVariableByCopy()) { assert(!FD->getType()->isAnyPointerType() && "Not expecting a captured pointer."); auto *Var = I->getCapturedVar(); QualType VarTy = Var->getType(); - setAddrOfLocalVar(Var, castValueFromUintptr(*this, FD->getType(), - Args[Cnt]->getName(), ArgLVal, - VarTy->isReferenceType())); + LocalAddrs.insert( + {Args[Cnt], + {Var, + FO.UIntPtrCastRequired + ? castValueFromUintptr(CGF, FD->getType(), Args[Cnt]->getName(), + ArgLVal, VarTy->isReferenceType()) + : ArgLVal.getAddress()}}); } else { // If 'this' is captured, load it into CXXThisValue. assert(I->capturesThis()); - CXXThisValue = - EmitLoadOfLValue(ArgLVal, Args[Cnt]->getLocation()).getScalarVal(); + CXXThisValue = CGF.EmitLoadOfLValue(ArgLVal, Args[Cnt]->getLocation()) + .getScalarVal(); + LocalAddrs.insert({Args[Cnt], {nullptr, ArgLVal.getAddress()}}); } ++Cnt; ++I; } + return {F, HasUIntPtrArgs}; +} + +llvm::Function * +CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) { + assert( + CapturedStmtInfo && + "CapturedStmtInfo should be set when generating the captured function"); + const CapturedDecl *CD = S.getCapturedDecl(); + // Build the argument list. + bool NeedWrapperFunction = + getDebugInfo() && + CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo; + FunctionArgList Args; + llvm::DenseMap<const Decl *, std::pair<const VarDecl *, Address>> LocalAddrs; + llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>> VLASizes; + FunctionOptions FO(&S, !NeedWrapperFunction, /*RegisterCastedArgsOnly=*/false, + CapturedStmtInfo->getHelperName()); + llvm::Function *F; + bool HasUIntPtrArgs; + std::tie(F, HasUIntPtrArgs) = emitOutlinedFunctionPrologue( + *this, Args, LocalAddrs, VLASizes, CXXThisValue, FO); + for (const auto &LocalAddrPair : LocalAddrs) { + if (LocalAddrPair.second.first) { + setAddrOfLocalVar(LocalAddrPair.second.first, + LocalAddrPair.second.second); + } + } + for (const auto &VLASizePair : VLASizes) + VLASizeMap[VLASizePair.second.first] = VLASizePair.second.second; PGO.assignRegionCounters(GlobalDecl(CD), F); CapturedStmtInfo->EmitBody(*this, CD->getBody()); FinishFunction(CD->getBodyRBrace()); - - return F; + if (!NeedWrapperFunction || !HasUIntPtrArgs) + return F; + + FunctionOptions WrapperFO(&S, /*UIntPtrCastRequired=*/true, + /*RegisterCastedArgsOnly=*/true, + ".nondebug_wrapper."); + CodeGenFunction WrapperCGF(CGM, /*suppressNewContext=*/true); + WrapperCGF.disableDebugInfo(); + Args.clear(); + LocalAddrs.clear(); + VLASizes.clear(); + llvm::Function *WrapperF = + emitOutlinedFunctionPrologue(WrapperCGF, Args, LocalAddrs, VLASizes, + WrapperCGF.CXXThisValue, WrapperFO).first; + LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); + llvm::SmallVector<llvm::Value *, 4> CallArgs; + for (const auto *Arg : Args) { + llvm::Value *CallArg; + auto I = LocalAddrs.find(Arg); + if (I != LocalAddrs.end()) { + LValue LV = + WrapperCGF.MakeAddrLValue(I->second.second, Arg->getType(), BaseInfo); + CallArg = WrapperCGF.EmitLoadOfScalar(LV, SourceLocation()); + } else { + auto EI = VLASizes.find(Arg); + if (EI != VLASizes.end()) + CallArg = EI->second.second; + else { + LValue LV = WrapperCGF.MakeAddrLValue(WrapperCGF.GetAddrOfLocalVar(Arg), + Arg->getType(), BaseInfo); + CallArg = WrapperCGF.EmitLoadOfScalar(LV, SourceLocation()); + } + } + CallArgs.emplace_back(CallArg); + } + WrapperCGF.Builder.CreateCall(F, CallArgs); + WrapperCGF.FinishFunction(); + return WrapperF; } //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp index c7e30fad7575..4f03de55149b 100644 --- a/lib/CodeGen/CodeGenAction.cpp +++ b/lib/CodeGen/CodeGenAction.cpp @@ -228,7 +228,10 @@ namespace clang { Ctx.getDiagnosticHandler(); void *OldDiagnosticContext = Ctx.getDiagnosticContext(); Ctx.setDiagnosticHandler(DiagnosticHandler, this); - Ctx.setDiagnosticHotnessRequested(CodeGenOpts.DiagnosticsWithHotness); + Ctx.setDiagnosticsHotnessRequested(CodeGenOpts.DiagnosticsWithHotness); + if (CodeGenOpts.DiagnosticsHotnessThreshold != 0) + Ctx.setDiagnosticsHotnessThreshold( + CodeGenOpts.DiagnosticsHotnessThreshold); std::unique_ptr<llvm::tool_output_file> OptRecordFile; if (!CodeGenOpts.OptRecordFile.empty()) { @@ -246,7 +249,7 @@ namespace clang { llvm::make_unique<yaml::Output>(OptRecordFile->os())); if (CodeGenOpts.getProfileUse() != CodeGenOptions::ProfileNone) - Ctx.setDiagnosticHotnessRequested(true); + Ctx.setDiagnosticsHotnessRequested(true); } // Link each LinkModule into our module. diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp index 9e193531d0f6..c3d66c1dabc5 100644 --- a/lib/CodeGen/CodeGenPGO.cpp +++ b/lib/CodeGen/CodeGenPGO.cpp @@ -617,6 +617,9 @@ uint64_t PGOHash::finalize() { void CodeGenPGO::assignRegionCounters(GlobalDecl GD, llvm::Function *Fn) { const Decl *D = GD.getDecl(); + if (!D->hasBody()) + return; + bool InstrumentRegions = CGM.getCodeGenOpts().hasProfileClangInstr(); llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader(); if (!InstrumentRegions && !PGOReader) diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index 5c13e59a0d73..cf86644fb8cd 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -23,10 +23,11 @@ using namespace clang; using namespace llvm::opt; Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain, - InputArgList *_Args, DerivedArgList *_TranslatedArgs) + InputArgList *_Args, DerivedArgList *_TranslatedArgs, + bool ContainsError) : TheDriver(D), DefaultToolChain(_DefaultToolChain), ActiveOffloadMask(0u), Args(_Args), TranslatedArgs(_TranslatedArgs), Redirects(nullptr), - ForDiagnostics(false) { + ForDiagnostics(false), ContainsError(ContainsError) { // The offloading host toolchain is the default tool chain. OrderedOffloadingToolchains.insert( std::make_pair(Action::OFK_Host, &DefaultToolChain)); diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index f23975829eaf..faced0697ed9 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -153,8 +153,10 @@ void Driver::setDriverModeFromOption(StringRef Opt) { Diag(diag::err_drv_unsupported_option_argument) << OptName << Value; } -InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) { +InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, + bool &ContainsError) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); + ContainsError = false; unsigned IncludedFlagsBitmask; unsigned ExcludedFlagsBitmask; @@ -167,27 +169,41 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) { IncludedFlagsBitmask, ExcludedFlagsBitmask); // Check for missing argument error. - if (MissingArgCount) - Diag(clang::diag::err_drv_missing_argument) + if (MissingArgCount) { + Diag(diag::err_drv_missing_argument) << Args.getArgString(MissingArgIndex) << MissingArgCount; + ContainsError |= + Diags.getDiagnosticLevel(diag::err_drv_missing_argument, + SourceLocation()) > DiagnosticsEngine::Warning; + } // Check for unsupported options. for (const Arg *A : Args) { if (A->getOption().hasFlag(options::Unsupported)) { - Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(Args); + Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args); + ContainsError |= Diags.getDiagnosticLevel(diag::err_drv_unsupported_opt, + SourceLocation()) > + DiagnosticsEngine::Warning; continue; } // Warn about -mcpu= without an argument. if (A->getOption().matches(options::OPT_mcpu_EQ) && A->containsValue("")) { - Diag(clang::diag::warn_drv_empty_joined_argument) << A->getAsString(Args); + Diag(diag::warn_drv_empty_joined_argument) << A->getAsString(Args); + ContainsError |= Diags.getDiagnosticLevel( + diag::warn_drv_empty_joined_argument, + SourceLocation()) > DiagnosticsEngine::Warning; } } - for (const Arg *A : Args.filtered(options::OPT_UNKNOWN)) - Diags.Report(IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl : - diag::err_drv_unknown_argument) - << A->getAsString(Args); + for (const Arg *A : Args.filtered(options::OPT_UNKNOWN)) { + auto ID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl + : diag::err_drv_unknown_argument; + + Diags.Report(ID) << A->getAsString(Args); + ContainsError |= Diags.getDiagnosticLevel(ID, SourceLocation()) > + DiagnosticsEngine::Warning; + } return Args; } @@ -600,9 +616,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // FIXME: This stuff needs to go into the Compilation, not the driver. bool CCCPrintPhases; - InputArgList Args = ParseArgStrings(ArgList.slice(1)); - if (Diags.hasErrorOccurred()) - return nullptr; + bool ContainsError; + InputArgList Args = ParseArgStrings(ArgList.slice(1), ContainsError); // Silence driver warnings if requested Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w)); @@ -692,7 +707,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { *UArgs, computeTargetTriple(*this, DefaultTargetTriple, *UArgs)); // The compilation takes ownership of Args. - Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs); + Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs, + ContainsError); if (!HandleImmediateArgs(*C)) return C; diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index 3a30f2a289b0..7a442c83e158 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -32,7 +32,7 @@ enum : SanitizerMask { RequiresPIE = DataFlow, NeedsUnwindTables = Address | Thread | Memory | DataFlow, SupportsCoverage = Address | KernelAddress | Memory | Leak | Undefined | - Integer | Nullability | DataFlow, + Integer | Nullability | DataFlow | Fuzzer, RecoverableByDefault = Undefined | Integer | Nullability, Unrecoverable = Unreachable | Return, LegacyFsanitizeRecoverMask = Undefined | Integer, diff --git a/lib/Driver/ToolChains/Arch/ARM.cpp b/lib/Driver/ToolChains/Arch/ARM.cpp index 4eac97620114..8cafd3c74bfb 100644 --- a/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/lib/Driver/ToolChains/Arch/ARM.cpp @@ -392,9 +392,7 @@ void arm::getARMTargetFeatures(const ToolChain &TC, if (B->getOption().matches(options::OPT_mlong_calls)) D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); } - - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-execute-only"); + Features.push_back("+execute-only"); } } } diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 292cf72b56ca..3731aa83ef06 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -35,6 +35,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/TargetParser.h" #include "llvm/Support/YAMLParser.h" #ifdef LLVM_ON_UNIX @@ -129,6 +130,13 @@ forAllAssociatedToolChains(Compilation &C, const JobAction &JA, else if (JA.isDeviceOffloading(Action::OFK_Cuda)) Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); + if (JA.isHostOffloading(Action::OFK_OpenMP)) { + auto TCs = C.getOffloadToolChains<Action::OFK_OpenMP>(); + for (auto II = TCs.first, IE = TCs.second; II != IE; ++II) + Work(*II->second); + } else if (JA.isDeviceOffloading(Action::OFK_OpenMP)) + Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); + // // TODO: Add support for other offloading programming models here. // @@ -781,15 +789,14 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, CmdArgs.push_back("-femit-coverage-data"); if (Args.hasFlag(options::OPT_fcoverage_mapping, - options::OPT_fno_coverage_mapping, false) && - !ProfileGenerateArg) - D.Diag(clang::diag::err_drv_argument_only_allowed_with) - << "-fcoverage-mapping" - << "-fprofile-instr-generate"; + options::OPT_fno_coverage_mapping, false)) { + if (!ProfileGenerateArg) + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << "-fcoverage-mapping" + << "-fprofile-instr-generate"; - if (Args.hasFlag(options::OPT_fcoverage_mapping, - options::OPT_fno_coverage_mapping, false)) CmdArgs.push_back("-fcoverage-mapping"); + } if (C.getArgs().hasArg(options::OPT_c) || C.getArgs().hasArg(options::OPT_S)) { @@ -1309,43 +1316,13 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, // FIXME: Support -meabi. // FIXME: Parts of this are duplicated in the backend, unify this somehow. const char *ABIName = nullptr; - if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) ABIName = A->getValue(); - } else if (Triple.isOSBinFormatMachO()) { - if (arm::useAAPCSForMachO(Triple)) { - ABIName = "aapcs"; - } else if (Triple.isWatchABI()) { - ABIName = "aapcs16"; - } else { - ABIName = "apcs-gnu"; - } - } else if (Triple.isOSWindows()) { - // FIXME: this is invalid for WindowsCE - ABIName = "aapcs"; - } else { - // Select the default based on the platform. - switch (Triple.getEnvironment()) { - case llvm::Triple::Android: - case llvm::Triple::GNUEABI: - case llvm::Triple::GNUEABIHF: - case llvm::Triple::MuslEABI: - case llvm::Triple::MuslEABIHF: - ABIName = "aapcs-linux"; - break; - case llvm::Triple::EABIHF: - case llvm::Triple::EABI: - ABIName = "aapcs"; - break; - default: - if (Triple.getOS() == llvm::Triple::NetBSD) - ABIName = "apcs-gnu"; - else if (Triple.getOS() == llvm::Triple::OpenBSD) - ABIName = "aapcs-linux"; - else - ABIName = "aapcs"; - break; - } + else { + std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false); + ABIName = llvm::ARM::computeDefaultTargetABI(Triple, CPU).data(); } + CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); @@ -1993,6 +1970,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); } + if (IsOpenMPDevice) { + // We have to pass the triple of the host if compiling for an OpenMP device. + std::string NormalizedTriple = + C.getSingleOffloadToolChain<Action::OFK_Host>() + ->getTriple() + .normalize(); + CmdArgs.push_back("-aux-triple"); + CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); + } + if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm || Triple.getArch() == llvm::Triple::thumb)) { unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6; @@ -4056,6 +4043,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_diagnostics_show_hotness, false)) CmdArgs.push_back("-fdiagnostics-show-hotness"); + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { + std::string Opt = std::string("-fdiagnostics-hotness-threshold=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Opt)); + } + if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { CmdArgs.push_back("-fdiagnostics-format"); CmdArgs.push_back(A->getValue()); @@ -4140,11 +4133,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_slp_vectorize, EnableSLPVec)) 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("-vectorize-slp-aggressive"); - if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) A->render(Args, CmdArgs); @@ -4413,10 +4401,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // device declarations can be identified. Also, -fopenmp-is-device is passed // along to tell the frontend that it is generating code for a device, so that // only the relevant declarations are emitted. - if (IsOpenMPDevice && Inputs.size() == 2) { + if (IsOpenMPDevice) { CmdArgs.push_back("-fopenmp-is-device"); - CmdArgs.push_back("-fopenmp-host-ir-file-path"); - CmdArgs.push_back(Args.MakeArgString(Inputs.back().getFilename())); + if (Inputs.size() == 2) { + CmdArgs.push_back("-fopenmp-host-ir-file-path"); + CmdArgs.push_back(Args.MakeArgString(Inputs.back().getFilename())); + } } // For all the host OpenMP offloading compile jobs we need to pass the targets diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp index 5e360f62e21a..e8bb703054de 100644 --- a/lib/Driver/ToolChains/CommonArgs.cpp +++ b/lib/Driver/ToolChains/CommonArgs.cpp @@ -215,6 +215,21 @@ static std::string getR600TargetGPU(const ArgList &Args) { return ""; } +static std::string getNios2TargetCPU(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mcpu_EQ); + if (!A) + A = Args.getLastArg(options::OPT_march_EQ); + + if (!A) + return ""; + + const char *name = A->getValue(); + return llvm::StringSwitch<const char *>(name) + .Case("r1", "nios2r1") + .Case("r2", "nios2r2") + .Default(name); +} + static std::string getLanaiTargetCPU(const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { return A->getValue(); @@ -267,6 +282,10 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, return A->getValue(); return ""; + case llvm::Triple::nios2: { + return getNios2TargetCPU(Args); + } + case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: @@ -598,7 +617,8 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols); // Inject libfuzzer dependencies. - if (TC.getSanitizerArgs().needsFuzzer()) { + if (TC.getSanitizerArgs().needsFuzzer() + && !Args.hasArg(options::OPT_shared)) { addLibFuzzerRuntime(TC, Args, CmdArgs); } diff --git a/lib/Driver/ToolChains/CrossWindows.cpp b/lib/Driver/ToolChains/CrossWindows.cpp index d290c62a056a..7d0c438b1360 100644 --- a/lib/Driver/ToolChains/CrossWindows.cpp +++ b/lib/Driver/ToolChains/CrossWindows.cpp @@ -238,8 +238,15 @@ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, const Driver &D = getDriver(); const std::string &SysRoot = D.SysRoot; - if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + auto AddSystemAfterIncludes = [&]() { + for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after)) + addSystemInclude(DriverArgs, CC1Args, P); + }; + + if (DriverArgs.hasArg(options::OPT_nostdinc)) { + AddSystemAfterIncludes(); return; + } addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { @@ -247,8 +254,7 @@ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::sys::path::append(ResourceDir, "include"); addSystemInclude(DriverArgs, CC1Args, ResourceDir); } - for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after)) - addSystemInclude(DriverArgs, CC1Args, P); + AddSystemAfterIncludes(); addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); } @@ -258,7 +264,7 @@ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, const llvm::Triple &Triple = getTriple(); const std::string &SysRoot = getDriver().SysRoot; - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + if (DriverArgs.hasArg(options::OPT_nostdinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; diff --git a/lib/Driver/ToolChains/Darwin.cpp b/lib/Driver/ToolChains/Darwin.cpp index e41b50c40b28..7b61095c3ba9 100644 --- a/lib/Driver/ToolChains/Darwin.cpp +++ b/lib/Driver/ToolChains/Darwin.cpp @@ -1053,7 +1053,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); if (Sanitize.needsTsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); - if (Sanitize.needsFuzzer()) + if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) AddFuzzerLinkArgs(Args, CmdArgs); if (Sanitize.needsStatsRt()) { StringRef OS = isTargetMacOS() ? "osx" : "iossim"; @@ -1150,6 +1150,17 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { Args.getLastArg(options::OPT_mwatchos_version_min_EQ, options::OPT_mwatchos_simulator_version_min_EQ); + unsigned Major, Minor, Micro; + bool HadExtra; + + // iOS 10 is the maximum deployment target for 32-bit targets. + if (iOSVersion && getTriple().isArch32Bit() && + Driver::GetReleaseVersion(iOSVersion->getValue(), Major, Minor, Micro, + HadExtra) && + Major > 10) + getDriver().Diag(diag::err_invalid_ios_deployment_target) + << iOSVersion->getAsString(Args); + // Add a macro to differentiate between m(iphone|tv|watch)os-version-min=X.Y and // -m(iphone|tv|watch)simulator-version-min=X.Y. if (Args.hasArg(options::OPT_mios_simulator_version_min_EQ) || @@ -1191,6 +1202,14 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { if (char *env = ::getenv("WATCHOS_DEPLOYMENT_TARGET")) WatchOSTarget = env; + // iOS 10 is the maximum deployment target for 32-bit targets. + if (!iOSTarget.empty() && getTriple().isArch32Bit() && + Driver::GetReleaseVersion(iOSTarget.c_str(), Major, Minor, Micro, + HadExtra) && + Major > 10) + getDriver().Diag(diag::err_invalid_ios_deployment_target) + << std::string("IPHONEOS_DEPLOYMENT_TARGET=") + iOSTarget; + // If there is no command-line argument to specify the Target version and // no environment variable defined, see if we can set the default based // on -isysroot. @@ -1308,8 +1327,6 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { llvm_unreachable("Unable to infer Darwin variant"); // Set the tool chain target information. - unsigned Major, Minor, Micro; - bool HadExtra; if (Platform == MacOS) { assert((!iOSVersion && !TvOSVersion && !WatchOSVersion) && "Unknown target platform!"); @@ -1325,6 +1342,13 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << iOSVersion->getAsString(Args); + // iOS 10 is the maximum deployment target for 32-bit targets. If the + // inferred deployment target is iOS 11 or later, set it to 10.99. + if (getTriple().isArch32Bit() && Major >= 11) { + Major = 10; + Minor = 99; + Micro = 99; + } } else if (Platform == TvOS) { if (!Driver::GetReleaseVersion(TvOSVersion->getValue(), Major, Minor, Micro, HadExtra) || HadExtra || @@ -1667,6 +1691,28 @@ void MachO::AddLinkRuntimeLibArgs(const ArgList &Args, AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true); } +bool Darwin::isAlignedAllocationUnavailable() const { + switch (TargetPlatform) { + case MacOS: // Earlier than 10.13. + return TargetVersion < VersionTuple(10U, 13U, 0U); + case IPhoneOS: + case IPhoneOSSimulator: + case TvOS: + case TvOSSimulator: // Earlier than 11.0. + return TargetVersion < VersionTuple(11U, 0U, 0U); + case WatchOS: + case WatchOSSimulator: // Earlier than 4.0. + return TargetVersion < VersionTuple(4U, 0U, 0U); + } + llvm_unreachable("Unsupported platform"); +} + +void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + if (isAlignedAllocationUnavailable()) + CC1Args.push_back("-faligned-alloc-unavailable"); +} + DerivedArgList * Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const { diff --git a/lib/Driver/ToolChains/Darwin.h b/lib/Driver/ToolChains/Darwin.h index 16ed04286ac0..ffcdf9a71a46 100644 --- a/lib/Driver/ToolChains/Darwin.h +++ b/lib/Driver/ToolChains/Darwin.h @@ -384,6 +384,14 @@ protected: return TargetVersion < VersionTuple(V0, V1, V2); } + /// Return true if c++17 aligned allocation/deallocation functions are not + /// implemented in the c++ standard library of the deployment target we are + /// targeting. + bool isAlignedAllocationUnavailable() const; + + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + StringRef getPlatformFamily() const; static StringRef getSDKName(StringRef isysroot); StringRef getOSLibraryNameSuffix() const; diff --git a/lib/Driver/ToolChains/MipsLinux.cpp b/lib/Driver/ToolChains/MipsLinux.cpp index 709c396a64b7..b394208336ed 100644 --- a/lib/Driver/ToolChains/MipsLinux.cpp +++ b/lib/Driver/ToolChains/MipsLinux.cpp @@ -109,7 +109,7 @@ std::string MipsLLVMToolChain::findLibCxxIncludePath() const { void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { assert((GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) && - "Only -lc++ (aka libxx) is suported in this toolchain."); + "Only -lc++ (aka libxx) is supported in this toolchain."); CmdArgs.push_back("-lc++"); CmdArgs.push_back("-lc++abi"); diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index cca773cfe3cb..4197587a74c0 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -56,6 +56,8 @@ static bool startsNextParameter(const FormatToken &Current, if (Current.is(TT_CtorInitializerComma) && Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma) return true; + if (Style.Language == FormatStyle::LK_Proto && Current.is(TT_SelectorName)) + return true; return Previous.is(tok::comma) && !Current.isTrailingComment() && ((Previous.isNot(TT_CtorInitializerComma) || Style.BreakConstructorInitializers != @@ -499,6 +501,13 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, } } +static bool lessOpensProtoMessageField(const FormatToken &LessTok, + const LineState &State) { + assert(LessTok.is(tok::less)); + return LessTok.NestingLevel > 0 || + (LessTok.Previous && LessTok.Previous->is(tok::equal)); +} + unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, bool DryRun) { FormatToken &Current = *State.NextToken; @@ -641,6 +650,9 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, // before the corresponding } or ]. if (PreviousNonComment && (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || + (Style.Language == FormatStyle::LK_Proto && + PreviousNonComment->is(tok::less) && + lessOpensProtoMessageField(*PreviousNonComment, State)) || (PreviousNonComment->is(TT_TemplateString) && PreviousNonComment->opensScope()))) State.Stack.back().BreakBeforeClosingBrace = true; @@ -682,7 +694,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block) return Current.NestingLevel == 0 ? State.FirstIndent : State.Stack.back().Indent; - if (Current.isOneOf(tok::r_brace, tok::r_square) && State.Stack.size() > 1) { + if ((Current.isOneOf(tok::r_brace, tok::r_square) || + (Current.is(tok::greater) && Style.Language == FormatStyle::LK_Proto)) && + State.Stack.size() > 1) { if (Current.closesBlockOrBlockTypeList(Style)) return State.Stack[State.Stack.size() - 2].NestedBlockIndent; if (Current.MatchingParen && @@ -1035,7 +1049,9 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, bool BreakBeforeParameter = false; unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall, State.Stack.back().NestedBlockIndent); - if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) { + if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || + (Style.Language == FormatStyle::LK_Proto && Current.is(tok::less) && + lessOpensProtoMessageField(Current, State))) { if (Current.opensBlockOrBlockTypeList(Style)) { NewIndent = Style.IndentWidth + std::min(State.Column, State.Stack.back().NestedBlockIndent); @@ -1047,12 +1063,12 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, Current.MatchingParen->Previous && Current.MatchingParen->Previous->is(tok::comma); AvoidBinPacking = - (Current.is(TT_ArrayInitializerLSquare) && EndsInComma) || - Current.is(TT_DictLiteral) || + EndsInComma || Current.is(TT_DictLiteral) || Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments || (NextNoComment && NextNoComment->isOneOf(TT_DesignatedInitializerPeriod, TT_DesignatedInitializerLSquare)); + BreakBeforeParameter = EndsInComma; if (Current.ParameterCount > 1) NestedBlockIndent = std::max(NestedBlockIndent, State.Column + 1); } else { diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 7659d56adf25..bb6781d79517 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -44,7 +44,6 @@ using clang::format::FormatStyle; -LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string) LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory) namespace llvm { @@ -414,7 +413,9 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> { IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch); IO.mapOptional("BeforeElse", Wrapping.BeforeElse); IO.mapOptional("IndentBraces", Wrapping.IndentBraces); - IO.mapOptional("SplitEmptyFunctionBody", Wrapping.SplitEmptyFunctionBody); + IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction); + IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord); + IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace); } }; @@ -490,7 +491,8 @@ static FormatStyle expandPresets(const FormatStyle &Style) { return Style; FormatStyle Expanded = Style; Expanded.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false, true}; + false, false, false, false, false, true, + true, true}; switch (Style.BreakBeforeBraces) { case FormatStyle::BS_Linux: Expanded.BraceWrapping.AfterClass = true; @@ -503,7 +505,8 @@ static FormatStyle expandPresets(const FormatStyle &Style) { Expanded.BraceWrapping.AfterFunction = true; Expanded.BraceWrapping.AfterStruct = true; Expanded.BraceWrapping.AfterUnion = true; - Expanded.BraceWrapping.SplitEmptyFunctionBody = false; + Expanded.BraceWrapping.SplitEmptyFunction = false; + Expanded.BraceWrapping.SplitEmptyRecord = false; break; case FormatStyle::BS_Stroustrup: Expanded.BraceWrapping.AfterFunction = true; @@ -523,7 +526,8 @@ static FormatStyle expandPresets(const FormatStyle &Style) { break; case FormatStyle::BS_GNU: Expanded.BraceWrapping = {true, true, true, true, true, true, - true, true, true, true, true, true}; + true, true, true, true, true, true, + true, true}; break; case FormatStyle::BS_WebKit: Expanded.BraceWrapping.AfterFunction = true; @@ -560,7 +564,8 @@ FormatStyle getLLVMStyle() { LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; LLVMStyle.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false, true}; + false, false, false, false, false, true, + true, true}; LLVMStyle.BreakAfterJavaFieldAnnotations = false; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; LLVMStyle.BreakBeforeInheritanceComma = false; @@ -579,9 +584,9 @@ FormatStyle getLLVMStyle() { LLVMStyle.ForEachMacros.push_back("Q_FOREACH"); LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH"); LLVMStyle.IncludeCategories = {{"^\"(llvm|llvm-c|clang|clang-c)/", 2}, - {"^(<|\"(gtest|isl|json)/)", 3}, + {"^(<|\"(gtest|gmock|isl|json)/)", 3}, {".*", 1}}; - LLVMStyle.IncludeIsMainRegex = "$"; + LLVMStyle.IncludeIsMainRegex = "(Test)?$"; LLVMStyle.IndentCaseLabels = false; LLVMStyle.IndentWrappedFunctionNames = false; LLVMStyle.IndentWidth = 2; @@ -1409,7 +1414,7 @@ public: : Style(Style), FileName(FileName) { FileStem = llvm::sys::path::stem(FileName); for (const auto &Category : Style.IncludeCategories) - CategoryRegexs.emplace_back(Category.Regex); + CategoryRegexs.emplace_back(Category.Regex, llvm::Regex::IgnoreCase); IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") || FileName.endswith(".cpp") || FileName.endswith(".c++") || FileName.endswith(".cxx") || FileName.endswith(".m") || @@ -1437,9 +1442,11 @@ private: return false; StringRef HeaderStem = llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1)); - if (FileStem.startswith(HeaderStem)) { + if (FileStem.startswith(HeaderStem) || + FileStem.startswith_lower(HeaderStem)) { llvm::Regex MainIncludeRegex( - (HeaderStem + Style.IncludeIsMainRegex).str()); + (HeaderStem + Style.IncludeIsMainRegex).str(), + llvm::Regex::IgnoreCase); if (MainIncludeRegex.match(FileStem)) return true; } diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index c5bf48cdcc06..0fe91adcd472 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -465,7 +465,8 @@ struct FormatToken { return is(TT_ArrayInitializerLSquare) || (is(tok::l_brace) && (BlockKind == BK_Block || is(TT_DictLiteral) || - (!Style.Cpp11BracedListStyle && NestingLevel == 0))); + (!Style.Cpp11BracedListStyle && NestingLevel == 0))) || + (is(tok::less) && Style.Language == FormatStyle::LK_Proto); } /// \brief Same as opensBlockOrBlockTypeList, but for the closing token. @@ -475,6 +476,19 @@ struct FormatToken { return MatchingParen && MatchingParen->opensBlockOrBlockTypeList(Style); } + /// \brief Return the actual namespace token, if this token starts a namespace + /// block. + const FormatToken *getNamespaceToken() const { + const FormatToken *NamespaceTok = this; + if (is(tok::comment)) + NamespaceTok = NamespaceTok->getNextNonComment(); + // Detect "(inline)? namespace" in the beginning of a line. + if (NamespaceTok && NamespaceTok->is(tok::kw_inline)) + NamespaceTok = NamespaceTok->getNextNonComment(); + return NamespaceTok && NamespaceTok->is(tok::kw_namespace) ? NamespaceTok + : nullptr; + } + private: // Disallow copying. FormatToken(const FormatToken &) = delete; diff --git a/lib/Format/NamespaceEndCommentsFixer.cpp b/lib/Format/NamespaceEndCommentsFixer.cpp index 1bbb41f757ae..85b70b8c0a76 100644 --- a/lib/Format/NamespaceEndCommentsFixer.cpp +++ b/lib/Format/NamespaceEndCommentsFixer.cpp @@ -174,7 +174,7 @@ tooling::Replacements NamespaceEndCommentsFixer::analyze( AllNamespaceNames = "::" + NamespaceName + AllNamespaceNames; continue; } - NamespaceName += std::move(AllNamespaceNames); + NamespaceName += AllNamespaceNames; CompactedNamespacesCount = 0; AllNamespaceNames = std::string(); } diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 505f42ec9a06..d78a37532fe8 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -89,7 +89,8 @@ private: continue; } if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) || - (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext)) + (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext && + Style.Language != FormatStyle::LK_Proto)) return false; // If a && or || is found and interpreted as a binary operator, this set // of angles is likely part of something like "a < b && c > d". If the @@ -103,6 +104,14 @@ private: !Line.startsWith(tok::kw_template)) return false; updateParameterCount(Left, CurrentToken); + if (Style.Language == FormatStyle::LK_Proto) { + if (FormatToken *Previous = CurrentToken->getPreviousNonComment()) { + if (CurrentToken->is(tok::colon) || + (CurrentToken->isOneOf(tok::l_brace, tok::less) && + Previous->isNot(tok::colon))) + Previous->Type = TT_SelectorName; + } + } if (!consumeToken()) return false; } @@ -440,7 +449,7 @@ private: if (CurrentToken->isOneOf(tok::r_paren, tok::r_square)) return false; updateParameterCount(Left, CurrentToken); - if (CurrentToken->isOneOf(tok::colon, tok::l_brace)) { + if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) { FormatToken *Previous = CurrentToken->getPreviousNonComment(); if (((CurrentToken->is(tok::colon) && (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) || @@ -1561,8 +1570,10 @@ private: const FormatToken *NextNonComment = Current->getNextNonComment(); if (Current->is(TT_ConditionalExpr)) return prec::Conditional; - if (NextNonComment && NextNonComment->is(tok::colon) && - NextNonComment->is(TT_DictLiteral)) + if (NextNonComment && Current->is(TT_SelectorName) && + (NextNonComment->is(TT_DictLiteral) || + (Style.Language == FormatStyle::LK_Proto && + NextNonComment->is(tok::less)))) return prec::Assignment; if (Current->is(TT_JsComputedPropertyName)) return prec::Assignment; @@ -2549,10 +2560,16 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, // deliberate choice and might have aligned the contents of the string // literal accordingly. Thus, we try keep existing line breaks. return Right.NewlinesBefore > 0; - if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 && - Style.Language == FormatStyle::LK_Proto) - // Don't put enums onto single lines in protocol buffers. + if ((Right.Previous->is(tok::l_brace) || + (Right.Previous->is(tok::less) && + Right.Previous->Previous && + Right.Previous->Previous->is(tok::equal)) + ) && + Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) { + // Don't put enums or option definitions onto single lines in protocol + // buffers. return true; + } if (Right.is(TT_InlineASMBrace)) return Right.HasUnescapedNewline; if (isAllmanBrace(Left) || isAllmanBrace(Right)) diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp index 8836c07cac71..2005a2822924 100644 --- a/lib/Format/UnwrappedLineFormatter.cpp +++ b/lib/Format/UnwrappedLineFormatter.cpp @@ -136,10 +136,7 @@ private: bool isNamespaceDeclaration(const AnnotatedLine *Line) { const FormatToken *NamespaceTok = Line->First; - // Detect "(inline)? namespace" in the beginning of a line. - if (NamespaceTok->is(tok::kw_inline)) - NamespaceTok = NamespaceTok->getNextNonComment(); - return NamespaceTok && NamespaceTok->is(tok::kw_namespace); + return NamespaceTok && NamespaceTok->getNamespaceToken(); } bool isEndOfNamespace(const AnnotatedLine *Line, @@ -216,10 +213,31 @@ private: if (TheLine->Last->is(TT_FunctionLBrace) && TheLine->First == TheLine->Last && - !Style.BraceWrapping.SplitEmptyFunctionBody && + !Style.BraceWrapping.SplitEmptyFunction && I[1]->First->is(tok::r_brace)) return tryMergeSimpleBlock(I, E, Limit); + // Handle empty record blocks where the brace has already been wrapped + if (TheLine->Last->is(tok::l_brace) && TheLine->First == TheLine->Last && + I != AnnotatedLines.begin()) { + bool EmptyBlock = I[1]->First->is(tok::r_brace); + + const FormatToken *Tok = I[-1]->First; + if (Tok && Tok->is(tok::comment)) + Tok = Tok->getNextNonComment(); + + if (Tok && Tok->getNamespaceToken()) + return !Style.BraceWrapping.SplitEmptyNamespace && EmptyBlock + ? tryMergeSimpleBlock(I, E, Limit) : 0; + + if (Tok && Tok->is(tok::kw_typedef)) + Tok = Tok->getNextNonComment(); + if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union, + Keywords.kw_interface)) + return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock + ? tryMergeSimpleBlock(I, E, Limit) : 0; + } + // FIXME: TheLine->Level != 0 might or might not be the right check to do. // If necessary, change to something smarter. bool MergeShortFunctions = diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index f7678bb6b2a5..ba3a4c17ee12 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -1176,9 +1176,12 @@ void UnwrappedLineParser::parseStructuralElement() { } nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) { + if (FormatTok->Tok.is(tok::l_brace)) parseBracedList(); - } + else if (Style.Language == FormatStyle::LK_Proto && + FormatTok->Tok.is(tok::less)) + parseBracedList(/*ContinueOnSemicolons=*/false, + /*ClosingBraceKind=*/tok::greater); break; case tok::l_square: parseSquare(); @@ -1346,7 +1349,8 @@ bool UnwrappedLineParser::tryToParseBracedList() { return true; } -bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) { +bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, + tok::TokenKind ClosingBraceKind) { bool HasError = false; nextToken(); @@ -1375,6 +1379,10 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) { parseChildBlock(); } } + if (FormatTok->Tok.getKind() == ClosingBraceKind) { + nextToken(); + return !HasError; + } switch (FormatTok->Tok.getKind()) { case tok::caret: nextToken(); @@ -1401,9 +1409,6 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) { FormatTok->BlockKind = BK_BracedInit; parseBracedList(); break; - case tok::r_brace: - nextToken(); - return !HasError; case tok::semi: // JavaScript (or more precisely TypeScript) can have semicolons in braced // lists (in so-called TypeMemberLists). Thus, the semicolon cannot be diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h index 15d1d9cda7a2..a2aa2f006728 100644 --- a/lib/Format/UnwrappedLineParser.h +++ b/lib/Format/UnwrappedLineParser.h @@ -93,7 +93,8 @@ private: void readTokenWithJavaScriptASI(); void parseStructuralElement(); bool tryToParseBracedList(); - bool parseBracedList(bool ContinueOnSemicolons = false); + bool parseBracedList(bool ContinueOnSemicolons = false, + tok::TokenKind ClosingBraceKind = tok::r_brace); void parseParens(); void parseSquare(); void parseIfThenElse(); diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp index 986f98ae598b..354527db7bad 100644 --- a/lib/Frontend/ASTMerge.cpp +++ b/lib/Frontend/ASTMerge.cpp @@ -44,9 +44,9 @@ void ASTMergeAction::ExecuteAction() { new ForwardingDiagnosticConsumer( *CI.getDiagnostics().getClient()), /*ShouldOwnClient=*/true)); - std::unique_ptr<ASTUnit> Unit = - ASTUnit::LoadFromASTFile(ASTFiles[I], CI.getPCHContainerReader(), - Diags, CI.getFileSystemOpts(), false); + std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile( + ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags, + CI.getFileSystemOpts(), false); if (!Unit) continue; diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 1f34f10f55af..1094e6d089a6 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -458,7 +458,7 @@ namespace { /// a Preprocessor. class ASTInfoCollector : public ASTReaderListener { Preprocessor &PP; - ASTContext &Context; + ASTContext *Context; HeaderSearchOptions &HSOpts; PreprocessorOptions &PPOpts; LangOptions &LangOpt; @@ -468,7 +468,7 @@ class ASTInfoCollector : public ASTReaderListener { bool InitializedLanguage; public: - ASTInfoCollector(Preprocessor &PP, ASTContext &Context, + ASTInfoCollector(Preprocessor &PP, ASTContext *Context, HeaderSearchOptions &HSOpts, PreprocessorOptions &PPOpts, LangOptions &LangOpt, std::shared_ptr<TargetOptions> &TargetOpts, @@ -536,12 +536,15 @@ private: // Initialize the preprocessor. PP.Initialize(*Target); + if (!Context) + return; + // Initialize the ASTContext - Context.InitBuiltinTypes(*Target); + Context->InitBuiltinTypes(*Target); // We didn't have access to the comment options when the ASTContext was // constructed, so register them now. - Context.getCommentCommandTraits().registerCommentOptions( + Context->getCommentCommandTraits().registerCommentOptions( LangOpt.CommentOpts); } }; @@ -671,7 +674,7 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags, std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( const std::string &Filename, const PCHContainerReader &PCHContainerRdr, - IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, const FileSystemOptions &FileSystemOpts, bool UseDebugInfo, bool OnlyLocalDecls, ArrayRef<RemappedFile> RemappedFiles, bool CaptureDiagnostics, bool AllowPCHWithCompilerErrors, @@ -722,21 +725,21 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( /*OwnsHeaderSearch=*/false); Preprocessor &PP = *AST->PP; - AST->Ctx = new ASTContext(*AST->LangOpts, AST->getSourceManager(), - PP.getIdentifierTable(), PP.getSelectorTable(), - PP.getBuiltinInfo()); - ASTContext &Context = *AST->Ctx; + if (ToLoad >= LoadASTOnly) + AST->Ctx = new ASTContext(*AST->LangOpts, AST->getSourceManager(), + PP.getIdentifierTable(), PP.getSelectorTable(), + PP.getBuiltinInfo()); bool disableValid = false; if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION")) disableValid = true; - AST->Reader = new ASTReader(PP, Context, PCHContainerRdr, { }, + AST->Reader = new ASTReader(PP, AST->Ctx.get(), PCHContainerRdr, { }, /*isysroot=*/"", /*DisableValidation=*/disableValid, AllowPCHWithCompilerErrors); AST->Reader->setListener(llvm::make_unique<ASTInfoCollector>( - *AST->PP, Context, *AST->HSOpts, *AST->PPOpts, *AST->LangOpts, + *AST->PP, AST->Ctx.get(), *AST->HSOpts, *AST->PPOpts, *AST->LangOpts, AST->TargetOpts, AST->Target, Counter)); // Attach the AST reader to the AST context as an external AST @@ -744,7 +747,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( // AST file as needed. // We need the external source to be set up before we read the AST, because // eagerly-deserialized declarations may use it. - Context.setExternalSource(AST->Reader); + if (AST->Ctx) + AST->Ctx->setExternalSource(AST->Reader); switch (AST->Reader->ReadAST(Filename, serialization::MK_MainFile, SourceLocation(), ASTReader::ARR_None)) { @@ -766,15 +770,18 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( PP.setCounterValue(Counter); // Create an AST consumer, even though it isn't used. - AST->Consumer.reset(new ASTConsumer); - + if (ToLoad >= LoadASTOnly) + AST->Consumer.reset(new ASTConsumer); + // Create a semantic analysis object and tell the AST reader about it. - AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer)); - AST->TheSema->Initialize(); - AST->Reader->InitializeSema(*AST->TheSema); + if (ToLoad >= LoadEverything) { + AST->TheSema.reset(new Sema(PP, *AST->Ctx, *AST->Consumer)); + AST->TheSema->Initialize(); + AST->Reader->InitializeSema(*AST->TheSema); + } // Tell the diagnostic client that we have started a source file. - AST->getDiagnostics().getClient()->BeginSourceFile(Context.getLangOpts(),&PP); + AST->getDiagnostics().getClient()->BeginSourceFile(PP.getLangOpts(), &PP); return AST; } @@ -1638,7 +1645,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine( &StoredDiagnostics, nullptr); CI = clang::createInvocationFromCommandLine( - llvm::makeArrayRef(ArgBegin, ArgEnd), Diags); + llvm::makeArrayRef(ArgBegin, ArgEnd), Diags, VFS); if (!CI) return nullptr; } diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp index b984c2ed0dd5..534c7587f48d 100644 --- a/lib/Frontend/ChainedIncludesSource.cpp +++ b/lib/Frontend/ChainedIncludesSource.cpp @@ -83,7 +83,7 @@ createASTReader(CompilerInstance &CI, StringRef pchFile, ASTDeserializationListener *deserialListener = nullptr) { Preprocessor &PP = CI.getPreprocessor(); std::unique_ptr<ASTReader> Reader; - Reader.reset(new ASTReader(PP, CI.getASTContext(), + Reader.reset(new ASTReader(PP, &CI.getASTContext(), CI.getPCHContainerReader(), /*Extensions=*/{ }, /*isysroot=*/"", /*DisableValidation=*/true)); diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index e5da2ae4f22e..bb6a665cb456 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -517,7 +517,7 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource( HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); IntrusiveRefCntPtr<ASTReader> Reader(new ASTReader( - PP, Context, PCHContainerRdr, Extensions, + PP, &Context, PCHContainerRdr, Extensions, Sysroot.empty() ? "" : Sysroot.data(), DisablePCHValidation, AllowPCHWithCompilerErrors, /*AllowConfigurationMismatch*/ false, HSOpts.ModulesValidateSystemHeaders, UseGlobalModuleIndex)); @@ -825,8 +825,11 @@ bool CompilerInstance::InitializeSourceManager( const FrontendInputFile &Input, DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, HeaderSearch *HS, DependencyOutputOptions &DepOpts, const FrontendOptions &Opts) { - SrcMgr::CharacteristicKind - Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; + SrcMgr::CharacteristicKind Kind = + Input.getKind().getFormat() == InputKind::ModuleMap + ? Input.isSystem() ? SrcMgr::C_System_ModuleMap + : SrcMgr::C_User_ModuleMap + : Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; if (Input.isBuffer()) { SourceMgr.setMainFileID(SourceMgr.createFileID( @@ -933,8 +936,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { if (!hasTarget()) return false; - // Create TargetInfo for the other side of CUDA compilation. - if (getLangOpts().CUDA && !getFrontendOpts().AuxTriple.empty()) { + // Create TargetInfo for the other side of CUDA and OpenMP compilation. + if ((getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) && + !getFrontendOpts().AuxTriple.empty()) { auto TO = std::make_shared<TargetOptions>(); TO->Triple = getFrontendOpts().AuxTriple; TO->HostTriple = getTarget().getTriple().str(); @@ -1469,7 +1473,7 @@ void CompilerInstance::createModuleManager() { "Reading modules", *FrontendTimerGroup); ModuleManager = new ASTReader( - getPreprocessor(), getASTContext(), getPCHContainerReader(), + getPreprocessor(), &getASTContext(), getPCHContainerReader(), getFrontendOpts().ModuleFileExtensions, Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation, /*AllowASTWithCompilerErrors=*/false, diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 6254b0013bab..00f6b9b46f03 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -476,6 +476,10 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, OPT_fexperimental_new_pass_manager, OPT_fno_experimental_new_pass_manager, /* Default */ false); + Opts.DebugPassManager = + Args.hasFlag(OPT_fdebug_pass_manager, OPT_fno_debug_pass_manager, + /* Default */ false); + if (Arg *A = Args.getLastArg(OPT_fveclib)) { StringRef Name = A->getValue(); if (Name == "Accelerate") @@ -668,7 +672,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.MSVolatile = Args.hasArg(OPT_fms_volatile); - Opts.VectorizeBB = Args.hasArg(OPT_vectorize_slp_aggressive); Opts.VectorizeLoop = Args.hasArg(OPT_vectorize_loops); Opts.VectorizeSLP = Args.hasArg(OPT_vectorize_slp); @@ -906,12 +909,18 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DiagnosticsWithHotness = Args.hasArg(options::OPT_fdiagnostics_show_hotness); bool UsingSampleProfile = !Opts.SampleProfileFile.empty(); + bool UsingProfile = UsingSampleProfile || + (Opts.getProfileUse() != CodeGenOptions::ProfileNone); - if (Opts.DiagnosticsWithHotness && - Opts.getProfileUse() == CodeGenOptions::ProfileNone && - !UsingSampleProfile) { - Diags.Report(diag::warn_drv_fdiagnostics_show_hotness_requires_pgo); - } + if (Opts.DiagnosticsWithHotness && !UsingProfile) + Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo) + << "-fdiagnostics-show-hotness"; + + Opts.DiagnosticsHotnessThreshold = getLastArgUInt64Value( + Args, options::OPT_fdiagnostics_hotness_threshold_EQ, 0); + if (Opts.DiagnosticsHotnessThreshold > 0 && !UsingProfile) + Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo) + << "-fdiagnostics-hotness-threshold="; // If the user requested to use a sample profile for PGO, then the // backend will need to track source location information so the profile @@ -2106,6 +2115,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.AlignedAllocation = Args.hasFlag(OPT_faligned_allocation, OPT_fno_aligned_allocation, Opts.AlignedAllocation); + Opts.AlignedAllocationUnavailable = + Opts.AlignedAllocation && Args.hasArg(OPT_aligned_alloc_unavailable); Opts.NewAlignOverride = getLastArgIntValue(Args, OPT_fnew_alignment_EQ, 0, Diags); if (Opts.NewAlignOverride && !llvm::isPowerOf2_32(Opts.NewAlignOverride)) { @@ -2557,7 +2568,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args, Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Value; else - Opts.EABIVersion = Value; + Opts.EABIVersion = EABIVersion; } Opts.CPU = Args.getLastArgValue(OPT_target_cpu); Opts.FPMath = Args.getLastArgValue(OPT_mfpmath); @@ -2644,6 +2655,10 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple; } + // Set the triple of the host for OpenMP device compile. + if (LangOpts.OpenMPIsDevice) + Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple; + // FIXME: Override value name discarding when asan or msan is used because the // backend passes depend on the name of the alloca in order to print out // names. diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp index 49d459e78c45..c3ce7ce2b742 100644 --- a/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -31,8 +31,8 @@ using namespace llvm::opt; /// \return A CompilerInvocation, or 0 if none was built for the given /// argument vector. std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine( - ArrayRef<const char *> ArgList, - IntrusiveRefCntPtr<DiagnosticsEngine> Diags) { + ArrayRef<const char *> ArgList, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { if (!Diags.get()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -46,7 +46,7 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine( // FIXME: We shouldn't have to pass in the path info. driver::Driver TheDriver(Args[0], llvm::sys::getDefaultTargetTriple(), - *Diags); + *Diags, VFS); // Don't check that inputs exist, they may have been remapped. TheDriver.setCheckInputsExist(false); diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp index bd14c53e4d15..561eb9c4a316 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -55,8 +55,8 @@ struct DepCollectorPPCallbacks : public PPCallbacks { llvm::sys::path::remove_leading_dotslash(FE->getName()); DepCollector.maybeAddDependency(Filename, /*FromModule*/false, - FileType != SrcMgr::C_User, - /*IsModuleFile*/false, /*IsMissing*/false); + isSystem(FileType), + /*IsModuleFile*/false, /*IsMissing*/false); } void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, @@ -265,7 +265,7 @@ bool DFGImpl::FileMatchesDepCriteria(const char *Filename, if (IncludeSystemHeaders) return true; - return FileType == SrcMgr::C_User; + return !isSystem(FileType); } void DFGImpl::FileChanged(SourceLocation Loc, diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp index 177feac97441..e3263843e29b 100644 --- a/lib/Frontend/DiagnosticRenderer.cpp +++ b/lib/Frontend/DiagnosticRenderer.cpp @@ -76,20 +76,19 @@ static void mergeFixits(ArrayRef<FixItHint> FixItHints, } } -void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, +void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> FixItHints, - const SourceManager *SM, DiagOrStoredDiag D) { - assert(SM || Loc.isInvalid()); + assert(Loc.hasManager() || Loc.isInvalid()); beginDiagnostic(D, Level); if (!Loc.isValid()) // If we have no source location, just emit the diagnostic message. - emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, SM, D); + emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, D); else { // Get the ranges into a local array we can hack on. SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(), @@ -97,7 +96,7 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, SmallVector<FixItHint, 8> MergedFixits; if (!FixItHints.empty()) { - mergeFixits(FixItHints, *SM, LangOpts, MergedFixits); + mergeFixits(FixItHints, Loc.getManager(), LangOpts, MergedFixits); FixItHints = MergedFixits; } @@ -107,25 +106,25 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, if (I->RemoveRange.isValid()) MutableRanges.push_back(I->RemoveRange); - SourceLocation UnexpandedLoc = Loc; + FullSourceLoc UnexpandedLoc = Loc; // Find the ultimate expansion location for the diagnostic. - Loc = SM->getFileLoc(Loc); + Loc = Loc.getFileLoc(); - PresumedLoc PLoc = SM->getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); + PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc); // First, if this diagnostic is not in the main file, print out the // "included from" lines. - emitIncludeStack(Loc, PLoc, Level, *SM); + emitIncludeStack(Loc, PLoc, Level); // Next, emit the actual diagnostic message and caret. - emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D); - emitCaret(Loc, Level, MutableRanges, FixItHints, *SM); + emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D); + emitCaret(Loc, Level, MutableRanges, FixItHints); // If this location is within a macro, walk from UnexpandedLoc up to Loc // and produce a macro backtrace. if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) { - emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM); + emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints); } } @@ -139,15 +138,12 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) { emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(), Diag.getRanges(), Diag.getFixIts(), - Diag.getLocation().isValid() ? &Diag.getLocation().getManager() - : nullptr, &Diag); } void DiagnosticRenderer::emitBasicNote(StringRef Message) { - emitDiagnosticMessage( - SourceLocation(), PresumedLoc(), DiagnosticsEngine::Note, Message, - None, nullptr, DiagOrStoredDiag()); + emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note, + Message, None, DiagOrStoredDiag()); } /// \brief Prints an include stack when appropriate for a particular @@ -161,12 +157,11 @@ void DiagnosticRenderer::emitBasicNote(StringRef Message) { /// \param Loc The diagnostic location. /// \param PLoc The presumed location of the diagnostic location. /// \param Level The diagnostic level of the message this stack pertains to. -void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, - PresumedLoc PLoc, - DiagnosticsEngine::Level Level, - const SourceManager &SM) { - SourceLocation IncludeLoc = - PLoc.isInvalid() ? SourceLocation() : PLoc.getIncludeLoc(); +void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level) { + FullSourceLoc IncludeLoc = + PLoc.isInvalid() ? FullSourceLoc() + : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager()); // Skip redundant include stacks altogether. if (LastIncludeLoc == IncludeLoc) @@ -178,74 +173,70 @@ void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, return; if (IncludeLoc.isValid()) - emitIncludeStackRecursively(IncludeLoc, SM); + emitIncludeStackRecursively(IncludeLoc); else { - emitModuleBuildStack(SM); - emitImportStack(Loc, SM); + emitModuleBuildStack(Loc.getManager()); + emitImportStack(Loc); } } /// \brief Helper to recursivly walk up the include stack and print each layer /// on the way back down. -void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, - const SourceManager &SM) { +void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) { if (Loc.isInvalid()) { - emitModuleBuildStack(SM); + emitModuleBuildStack(Loc.getManager()); return; } - - PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); + + PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc); if (PLoc.isInvalid()) return; // If this source location was imported from a module, print the module // import stack rather than the // FIXME: We want submodule granularity here. - std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc); + std::pair<FullSourceLoc, StringRef> Imported = Loc.getModuleImportLoc(); if (!Imported.second.empty()) { // This location was imported by a module. Emit the module import stack. - emitImportStackRecursively(Imported.first, Imported.second, SM); + emitImportStackRecursively(Imported.first, Imported.second); return; } // Emit the other include frames first. - emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM); - + emitIncludeStackRecursively( + FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager())); + // Emit the inclusion text/note. - emitIncludeLocation(Loc, PLoc, SM); + emitIncludeLocation(Loc, PLoc); } /// \brief Emit the module import stack associated with the current location. -void DiagnosticRenderer::emitImportStack(SourceLocation Loc, - const SourceManager &SM) { +void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc) { if (Loc.isInvalid()) { - emitModuleBuildStack(SM); + emitModuleBuildStack(Loc.getManager()); return; } - std::pair<SourceLocation, StringRef> NextImportLoc - = SM.getModuleImportLoc(Loc); - emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM); + std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc(); + emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second); } /// \brief Helper to recursivly walk up the import stack and print each layer /// on the way back down. -void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc, - StringRef ModuleName, - const SourceManager &SM) { +void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc, + StringRef ModuleName) { if (ModuleName.empty()) { return; } - PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); + PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc); // Emit the other import frames first. - std::pair<SourceLocation, StringRef> NextImportLoc - = SM.getModuleImportLoc(Loc); - emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM); + std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc(); + emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second); // Emit the inclusion text/note. - emitImportLocation(Loc, PLoc, ModuleName, SM); + emitImportLocation(Loc, PLoc, ModuleName); } /// \brief Emit the module build stack, for cases where a module is (re-)built @@ -253,13 +244,9 @@ void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc, void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) { ModuleBuildStack Stack = SM.getModuleBuildStack(); for (unsigned I = 0, N = Stack.size(); I != N; ++I) { - const SourceManager &CurSM = Stack[I].second.getManager(); - SourceLocation CurLoc = Stack[I].second; - emitBuildingModuleLocation(CurLoc, - CurSM.getPresumedLoc(CurLoc, + emitBuildingModuleLocation(Stack[I].second, Stack[I].second.getPresumedLoc( DiagOpts->ShowPresumedLoc), - Stack[I].first, - CurSM); + Stack[I].first); } } @@ -348,12 +335,12 @@ static void computeCommonMacroArgExpansionFileIDs( // in the same expansion as the caret; otherwise, we crawl to the top of // each chain. Two locations are part of the same macro expansion // iff the FileID is the same. -static void mapDiagnosticRanges( - SourceLocation CaretLoc, - ArrayRef<CharSourceRange> Ranges, - SmallVectorImpl<CharSourceRange> &SpellingRanges, - const SourceManager *SM) { - FileID CaretLocFileID = SM->getFileID(CaretLoc); +static void +mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef<CharSourceRange> Ranges, + SmallVectorImpl<CharSourceRange> &SpellingRanges) { + FileID CaretLocFileID = CaretLoc.getFileID(); + + const SourceManager *SM = &CaretLoc.getManager(); for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { if (I->isInvalid()) continue; @@ -404,42 +391,39 @@ static void mapDiagnosticRanges( } } -void DiagnosticRenderer::emitCaret(SourceLocation Loc, +void DiagnosticRenderer::emitCaret(FullSourceLoc Loc, DiagnosticsEngine::Level Level, ArrayRef<CharSourceRange> Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) { + ArrayRef<FixItHint> Hints) { SmallVector<CharSourceRange, 4> SpellingRanges; - mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); - emitCodeContext(Loc, Level, SpellingRanges, Hints, SM); + mapDiagnosticRanges(Loc, Ranges, SpellingRanges); + emitCodeContext(Loc, Level, SpellingRanges, Hints); } /// \brief A helper function for emitMacroExpansion to print the /// macro expansion message void DiagnosticRenderer::emitSingleMacroExpansion( - SourceLocation Loc, - DiagnosticsEngine::Level Level, - ArrayRef<CharSourceRange> Ranges, - const SourceManager &SM) { + FullSourceLoc Loc, DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges) { // Find the spelling location for the macro definition. We must use the // spelling location here to avoid emitting a macro backtrace for the note. - SourceLocation SpellingLoc = SM.getSpellingLoc(Loc); + FullSourceLoc SpellingLoc = Loc.getSpellingLoc(); // Map the ranges into the FileID of the diagnostic location. SmallVector<CharSourceRange, 4> SpellingRanges; - mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); + mapDiagnosticRanges(Loc, Ranges, SpellingRanges); SmallString<100> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); - StringRef MacroName = - Lexer::getImmediateMacroNameForDiagnostics(Loc, SM, LangOpts); + StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( + Loc, Loc.getManager(), LangOpts); if (MacroName.empty()) Message << "expanded from here"; else Message << "expanded from macro '" << MacroName << "'"; emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(), - SpellingRanges, None, &SM); + SpellingRanges, None); } /// Check that the macro argument location of Loc starts with ArgumentLoc. @@ -473,13 +457,12 @@ static bool checkRangeForMacroArgExpansion(CharSourceRange Range, /// A helper function to check if the current ranges are all inside the same /// macro argument expansion as Loc. -static bool checkRangesForMacroArgExpansion(SourceLocation Loc, - ArrayRef<CharSourceRange> Ranges, - const SourceManager &SM) { +static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc, + ArrayRef<CharSourceRange> Ranges) { assert(Loc.isMacroID() && "Must be a macro expansion!"); SmallVector<CharSourceRange, 4> SpellingRanges; - mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); + mapDiagnosticRanges(Loc, Ranges, SpellingRanges); /// Count all valid ranges. unsigned ValidCount = 0; @@ -490,15 +473,15 @@ static bool checkRangesForMacroArgExpansion(SourceLocation Loc, return false; /// To store the source location of the argument location. - SourceLocation ArgumentLoc; + FullSourceLoc ArgumentLoc; /// Set the ArgumentLoc to the beginning location of the expansion of Loc /// so to check if the ranges expands to the same beginning location. - if (!SM.isMacroArgExpansion(Loc,&ArgumentLoc)) + if (!Loc.isMacroArgExpansion(&ArgumentLoc)) return false; for (auto I = SpellingRanges.begin(), E = SpellingRanges.end(); I != E; ++I) { - if (!checkRangeForMacroArgExpansion(*I, SM, ArgumentLoc)) + if (!checkRangeForMacroArgExpansion(*I, Loc.getManager(), ArgumentLoc)) return false; } @@ -516,34 +499,33 @@ static bool checkRangesForMacroArgExpansion(SourceLocation Loc, /// \param Level The diagnostic level currently being emitted. /// \param Ranges The underlined ranges for this code snippet. /// \param Hints The FixIt hints active for this diagnostic. -void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, +void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc, DiagnosticsEngine::Level Level, ArrayRef<CharSourceRange> Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) { + ArrayRef<FixItHint> Hints) { assert(Loc.isValid() && "must have a valid source location here"); // Produce a stack of macro backtraces. - SmallVector<SourceLocation, 8> LocationStack; + SmallVector<FullSourceLoc, 8> LocationStack; unsigned IgnoredEnd = 0; while (Loc.isMacroID()) { // If this is the expansion of a macro argument, point the caret at the // use of the argument in the definition of the macro, not the expansion. - if (SM.isMacroArgExpansion(Loc)) - LocationStack.push_back(SM.getImmediateExpansionRange(Loc).first); + if (Loc.isMacroArgExpansion()) + LocationStack.push_back(Loc.getImmediateExpansionRange().first); else LocationStack.push_back(Loc); - if (checkRangesForMacroArgExpansion(Loc, Ranges, SM)) + if (checkRangesForMacroArgExpansion(Loc, Ranges)) IgnoredEnd = LocationStack.size(); - Loc = SM.getImmediateMacroCallerLoc(Loc); + Loc = Loc.getImmediateMacroCallerLoc(); // Once the location no longer points into a macro, try stepping through // the last found location. This sometimes produces additional useful // backtraces. if (Loc.isFileID()) - Loc = SM.getImmediateMacroCallerLoc(LocationStack.back()); + Loc = LocationStack.back().getImmediateMacroCallerLoc(); assert(Loc.isValid() && "must have a valid source location here"); } @@ -555,7 +537,7 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, if (MacroDepth <= MacroLimit || MacroLimit == 0) { for (auto I = LocationStack.rbegin(), E = LocationStack.rend(); I != E; ++I) - emitSingleMacroExpansion(*I, Level, Ranges, SM); + emitSingleMacroExpansion(*I, Level, Ranges); return; } @@ -565,7 +547,7 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, for (auto I = LocationStack.rbegin(), E = LocationStack.rbegin() + MacroStartMessages; I != E; ++I) - emitSingleMacroExpansion(*I, Level, Ranges, SM); + emitSingleMacroExpansion(*I, Level, Ranges); SmallString<200> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); @@ -577,26 +559,24 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, for (auto I = LocationStack.rend() - MacroEndMessages, E = LocationStack.rend(); I != E; ++I) - emitSingleMacroExpansion(*I, Level, Ranges, SM); + emitSingleMacroExpansion(*I, Level, Ranges); } DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {} -void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc, - PresumedLoc PLoc, - const SourceManager &SM) { +void DiagnosticNoteRenderer::emitIncludeLocation(FullSourceLoc Loc, + PresumedLoc PLoc) { // Generate a note indicating the include location. SmallString<200> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); Message << "in file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; - emitNote(Loc, Message.str(), &SM); + emitNote(Loc, Message.str()); } -void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc, +void DiagnosticNoteRenderer::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) { + StringRef ModuleName) { // Generate a note indicating the include location. SmallString<200> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); @@ -605,14 +585,12 @@ void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc, Message << "' imported from " << PLoc.getFilename() << ':' << PLoc.getLine(); Message << ":"; - emitNote(Loc, Message.str(), &SM); + emitNote(Loc, Message.str()); } -void -DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc, - PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) { +void DiagnosticNoteRenderer::emitBuildingModuleLocation(FullSourceLoc Loc, + PresumedLoc PLoc, + StringRef ModuleName) { // Generate a note indicating the include location. SmallString<200> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); @@ -621,5 +599,5 @@ DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc, << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; else Message << "while building module '" << ModuleName << "':"; - emitNote(Loc, Message.str(), &SM); + emitNote(Loc, Message.str()); } diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index f81a06b31869..704d51509851 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -200,12 +200,12 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, /// /// \param CI The compiler instance. /// \param InputFile Populated with the filename from the line marker. -/// \param AddLineNote If \c true, add a line note corresponding to this line -/// directive. Only use this if the directive will not actually be -/// visited by the preprocessor. +/// \param IsModuleMap If \c true, add a line note corresponding to this line +/// directive. (We need to do this because the directive will not be +/// visited by the preprocessor.) static SourceLocation ReadOriginalFileName(CompilerInstance &CI, std::string &InputFile, - bool AddLineNote = false) { + bool IsModuleMap = false) { auto &SourceMgr = CI.getSourceManager(); auto MainFileID = SourceMgr.getMainFileID(); @@ -231,7 +231,7 @@ static SourceLocation ReadOriginalFileName(CompilerInstance &CI, unsigned LineNo; SourceLocation LineNoLoc = T.getLocation(); - if (AddLineNote) { + if (IsModuleMap) { llvm::SmallString<16> Buffer; if (Lexer::getSpelling(LineNoLoc, Buffer, SourceMgr, CI.getLangOpts()) .getAsInteger(10, LineNo)) @@ -250,10 +250,10 @@ static SourceLocation ReadOriginalFileName(CompilerInstance &CI, return SourceLocation(); InputFile = Literal.GetString().str(); - if (AddLineNote) + if (IsModuleMap) CI.getSourceManager().AddLineNote( LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile), false, - false, SrcMgr::C_User); + false, SrcMgr::C_User_ModuleMap); return T.getLocation(); } @@ -403,7 +403,7 @@ static bool loadModuleMapForModuleBuild(CompilerInstance &CI, bool IsSystem, Offset = 0; if (IsPreprocessed) { SourceLocation EndOfLineMarker = - ReadOriginalFileName(CI, PresumedModuleMapFile, /*AddLineNote*/true); + ReadOriginalFileName(CI, PresumedModuleMapFile, /*IsModuleMap*/ true); if (EndOfLineMarker.isValid()) Offset = CI.getSourceManager().getDecomposedLoc(EndOfLineMarker).second; } @@ -536,8 +536,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false); std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile( - InputFile, CI.getPCHContainerReader(), ASTDiags, CI.getFileSystemOpts(), - CI.getCodeGenOpts().DebugTypeExtRefs); + InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly, + ASTDiags, CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs); if (!AST) goto failure; @@ -547,27 +547,36 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.getPreprocessorOpts() = AST->getPreprocessorOpts(); CI.getLangOpts() = AST->getLangOpts(); - // Preload all the module files loaded transitively by the AST unit. - if (auto ASTReader = AST->getASTReader()) { - auto &MM = ASTReader->getModuleManager(); - for (ModuleFile &MF : MM) - if (&MF != &MM.getPrimaryModule()) - CI.getFrontendOpts().ModuleFiles.push_back(MF.FileName); - } - // FIXME: Preload module maps loaded by the AST unit. - // Set the shared objects, these are reset when we finish processing the // file, otherwise the CompilerInstance will happily destroy them. CI.setFileManager(&AST->getFileManager()); CI.createSourceManager(CI.getFileManager()); CI.getSourceManager().initializeForReplay(AST->getSourceManager()); + // Preload all the module files loaded transitively by the AST unit. Also + // load all module map files that were parsed as part of building the AST + // unit. + if (auto ASTReader = AST->getASTReader()) { + auto &MM = ASTReader->getModuleManager(); + auto &PrimaryModule = MM.getPrimaryModule(); + + for (ModuleFile &MF : MM) + if (&MF != &PrimaryModule) + CI.getFrontendOpts().ModuleFiles.push_back(MF.FileName); + + ASTReader->visitTopLevelModuleMaps(PrimaryModule, + [&](const FileEntry *FE) { + CI.getFrontendOpts().ModuleMapFiles.push_back(FE->getName()); + }); + } + // Set up the input file for replay purposes. auto Kind = AST->getInputKind(); if (Kind.getFormat() == InputKind::ModuleMap) { Module *ASTModule = AST->getPreprocessor().getHeaderSearchInfo().lookupModule( AST->getLangOpts().CurrentModule, /*AllowSearch*/ false); + assert(ASTModule && "module file does not define its own module"); Input = FrontendInputFile(ASTModule->PresumedModuleMapFile, Kind); } else { auto &SM = CI.getSourceManager(); @@ -590,8 +599,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile( - InputFile, CI.getPCHContainerReader(), Diags, CI.getFileSystemOpts(), - CI.getCodeGenOpts().DebugTypeExtRefs); + InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags, + CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs); if (!AST) goto failure; diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 9621889b27ad..0fbcc1c7399e 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -230,7 +230,7 @@ void VerifyPCHAction::ExecuteAction() { bool Preamble = CI.getPreprocessorOpts().PrecompiledPreambleBytes.first != 0; const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot; std::unique_ptr<ASTReader> Reader(new ASTReader( - CI.getPreprocessor(), CI.getASTContext(), CI.getPCHContainerReader(), + CI.getPreprocessor(), &CI.getASTContext(), CI.getPCHContainerReader(), CI.getFrontendOpts().ModuleFileExtensions, Sysroot.empty() ? "" : Sysroot.c_str(), /*DisableValidation*/ false, diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 08befb33c962..71420df00025 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -1043,7 +1043,7 @@ void clang::InitializePreprocessor( if (InitOpts.UsePredefines) { // FIXME: This will create multiple definitions for most of the predefined // macros. This is not the right way to handle this. - if (LangOpts.CUDA && PP.getAuxTargetInfo()) + if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice) && PP.getAuxTargetInfo()) InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts, Builder); diff --git a/lib/Frontend/ModuleDependencyCollector.cpp b/lib/Frontend/ModuleDependencyCollector.cpp index 9b34d4211353..ede12aab6e69 100644 --- a/lib/Frontend/ModuleDependencyCollector.cpp +++ b/lib/Frontend/ModuleDependencyCollector.cpp @@ -248,7 +248,7 @@ std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src, // Always map a canonical src path to its real path into the YAML, by doing // this we map different virtual src paths to the same entry in the VFS // overlay, which is a way to emulate symlink inside the VFS; this is also - // needed for correctness, not doing that can lead to module redifinition + // needed for correctness, not doing that can lead to module redefinition // errors. addFileMapping(VirtualPath, CacheDst); return std::error_code(); diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp index b5a5acd8ad9a..7666fe10b381 100644 --- a/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -63,27 +63,20 @@ public: ~SDiagsRenderer() override {} protected: - void emitDiagnosticMessage(SourceLocation Loc, - PresumedLoc PLoc, - DiagnosticsEngine::Level Level, - StringRef Message, + void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, StringRef Message, ArrayRef<CharSourceRange> Ranges, - const SourceManager *SM, DiagOrStoredDiag D) override; - void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, + void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, - ArrayRef<CharSourceRange> Ranges, - const SourceManager &SM) override {} + ArrayRef<CharSourceRange> Ranges) override {} - void emitNote(SourceLocation Loc, StringRef Message, - const SourceManager *SM) override; + void emitNote(FullSourceLoc Loc, StringRef Message) override; - void emitCodeContext(SourceLocation Loc, - DiagnosticsEngine::Level Level, - SmallVectorImpl<CharSourceRange>& Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) override; + void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange> &Ranges, + ArrayRef<FixItHint> Hints) override; void beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level) override; @@ -193,11 +186,8 @@ private: void ExitDiagBlock(); /// \brief Emit a DIAG record. - void EmitDiagnosticMessage(SourceLocation Loc, - PresumedLoc PLoc, - DiagnosticsEngine::Level Level, - StringRef Message, - const SourceManager *SM, + void EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, StringRef Message, DiagOrStoredDiag D); /// \brief Emit FIXIT and SOURCE_RANGE records for a diagnostic. @@ -220,16 +210,14 @@ private: /// \brief Emit (lazily) the file string and retrieved the file identifier. unsigned getEmitFile(const char *Filename); - /// \brief Add SourceLocation information the specified record. - void AddLocToRecord(SourceLocation Loc, const SourceManager *SM, - PresumedLoc PLoc, RecordDataImpl &Record, - unsigned TokSize = 0); + /// \brief Add SourceLocation information the specified record. + void AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc, + RecordDataImpl &Record, unsigned TokSize = 0); /// \brief Add SourceLocation information the specified record. - void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record, - const SourceManager *SM, + void AddLocToRecord(FullSourceLoc Loc, RecordDataImpl &Record, unsigned TokSize = 0) { - AddLocToRecord(Loc, SM, SM ? SM->getPresumedLoc(Loc) : PresumedLoc(), + AddLocToRecord(Loc, Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(), Record, TokSize); } @@ -350,11 +338,8 @@ static void EmitRecordID(unsigned ID, const char *Name, Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); } -void SDiagsWriter::AddLocToRecord(SourceLocation Loc, - const SourceManager *SM, - PresumedLoc PLoc, - RecordDataImpl &Record, - unsigned TokSize) { +void SDiagsWriter::AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc, + RecordDataImpl &Record, unsigned TokSize) { if (PLoc.isInvalid()) { // Emit a "sentinel" location. Record.push_back((unsigned)0); // File. @@ -367,19 +352,19 @@ void SDiagsWriter::AddLocToRecord(SourceLocation Loc, Record.push_back(getEmitFile(PLoc.getFilename())); Record.push_back(PLoc.getLine()); Record.push_back(PLoc.getColumn()+TokSize); - Record.push_back(SM->getFileOffset(Loc)); + Record.push_back(Loc.getFileOffset()); } void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range, RecordDataImpl &Record, const SourceManager &SM) { - AddLocToRecord(Range.getBegin(), Record, &SM); + AddLocToRecord(FullSourceLoc(Range.getBegin(), SM), Record); unsigned TokSize = 0; if (Range.isTokenRange()) TokSize = Lexer::MeasureTokenLength(Range.getEnd(), SM, *LangOpts); - - AddLocToRecord(Range.getEnd(), Record, &SM, TokSize); + + AddLocToRecord(FullSourceLoc(Range.getEnd(), SM), Record, TokSize); } unsigned SDiagsWriter::getEmitFile(const char *FileName){ @@ -606,8 +591,8 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, if (DiagLevel == DiagnosticsEngine::Note) EnterDiagBlock(); - EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel, - State->diagBuf, nullptr, &Info); + EmitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagLevel, + State->diagBuf, &Info); if (DiagLevel == DiagnosticsEngine::Note) ExitDiagBlock(); @@ -618,12 +603,9 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, assert(Info.hasSourceManager() && LangOpts && "Unexpected diagnostic with valid location outside of a source file"); SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts); - Renderer.emitDiagnostic(Info.getLocation(), DiagLevel, - State->diagBuf, - Info.getRanges(), - Info.getFixItHints(), - &Info.getSourceManager(), - &Info); + Renderer.emitDiagnostic( + FullSourceLoc(Info.getLocation(), Info.getSourceManager()), DiagLevel, + State->diagBuf, Info.getRanges(), Info.getFixItHints(), &Info); } static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) { @@ -641,11 +623,9 @@ static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) { llvm_unreachable("invalid diagnostic level"); } -void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc, - PresumedLoc PLoc, +void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, StringRef Message, - const SourceManager *SM, DiagOrStoredDiag D) { llvm::BitstreamWriter &Stream = State->Stream; RecordData &Record = State->Record; @@ -655,7 +635,7 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc, Record.clear(); Record.push_back(RECORD_DIAG); Record.push_back(getStableLevel(Level)); - AddLocToRecord(Loc, SM, PLoc, Record); + AddLocToRecord(Loc, PLoc, Record); if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) { // Emit the category string lazily and get the category ID. @@ -672,15 +652,11 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc, Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message); } -void -SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc, - PresumedLoc PLoc, - DiagnosticsEngine::Level Level, - StringRef Message, - ArrayRef<clang::CharSourceRange> Ranges, - const SourceManager *SM, - DiagOrStoredDiag D) { - Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D); +void SDiagsRenderer::emitDiagnosticMessage( + FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, + StringRef Message, ArrayRef<clang::CharSourceRange> Ranges, + DiagOrStoredDiag D) { + Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, D); } void SDiagsWriter::EnterDiagBlock() { @@ -733,20 +709,18 @@ void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, } } -void SDiagsRenderer::emitCodeContext(SourceLocation Loc, +void SDiagsRenderer::emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, SmallVectorImpl<CharSourceRange> &Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) { - Writer.EmitCodeContext(Ranges, Hints, SM); + ArrayRef<FixItHint> Hints) { + Writer.EmitCodeContext(Ranges, Hints, Loc.getManager()); } -void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message, - const SourceManager *SM) { +void SDiagsRenderer::emitNote(FullSourceLoc Loc, StringRef Message) { Writer.EnterDiagBlock(); - PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc(); - Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, - Message, SM, DiagOrStoredDiag()); + PresumedLoc PLoc = Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(); + Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, Message, + DiagOrStoredDiag()); Writer.ExitDiagBlock(); } diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp index a24d5768f558..1e12ea5e597a 100644 --- a/lib/Frontend/TextDiagnostic.cpp +++ b/lib/Frontend/TextDiagnostic.cpp @@ -672,20 +672,16 @@ TextDiagnostic::TextDiagnostic(raw_ostream &OS, TextDiagnostic::~TextDiagnostic() {} -void -TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc, - PresumedLoc PLoc, - DiagnosticsEngine::Level Level, - StringRef Message, - ArrayRef<clang::CharSourceRange> Ranges, - const SourceManager *SM, - DiagOrStoredDiag D) { +void TextDiagnostic::emitDiagnosticMessage( + FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, + StringRef Message, ArrayRef<clang::CharSourceRange> Ranges, + DiagOrStoredDiag D) { uint64_t StartOfLocationInfo = OS.tell(); // Emit the location of this particular diagnostic. if (Loc.isValid()) - emitDiagnosticLoc(Loc, PLoc, Level, Ranges, *SM); - + emitDiagnosticLoc(Loc, PLoc, Level, Ranges); + if (DiagOpts->ShowColors) OS.resetColor(); @@ -787,17 +783,16 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) { /// This includes extracting as much location information as is present for /// the diagnostic and printing it, as well as any include stack or source /// ranges necessary. -void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, +void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, - ArrayRef<CharSourceRange> Ranges, - const SourceManager &SM) { + ArrayRef<CharSourceRange> Ranges) { if (PLoc.isInvalid()) { // At least print the file name if available: - FileID FID = SM.getFileID(Loc); + FileID FID = Loc.getFileID(); if (FID.isValid()) { - const FileEntry* FE = SM.getFileEntryForID(FID); + const FileEntry *FE = Loc.getFileEntry(); if (FE && FE->isValid()) { - emitFilename(FE->getName(), SM); + emitFilename(FE->getName(), Loc.getManager()); if (FE->isInPCH()) OS << " (in PCH)"; OS << ": "; @@ -813,7 +808,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); - emitFilename(PLoc.getFilename(), SM); + emitFilename(PLoc.getFilename(), Loc.getManager()); switch (DiagOpts->getFormat()) { case DiagnosticOptions::Clang: OS << ':' << LineNo; break; case DiagnosticOptions::MSVC: OS << '(' << LineNo; break; @@ -848,8 +843,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, } if (DiagOpts->ShowSourceRanges && !Ranges.empty()) { - FileID CaretFileID = - SM.getFileID(SM.getExpansionLoc(Loc)); + FileID CaretFileID = Loc.getExpansionLoc().getFileID(); bool PrintedRange = false; for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(), @@ -858,8 +852,10 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, // Ignore invalid ranges. if (!RI->isValid()) continue; - SourceLocation B = SM.getExpansionLoc(RI->getBegin()); - SourceLocation E = SM.getExpansionLoc(RI->getEnd()); + FullSourceLoc B = + FullSourceLoc(RI->getBegin(), Loc.getManager()).getExpansionLoc(); + FullSourceLoc E = + FullSourceLoc(RI->getEnd(), Loc.getManager()).getExpansionLoc(); // If the End location and the start location are the same and are a // macro location, then the range was something that came from a @@ -867,10 +863,12 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, // best we can do is to highlight the range. If this is a // function-like macro, we'd also like to highlight the arguments. if (B == E && RI->getEnd().isMacroID()) - E = SM.getExpansionRange(RI->getEnd()).second; + E = FullSourceLoc(RI->getEnd(), Loc.getManager()) + .getExpansionRange() + .second; - std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); - std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); + std::pair<FileID, unsigned> BInfo = B.getDecomposedLoc(); + std::pair<FileID, unsigned> EInfo = E.getDecomposedLoc(); // If the start or end of the range is in another file, just discard // it. @@ -881,13 +879,10 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, // tokens. unsigned TokSize = 0; if (RI->isTokenRange()) - TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts); + TokSize = Lexer::MeasureTokenLength(E, E.getManager(), LangOpts); - OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' - << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' - << SM.getLineNumber(EInfo.first, EInfo.second) << ':' - << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) - << '}'; + OS << '{' << B.getLineNumber() << ':' << B.getColumnNumber() << '-' + << E.getLineNumber() << ':' << (E.getColumnNumber() + TokSize) << '}'; PrintedRange = true; } @@ -897,9 +892,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, OS << ' '; } -void TextDiagnostic::emitIncludeLocation(SourceLocation Loc, - PresumedLoc PLoc, - const SourceManager &SM) { +void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) { if (DiagOpts->ShowLocation && PLoc.isValid()) OS << "In file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; @@ -907,9 +900,8 @@ void TextDiagnostic::emitIncludeLocation(SourceLocation Loc, OS << "In included file:\n"; } -void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) { +void TextDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, + StringRef ModuleName) { if (DiagOpts->ShowLocation && PLoc.isValid()) OS << "In module '" << ModuleName << "' imported from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; @@ -917,10 +909,9 @@ void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, OS << "In module '" << ModuleName << "':\n"; } -void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc, +void TextDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) { + StringRef ModuleName) { if (DiagOpts->ShowLocation && PLoc.isValid()) OS << "While building module '" << ModuleName << "' imported from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; @@ -1134,10 +1125,8 @@ static std::string buildFixItInsertionLine(unsigned LineNo, /// \param Ranges The underlined ranges for this code snippet. /// \param Hints The FixIt hints active for this diagnostic. void TextDiagnostic::emitSnippetAndCaret( - SourceLocation Loc, DiagnosticsEngine::Level Level, - SmallVectorImpl<CharSourceRange>& Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) { + FullSourceLoc Loc, DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange> &Ranges, ArrayRef<FixItHint> Hints) { assert(Loc.isValid() && "must have a valid source location here"); assert(Loc.isFileID() && "must have a file location here"); @@ -1154,18 +1143,18 @@ void TextDiagnostic::emitSnippetAndCaret( return; // Decompose the location into a FID/Offset pair. - std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + std::pair<FileID, unsigned> LocInfo = Loc.getDecomposedLoc(); FileID FID = LocInfo.first; - unsigned CaretFileOffset = LocInfo.second; + const SourceManager &SM = Loc.getManager(); // Get information about the buffer it points into. bool Invalid = false; - StringRef BufData = SM.getBufferData(FID, &Invalid); + StringRef BufData = Loc.getBufferData(&Invalid); if (Invalid) return; - unsigned CaretLineNo = SM.getLineNumber(FID, CaretFileOffset); - unsigned CaretColNo = SM.getColumnNumber(FID, CaretFileOffset); + unsigned CaretLineNo = Loc.getLineNumber(); + unsigned CaretColNo = Loc.getColumnNumber(); // Arbitrarily stop showing snippets when the line is too long. static const size_t MaxLineLengthToPrint = 4096; diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 17646b48e23d..5dd3252d5b1e 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -150,10 +150,9 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, "Unexpected diagnostic with no source manager"); assert(TextDiag && "Unexpected diagnostic outside source file processing"); - TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(), - Info.getRanges(), - Info.getFixItHints(), - &Info.getSourceManager()); + TextDiag->emitDiagnostic( + FullSourceLoc(Info.getLocation(), Info.getSourceManager()), Level, + DiagMessageStream.str(), Info.getRanges(), Info.getFixItHints()); OS.flush(); } diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index 018d59e5e871..40f78ce25ceb 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -2710,7 +2710,8 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem, // If the module map file wasn't already entered, do so now. if (ID.isInvalid()) { - auto FileCharacter = IsSystem ? SrcMgr::C_System : SrcMgr::C_User; + auto FileCharacter = + IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap; ID = SourceMgr.createFileID(File, ExternModuleLoc, FileCharacter); } diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index a6bfc32e2213..8af9a50cc204 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -1315,6 +1315,8 @@ static bool HasExtension(const Preprocessor &PP, StringRef Extension) { .Case("cxx_binary_literals", true) .Case("cxx_init_captures", LangOpts.CPlusPlus11) .Case("cxx_variable_templates", LangOpts.CPlusPlus) + // Miscellaneous language extensions + .Case("overloadable_unmarked", true) .Default(false); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index d0ce9fc89583..07054546f42f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -71,11 +71,18 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } +/// \brief Normalizes an attribute name by dropping prefixed and suffixed __. +static StringRef normalizeAttrName(StringRef Name) { + if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) + return Name.drop_front(2).drop_back(2); + return Name; +} + /// isAttributeLateParsed - Return true if the attribute has arguments that /// require late parsing. static bool isAttributeLateParsed(const IdentifierInfo &II) { #define CLANG_ATTR_LATE_PARSED_LIST - return llvm::StringSwitch<bool>(II.getName()) + return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) #include "clang/Parse/AttrParserStringSwitches.inc" .Default(false); #undef CLANG_ATTR_LATE_PARSED_LIST @@ -200,13 +207,6 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, } } -/// \brief Normalizes an attribute name by dropping prefixed and suffixed __. -static StringRef normalizeAttrName(StringRef Name) { - if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) - Name = Name.drop_front(2).drop_back(2); - return Name; -} - /// \brief Determine whether the given attribute has an identifier argument. static bool attributeHasIdentifierArg(const IdentifierInfo &II) { #define CLANG_ATTR_IDENTIFIER_ARG_LIST @@ -4319,8 +4319,15 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } - if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) - ParseEnumBody(StartLoc, TagDecl); + if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { + Decl *D = SkipBody.CheckSameAsPrevious ? SkipBody.New : TagDecl; + ParseEnumBody(StartLoc, D); + if (SkipBody.CheckSameAsPrevious && + !Actions.ActOnDuplicateDefinition(DS, TagDecl, SkipBody)) { + DS.SetTypeSpecError(); + return; + } + } if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, @@ -4392,11 +4399,9 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { } // Install the enumerator constant into EnumDecl. - Decl *EnumConstDecl = Actions.ActOnEnumConstant(getCurScope(), EnumDecl, - LastEnumConstDecl, - IdentLoc, Ident, - attrs.getList(), EqualLoc, - AssignedVal.get()); + Decl *EnumConstDecl = Actions.ActOnEnumConstant( + getCurScope(), EnumDecl, LastEnumConstDecl, IdentLoc, Ident, + attrs.getList(), EqualLoc, AssignedVal.get()); EnumAvailabilityDiags.back().done(); EnumConstantDecls.push_back(EnumConstDecl); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index a724fa242268..2301284b7f43 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1910,12 +1910,22 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, else if (getLangOpts().CPlusPlus) ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType, TagOrTempResult.get()); - else - ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get()); + else { + Decl *D = + SkipBody.CheckSameAsPrevious ? SkipBody.New : TagOrTempResult.get(); + // Parse the definition body. + ParseStructUnionBody(StartLoc, TagType, D); + if (SkipBody.CheckSameAsPrevious && + !Actions.ActOnDuplicateDefinition(DS, TagOrTempResult.get(), + SkipBody)) { + DS.SetTypeSpecError(); + return; + } + } } if (!TagOrTempResult.isInvalid()) - // Delayed proccessing of attributes. + // Delayed processing of attributes. Actions.ProcessDeclAttributeDelayed(TagOrTempResult.get(), attrs.getList()); const char *PrevSpec = nullptr; diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 934e13e72d05..fd2d07957c2b 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -305,10 +305,14 @@ static bool isThrowCaught(const CXXThrowExpr *Throw, CaughtType = CaughtType->castAs<ReferenceType>() ->getPointeeType() ->getUnqualifiedDesugaredType(); + if (ThrowType->isPointerType() && CaughtType->isPointerType()) { + ThrowType = ThrowType->getPointeeType()->getUnqualifiedDesugaredType(); + CaughtType = CaughtType->getPointeeType()->getUnqualifiedDesugaredType(); + } if (CaughtType == ThrowType) return true; const CXXRecordDecl *CaughtAsRecordType = - CaughtType->getPointeeCXXRecordDecl(); + CaughtType->getAsCXXRecordDecl(); const CXXRecordDecl *ThrowTypeAsRecordType = ThrowType->getAsCXXRecordDecl(); if (CaughtAsRecordType && ThrowTypeAsRecordType) return ThrowTypeAsRecordType->isDerivedFrom(CaughtAsRecordType); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 007a5e483e6c..34f5e26be810 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -1688,7 +1688,8 @@ bool Sema::checkOpenCLDisabledTypeDeclSpec(const DeclSpec &DS, QualType QT) { QT, OpenCLTypeExtMap); } -bool Sema::checkOpenCLDisabledDecl(const Decl &D, const Expr &E) { - return checkOpenCLDisabledTypeOrDecl(&D, E.getLocStart(), "", +bool Sema::checkOpenCLDisabledDecl(const NamedDecl &D, const Expr &E) { + IdentifierInfo *FnName = D.getIdentifier(); + return checkOpenCLDisabledTypeOrDecl(&D, E.getLocStart(), FnName, OpenCLDeclExtMap, 1, D.getSourceRange()); } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index b794628db738..845c4bf61b7a 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -6000,6 +6000,7 @@ shouldNotPrintDirectly(const ASTContext &Context, while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) { StringRef Name = UserTy->getDecl()->getName(); QualType CastTy = llvm::StringSwitch<QualType>(Name) + .Case("CFIndex", Context.LongTy) .Case("NSInteger", Context.LongTy) .Case("NSUInteger", Context.UnsignedLongTy) .Case("SInt32", Context.IntTy) @@ -9935,6 +9936,28 @@ void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) { ::CheckBoolLikeConversion(*this, E, CC); } +/// Diagnose when expression is an integer constant expression and its evaluation +/// results in integer overflow +void Sema::CheckForIntOverflow (Expr *E) { + // Use a work list to deal with nested struct initializers. + SmallVector<Expr *, 2> Exprs(1, E); + + do { + Expr *E = Exprs.pop_back_val(); + + if (isa<BinaryOperator>(E->IgnoreParenCasts())) { + E->IgnoreParenCasts()->EvaluateForOverflow(Context); + continue; + } + + if (auto InitList = dyn_cast<InitListExpr>(E)) + Exprs.append(InitList->inits().begin(), InitList->inits().end()); + + if (isa<ObjCBoxedExpr>(E)) + E->IgnoreParenCasts()->EvaluateForOverflow(Context); + } while (!Exprs.empty()); +} + namespace { /// \brief Visitor for expressions which looks for unsequenced operations on the /// same object. @@ -10436,7 +10459,7 @@ void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, if (!E->isInstantiationDependent()) CheckUnsequencedOperations(E); if (!IsConstexpr && !E->isValueDependent()) - E->EvaluateForOverflow(Context); + CheckForIntOverflow(E); DiagnoseMisalignedMembers(); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e340456bc6da..ef8a408f90de 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1327,15 +1327,17 @@ void Sema::ActOnExitFunctionContext() { /// overloaded function declaration or has the "overloadable" /// attribute. static bool AllowOverloadingOfFunction(LookupResult &Previous, - ASTContext &Context) { + ASTContext &Context, + const FunctionDecl *New) { if (Context.getLangOpts().CPlusPlus) return true; if (Previous.getResultKind() == LookupResult::FoundOverloaded) return true; - return (Previous.getResultKind() == LookupResult::Found - && Previous.getFoundDecl()->hasAttr<OverloadableAttr>()); + return Previous.getResultKind() == LookupResult::Found && + (Previous.getFoundDecl()->hasAttr<OverloadableAttr>() || + New->hasAttr<OverloadableAttr>()); } /// Add this decl to the scope shadowed decl chains. @@ -2933,6 +2935,41 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, New->dropAttr<InternalLinkageAttr>(); } + if (!getLangOpts().CPlusPlus) { + bool OldOvl = Old->hasAttr<OverloadableAttr>(); + if (OldOvl != New->hasAttr<OverloadableAttr>() && !Old->isImplicit()) { + Diag(New->getLocation(), diag::err_attribute_overloadable_mismatch) + << New << OldOvl; + + // Try our best to find a decl that actually has the overloadable + // attribute for the note. In most cases (e.g. programs with only one + // broken declaration/definition), this won't matter. + // + // FIXME: We could do this if we juggled some extra state in + // OverloadableAttr, rather than just removing it. + const Decl *DiagOld = Old; + if (OldOvl) { + auto OldIter = llvm::find_if(Old->redecls(), [](const Decl *D) { + const auto *A = D->getAttr<OverloadableAttr>(); + return A && !A->isImplicit(); + }); + // If we've implicitly added *all* of the overloadable attrs to this + // chain, emitting a "previous redecl" note is pointless. + DiagOld = OldIter == Old->redecls_end() ? nullptr : *OldIter; + } + + if (DiagOld) + Diag(DiagOld->getLocation(), + diag::note_attribute_overloadable_prev_overload) + << OldOvl; + + if (OldOvl) + New->addAttr(OverloadableAttr::CreateImplicit(Context)); + else + New->dropAttr<OverloadableAttr>(); + } + } + // If a function is first declared with a calling convention, but is later // declared or defined without one, all following decls assume the calling // convention of the first. @@ -9179,6 +9216,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, bool Redeclaration = false; NamedDecl *OldDecl = nullptr; + bool MayNeedOverloadableChecks = false; // Merge or overload the declaration with an existing declaration of // the same name, if appropriate. @@ -9187,13 +9225,14 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // a declaration that requires merging. If it's an overload, // there's no more work to do here; we'll just add the new // function to the scope. - if (!AllowOverloadingOfFunction(Previous, Context)) { + if (!AllowOverloadingOfFunction(Previous, Context, NewFD)) { NamedDecl *Candidate = Previous.getRepresentativeDecl(); if (shouldLinkPossiblyHiddenDecl(Candidate, NewFD)) { Redeclaration = true; OldDecl = Candidate; } } else { + MayNeedOverloadableChecks = true; switch (CheckOverload(S, NewFD, Previous, OldDecl, /*NewIsUsingDecl*/ false)) { case Ovl_Match: @@ -9208,18 +9247,6 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Redeclaration = false; break; } - - if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) { - // If a function name is overloadable in C, then every function - // with that name must be marked "overloadable". - Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) - << Redeclaration << NewFD; - NamedDecl *OverloadedDecl = - Redeclaration ? OldDecl : Previous.getRepresentativeDecl(); - Diag(OverloadedDecl->getLocation(), - diag::note_attribute_overloadable_prev_overload); - NewFD->addAttr(OverloadableAttr::CreateImplicit(Context)); - } } } @@ -9234,15 +9261,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, MergeTypeWithPrevious = false; // ... except in the presence of __attribute__((overloadable)). - if (OldDecl->hasAttr<OverloadableAttr>()) { - if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) { - Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) - << Redeclaration << NewFD; - Diag(Previous.getFoundDecl()->getLocation(), - diag::note_attribute_overloadable_prev_overload); - NewFD->addAttr(OverloadableAttr::CreateImplicit(Context)); - } + if (OldDecl->hasAttr<OverloadableAttr>() || + NewFD->hasAttr<OverloadableAttr>()) { if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) { + MayNeedOverloadableChecks = true; Redeclaration = false; OldDecl = nullptr; } @@ -9337,6 +9359,29 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, NewFD->setAccess(OldDecl->getAccess()); } } + } else if (!getLangOpts().CPlusPlus && MayNeedOverloadableChecks && + !NewFD->getAttr<OverloadableAttr>()) { + assert((Previous.empty() || + llvm::any_of(Previous, + [](const NamedDecl *ND) { + return ND->hasAttr<OverloadableAttr>(); + })) && + "Non-redecls shouldn't happen without overloadable present"); + + auto OtherUnmarkedIter = llvm::find_if(Previous, [](const NamedDecl *ND) { + const auto *FD = dyn_cast<FunctionDecl>(ND); + return FD && !FD->hasAttr<OverloadableAttr>(); + }); + + if (OtherUnmarkedIter != Previous.end()) { + Diag(NewFD->getLocation(), + diag::err_attribute_overloadable_multiple_unmarked_overloads); + Diag((*OtherUnmarkedIter)->getLocation(), + diag::note_attribute_overloadable_prev_overload) + << false; + + NewFD->addAttr(OverloadableAttr::CreateImplicit(Context)); + } } // Semantic checking for this function declaration (in isolation). @@ -11100,9 +11145,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { bool IsGlobal = GlobalStorage && !var->isStaticLocal(); QualType baseType = Context.getBaseElementType(type); - if (!var->getDeclContext()->isDependentContext() && - Init && !Init->isValueDependent()) { - + if (Init && !Init->isValueDependent()) { if (var->isConstexpr()) { SmallVector<PartialDiagnosticAt, 8> Notes; if (!var->evaluateValue(Notes) || !var->isInitICE()) { @@ -11932,7 +11975,7 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, if (canRedefineFunction(Definition, getLangOpts())) return; - // Don't emit an error when this is redifinition of a typo-corrected + // Don't emit an error when this is redefinition of a typo-corrected // definition. if (TypoCorrectedFunctionDefinitions.count(Definition)) return; @@ -13190,6 +13233,55 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (TUK == TUK_Friend || TUK == TUK_Reference) Redecl = NotForRedeclaration; + /// Create a new tag decl in C/ObjC. Since the ODR-like semantics for ObjC/C + /// implemented asks for structural equivalence checking, the returned decl + /// here is passed back to the parser, allowing the tag body to be parsed. + auto createTagFromNewDecl = [&]() -> TagDecl * { + assert(!getLangOpts().CPlusPlus && "not meant for C++ usage"); + // If there is an identifier, use the location of the identifier as the + // location of the decl, otherwise use the location of the struct/union + // keyword. + SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc; + TagDecl *New = nullptr; + + if (Kind == TTK_Enum) { + New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, nullptr, + ScopedEnum, ScopedEnumUsesClassTag, + !EnumUnderlying.isNull()); + // If this is an undefined enum, bail. + if (TUK != TUK_Definition && !Invalid) + return nullptr; + if (EnumUnderlying) { + EnumDecl *ED = cast<EnumDecl>(New); + if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo *>()) + ED->setIntegerTypeSourceInfo(TI); + else + ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0)); + ED->setPromotionType(ED->getIntegerType()); + } + } else { // struct/union + New = RecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name, + nullptr); + } + + if (RecordDecl *RD = dyn_cast<RecordDecl>(New)) { + // Add alignment attributes if necessary; these attributes are checked + // when the ASTContext lays out the structure. + // + // It is important for implementing the correct semantics that this + // happen here (in ActOnTag). The #pragma pack stack is + // maintained as a result of parser callbacks which can occur at + // many points during the parsing of a struct declaration (because + // the #pragma tokens are effectively skipped over during the + // parsing of the struct). + if (TUK == TUK_Definition) { + AddAlignmentAttributesForRecord(RD); + AddMsStructLayoutForRecord(RD); + } + } + return New; + }; + LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl); if (Name && SS.isNotEmpty()) { // We have a nested-name tag ('struct foo::bar'). @@ -13595,16 +13687,28 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, TSK_ExplicitSpecialization; } + // Note that clang allows ODR-like semantics for ObjC/C, i.e., do + // not keep more that one definition around (merge them). However, + // ensure the decl passes the structural compatibility check in + // C11 6.2.7/1 (or 6.1.2.6/1 in C89). NamedDecl *Hidden = nullptr; - if (SkipBody && getLangOpts().CPlusPlus && - !hasVisibleDefinition(Def, &Hidden)) { + if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) { // There is a definition of this tag, but it is not visible. We // explicitly make use of C++'s one definition rule here, and // assume that this definition is identical to the hidden one // we already have. Make the existing definition visible and // use it in place of this one. - SkipBody->ShouldSkip = true; - makeMergedDefinitionVisible(Hidden); + if (!getLangOpts().CPlusPlus) { + // Postpone making the old definition visible until after we + // complete parsing the new one and do the structural + // comparison. + SkipBody->CheckSameAsPrevious = true; + SkipBody->New = createTagFromNewDecl(); + SkipBody->Previous = Hidden; + } else { + SkipBody->ShouldSkip = true; + makeMergedDefinitionVisible(Hidden); + } return Def; } else if (!IsExplicitSpecializationAfterInstantiation) { // A redeclaration in function prototype scope in C isn't @@ -13832,7 +13936,7 @@ CreateNewDecl: // the ASTContext lays out the structure. // // It is important for implementing the correct semantics that this - // happen here (in act on tag decl). The #pragma pack stack is + // happen here (in ActOnTag). The #pragma pack stack is // maintained as a result of parser callbacks which can occur at // many points during the parsing of a struct declaration (because // the #pragma tokens are effectively skipped over during the @@ -13968,6 +14072,16 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { AddPushedVisibilityAttribute(Tag); } +bool Sema::ActOnDuplicateDefinition(DeclSpec &DS, Decl *Prev, + SkipBodyInfo &SkipBody) { + if (!hasStructuralCompatLayout(Prev, SkipBody.New)) + return false; + + // Make the previous decl visible. + makeMergedDefinitionVisible(SkipBody.Previous); + return true; +} + Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { assert(isa<ObjCContainerDecl>(IDecl) && "ActOnObjCContainerStartDefinition - Not ObjCContainerDecl"); @@ -15389,7 +15503,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, // different from T: // - every enumerator of every member of class T that is an unscoped // enumerated type - if (!TheEnumDecl->isScoped()) + if (getLangOpts().CPlusPlus && !TheEnumDecl->isScoped()) DiagnoseClassNameShadow(TheEnumDecl->getDeclContext(), DeclarationNameInfo(Id, IdLoc)); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index e8503427536d..1929bc539188 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -6571,7 +6571,7 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, } } -// Helper for delayed proccessing TransparentUnion attribute. +// Helper for delayed processing TransparentUnion attribute. void Sema::ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList) { for (const AttributeList *Attr = AttrList; Attr; Attr = Attr->getNext()) if (Attr->getKind() == AttributeList::AT_TransparentUnion) { diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 453ece9d9c4d..e9070881afe4 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -3778,6 +3778,15 @@ Sema::BuildMemInitializer(Decl *ConstructorD, if (BaseType.isNull()) return true; + TInfo = Context.CreateTypeSourceInfo(BaseType); + DependentNameTypeLoc TL = + TInfo->getTypeLoc().castAs<DependentNameTypeLoc>(); + if (!TL.isNull()) { + TL.setNameLoc(IdLoc); + TL.setElaboratedKeywordLoc(SourceLocation()); + TL.setQualifierLoc(SS.getWithLocInContext(Context)); + } + R.clear(); R.setLookupName(MemberOrBase); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 710ead30790f..a9cf3ec7990b 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1646,6 +1646,27 @@ static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style, return false; } +// Emit a diagnostic if an aligned allocation/deallocation function that is not +// implemented in the standard library is selected. +static void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD, + SourceLocation Loc, bool IsDelete, + Sema &S) { + if (!S.getLangOpts().AlignedAllocationUnavailable) + return; + + // Return if there is a definition. + if (FD.isDefined()) + return; + + bool IsAligned = false; + if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) { + S.Diag(Loc, diag::warn_aligned_allocation_unavailable) + << IsDelete << FD.getType().getAsString() + << S.getASTContext().getTargetInfo().getTriple().str(); + S.Diag(Loc, diag::note_silence_unligned_allocation_unavailable); + } +} + ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen, @@ -2023,11 +2044,13 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, if (DiagnoseUseOfDecl(OperatorNew, StartLoc)) return ExprError(); MarkFunctionReferenced(StartLoc, OperatorNew); + diagnoseUnavailableAlignedAllocation(*OperatorNew, StartLoc, false, *this); } if (OperatorDelete) { if (DiagnoseUseOfDecl(OperatorDelete, StartLoc)) return ExprError(); MarkFunctionReferenced(StartLoc, OperatorDelete); + diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true, *this); } // C++0x [expr.new]p17: @@ -3243,6 +3266,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, PDiag(diag::err_access_dtor) << PointeeElem); } } + + diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true, + *this); } CXXDeleteExpr *Result = new (Context) CXXDeleteExpr( @@ -4093,15 +4119,9 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, case UTT_IsStandardLayout: case UTT_IsPOD: case UTT_IsLiteral: - ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0); - LLVM_FALLTHROUGH; - - // C++1z [meta.unary.prop]: - // T shall be a complete type, cv void, or an array of unknown bound. - case UTT_IsDestructible: - case UTT_IsNothrowDestructible: - case UTT_IsTriviallyDestructible: - // Per the GCC type traits documentation, the same constraints apply to these. + // Per the GCC type traits documentation, T shall be a complete type, cv void, + // or an array of unknown bound. But GCC actually imposes the same constraints + // as above. case UTT_HasNothrowAssign: case UTT_HasNothrowMoveAssign: case UTT_HasNothrowConstructor: @@ -4113,6 +4133,14 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, case UTT_HasTrivialCopy: case UTT_HasTrivialDestructor: case UTT_HasVirtualDestructor: + ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0); + LLVM_FALLTHROUGH; + + // C++1z [meta.unary.prop]: + // T shall be a complete type, cv void, or an array of unknown bound. + case UTT_IsDestructible: + case UTT_IsNothrowDestructible: + case UTT_IsTriviallyDestructible: if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType()) return true; diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 2b7733d2adbd..49da0e499771 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -412,6 +412,30 @@ public: return false; } + /// Do the check specified in \a Check to all component lists at a given level + /// and return true if any issue is found. + bool checkMappableExprComponentListsForDeclAtLevel( + ValueDecl *VD, unsigned Level, + const llvm::function_ref< + bool(OMPClauseMappableExprCommon::MappableExprComponentListRef, + OpenMPClauseKind)> &Check) { + if (isStackEmpty()) + return false; + + auto StartI = Stack.back().first.begin(); + auto EndI = Stack.back().first.end(); + if (std::distance(StartI, EndI) <= (int)Level) + return false; + std::advance(StartI, Level); + + auto MI = StartI->MappedExprComponents.find(VD); + if (MI != StartI->MappedExprComponents.end()) + for (auto &L : MI->second.Components) + if (Check(L, MI->second.Kind)) + return true; + return false; + } + /// Create a new mappable expression component list associated with a given /// declaration and initialize it with the provided list of components. void addMappableExpressionComponents( @@ -994,9 +1018,8 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) { bool IsVariableUsedInMapClause = false; bool IsVariableAssociatedWithSection = false; - DSAStack->checkMappableExprComponentListsForDecl( - D, /*CurrentRegionOnly=*/true, - [&](OMPClauseMappableExprCommon::MappableExprComponentListRef + DSAStack->checkMappableExprComponentListsForDeclAtLevel( + D, Level, [&](OMPClauseMappableExprCommon::MappableExprComponentListRef MapExprComponents, OpenMPClauseKind WhereFoundClauseKind) { // Only the map clause information influences how a variable is diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 8c8402e75e37..b19dcb2a5099 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/ASTStructuralEquivalence.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -7111,6 +7112,20 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, return false; } +bool Sema::hasStructuralCompatLayout(Decl *D, Decl *Suggested) { + llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls; + if (!Suggested) + return false; + + // FIXME: Add a specific mode for C11 6.2.7/1 in StructuralEquivalenceContext + // and isolate from other C++ specific checks. + StructuralEquivalenceContext Ctx( + D->getASTContext(), Suggested->getASTContext(), NonEquivalentDecls, + false /*StrictTypeSpelling*/, true /*Complain*/, + true /*ErrorOnTagTypeMismatch*/); + return Ctx.IsStructurallyEquivalent(D, Suggested); +} + /// \brief Determine whether there is any declaration of \p D that was ever a /// definition (perhaps before module merging) and is currently visible. /// \param D The definition of the entity. diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index ef2841849ff6..3aee3c04001d 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -856,7 +856,7 @@ static bool isInterestingIdentifier(ASTReader &Reader, IdentifierInfo &II, II.isPoisoned() || (IsModule ? II.hasRevertedBuiltin() : II.getObjCOrBuiltinID()) || II.hasRevertedTokenIDToIdentifier() || - (!(IsModule && Reader.getContext().getLangOpts().CPlusPlus) && + (!(IsModule && Reader.getPreprocessor().getLangOpts().CPlusPlus) && II.getFETokenInfo<void>()); } @@ -1148,7 +1148,7 @@ bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M, void ASTReader::Error(StringRef Msg) const { Error(diag::err_fe_pch_malformed, Msg); - if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight() && + if (PP.getLangOpts().Modules && !Diags.isDiagnosticInFlight() && !PP.getHeaderSearchInfo().getModuleCachePath().empty()) { Diag(diag::note_module_cache_path) << PP.getHeaderSearchInfo().getModuleCachePath(); @@ -1391,15 +1391,14 @@ bool ASTReader::ReadSLocEntry(int ID) { const DeclID *FirstDecl = F->FileSortedDecls + Record[6]; unsigned NumFileDecls = Record[7]; - if (NumFileDecls) { + if (NumFileDecls && ContextObj) { assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?"); FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl, NumFileDecls)); } const SrcMgr::ContentCache *ContentCache - = SourceMgr.getOrCreateContentCache(File, - /*isSystemFile=*/FileCharacter != SrcMgr::C_User); + = SourceMgr.getOrCreateContentCache(File, isSystem(FileCharacter)); if (OverriddenBuffer && !ContentCache->BufferOverridden && ContentCache->ContentsEntry == ContentCache->OrigEntry && !ContentCache->getRawBuffer()) { @@ -1697,9 +1696,9 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, HeaderFileInfo HFI; unsigned Flags = *d++; // FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp. - HFI.isImport |= (Flags >> 4) & 0x01; - HFI.isPragmaOnce |= (Flags >> 3) & 0x01; - HFI.DirInfo = (Flags >> 1) & 0x03; + HFI.isImport |= (Flags >> 5) & 0x01; + HFI.isPragmaOnce |= (Flags >> 4) & 0x01; + HFI.DirInfo = (Flags >> 1) & 0x07; HFI.IndexHeaderMapHeader = Flags & 0x01; // FIXME: Find a better way to handle this. Maybe just store a // "has been included" flag? @@ -2029,6 +2028,7 @@ ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) { R.StoredTime = static_cast<time_t>(Record[2]); R.Overridden = static_cast<bool>(Record[3]); R.Transient = static_cast<bool>(Record[4]); + R.TopLevelModuleMap = static_cast<bool>(Record[5]); R.Filename = Blob; ResolveImportedPath(F, R.Filename); return R; @@ -2614,10 +2614,11 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // 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->hasExternalLexicalStorage() && - !getContext().getLangOpts().CPlusPlus) - DC->setMustBuildLookupTable(); + if (ASTContext *Ctx = ContextObj) { + DeclContext *DC = Ctx->getTranslationUnitDecl(); + if (DC->hasExternalLexicalStorage() && !Ctx->getLangOpts().CPlusPlus) + DC->setMustBuildLookupTable(); + } return Success; } @@ -2706,7 +2707,33 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // Read and process a record. Record.clear(); StringRef Blob; - switch ((ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) { + auto RecordType = + (ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob); + + // If we're not loading an AST context, we don't care about most records. + if (!ContextObj) { + switch (RecordType) { + case IDENTIFIER_TABLE: + case IDENTIFIER_OFFSET: + case INTERESTING_IDENTIFIERS: + case STATISTICS: + case PP_CONDITIONAL_STACK: + case PP_COUNTER_VALUE: + case SOURCE_LOCATION_OFFSETS: + case MODULE_OFFSET_MAP: + case SOURCE_MANAGER_LINE_TABLE: + case SOURCE_LOCATION_PRELOADS: + case PPD_ENTITIES_OFFSETS: + case HEADER_SEARCH_TABLE: + case IMPORTED_MODULES: + case MACRO_OFFSET: + break; + default: + continue; + } + } + + switch (RecordType) { default: // Default behavior: ignore. break; @@ -2765,7 +2792,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } case TU_UPDATE_LEXICAL: { - DeclContext *TU = Context.getTranslationUnitDecl(); + DeclContext *TU = ContextObj->getTranslationUnitDecl(); LexicalContents Contents( reinterpret_cast<const llvm::support::unaligned_uint32_t *>( Blob.data()), @@ -3455,12 +3482,6 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, unsigned Idx = 0; F.ModuleMapPath = ReadPath(F, Record, Idx); - if (F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule) { - // For an explicitly-loaded module, we don't care whether the original - // module map file exists or matches. - return Success; - } - // Try to resolve ModuleName in the current header search context and // verify that it is found in the same module map file as we saved. If the // top-level AST file is a main file, skip this check because there is no @@ -3667,7 +3688,7 @@ bool ASTReader::loadGlobalIndex() { return false; if (TriedLoadingGlobalIndex || !UseGlobalIndex || - !Context.getLangOpts().Modules) + !PP.getLangOpts().Modules) return true; // Try to load the global index. @@ -3685,7 +3706,7 @@ bool ASTReader::loadGlobalIndex() { } bool ASTReader::isGlobalIndexUnavailable() const { - return Context.getLangOpts().Modules && UseGlobalIndex && + return PP.getLangOpts().Modules && UseGlobalIndex && !hasGlobalIndex() && TriedLoadingGlobalIndex; } @@ -3743,7 +3764,9 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, Deserializing AnASTFile(this); // Bump the generation number. - unsigned PreviousGeneration = incrementGeneration(Context); + unsigned PreviousGeneration = 0; + if (ContextObj) + PreviousGeneration = incrementGeneration(*ContextObj); unsigned NumModules = ModuleMgr.size(); SmallVector<ImportedModule, 4> Loaded; @@ -3762,7 +3785,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, LoadedSet.insert(IM.Mod); ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, LoadedSet, - Context.getLangOpts().Modules + PP.getLangOpts().Modules ? &PP.getHeaderSearchInfo().getModuleMap() : nullptr); @@ -3858,7 +3881,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, F.ImportLoc = TranslateSourceLocation(*M->ImportedBy, M->ImportLoc); } - if (!Context.getLangOpts().CPlusPlus || + if (!PP.getLangOpts().CPlusPlus || (Type != MK_ImplicitModule && Type != MK_ExplicitModule && Type != MK_PrebuiltModule)) { // Mark all of the identifiers in the identifier table as being out of date, @@ -3915,7 +3938,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, // Might be unnecessary as use declarations are only used to build the // module itself. - InitializeContext(); + if (ContextObj) + InitializeContext(); if (SemaObj) UpdateSema(); @@ -3937,10 +3961,12 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, // For any Objective-C class definitions we have already loaded, make sure // that we load any additional categories. - for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) { - loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(), - ObjCClassesLoaded[I], - PreviousGeneration); + if (ContextObj) { + for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) { + loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(), + ObjCClassesLoaded[I], + PreviousGeneration); + } } if (PP.getHeaderSearchInfo() @@ -4320,6 +4346,9 @@ ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) { } void ASTReader::InitializeContext() { + assert(ContextObj && "no context to initialize"); + ASTContext &Context = *ContextObj; + // If there's a listener, notify them that we "read" the translation unit. if (DeserializationListener) DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID, @@ -5054,8 +5083,8 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; } case SUBMODULE_REQUIRES: { - CurrentModule->addRequirement(Blob, Record[0], Context.getLangOpts(), - Context.getTargetInfo()); + CurrentModule->addRequirement(Blob, Record[0], PP.getLangOpts(), + PP.getTargetInfo()); break; } @@ -5081,10 +5110,12 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } case SUBMODULE_INITIALIZERS: + if (!ContextObj) + break; SmallVector<uint32_t, 16> Inits; for (auto &ID : Record) Inits.push_back(getGlobalDeclID(F, ID)); - Context.addLazyModuleInitializers(CurrentModule, Inits); + ContextObj->addLazyModuleInitializers(CurrentModule, Inits); break; } } @@ -5705,6 +5736,8 @@ ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) { /// location. It is a helper routine for GetType, which deals with reading type /// IDs. QualType ASTReader::readTypeRecord(unsigned Index) { + assert(ContextObj && "reading type with no AST context"); + ASTContext &Context = *ContextObj; RecordLocation Loc = TypeCursorForIndex(Index); BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor; @@ -6561,6 +6594,9 @@ ASTReader::GetTypeSourceInfo(ModuleFile &F, const ASTReader::RecordData &Record, } QualType ASTReader::GetType(TypeID ID) { + assert(ContextObj && "reading type with no AST context"); + ASTContext &Context = *ContextObj; + unsigned FastQuals = ID & Qualifiers::FastMask; unsigned Index = ID >> Qualifiers::FastWidth; @@ -6892,6 +6928,9 @@ ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) { } CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { + assert(ContextObj && "reading base specifiers with no AST context"); + ASTContext &Context = *ContextObj; + RecordLocation Loc = getLocalBitOffset(Offset); BitstreamCursor &Cursor = Loc.F->DeclsCursor; SavedStreamPosition SavedPosition(Cursor); @@ -7023,8 +7062,9 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) { } Decl *ASTReader::GetExistingDecl(DeclID ID) { + assert(ContextObj && "reading decl with no AST context"); if (ID < NUM_PREDEF_DECL_IDS) { - Decl *D = getPredefinedDecl(Context, (PredefinedDeclIDs)ID); + Decl *D = getPredefinedDecl(*ContextObj, (PredefinedDeclIDs)ID); if (D) { // Track that we have merged the declaration with ID \p ID into the // pre-existing predefined declaration \p D. @@ -7569,7 +7609,7 @@ IdentifierInfo *ASTReader::get(StringRef Name) { // all interesting declarations, and don't need to use the scope for name // lookups). Perform the lookup in PCH files, though, since we don't build // a complete initial identifier table if we're carrying on from a PCH. - if (Context.getLangOpts().CPlusPlus) { + if (PP.getLangOpts().CPlusPlus) { for (auto F : ModuleMgr.pch_modules()) if (Visitor(*F)) break; @@ -8223,7 +8263,7 @@ ASTReader::getSourceDescriptor(unsigned ID) { return ExternalASTSource::ASTSourceDescriptor(*M); // If there is only a single PCH, return it instead. - // Chained PCH are not suported. + // Chained PCH are not supported. const auto &PCHChain = ModuleMgr.pch_modules(); if (std::distance(std::begin(PCHChain), std::end(PCHChain))) { ModuleFile &MF = ModuleMgr.getPrimaryModule(); @@ -8299,6 +8339,7 @@ ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const { DeclarationName ASTReader::ReadDeclarationName(ModuleFile &F, const RecordData &Record, unsigned &Idx) { + ASTContext &Context = getContext(); DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++]; switch (Kind) { case DeclarationName::Identifier: @@ -8389,7 +8430,8 @@ void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info, unsigned NumTPLists = Record[Idx++]; Info.NumTemplParamLists = NumTPLists; if (NumTPLists) { - Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists]; + Info.TemplParamLists = + new (getContext()) TemplateParameterList *[NumTPLists]; for (unsigned i = 0; i != NumTPLists; ++i) Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx); } @@ -8398,6 +8440,7 @@ void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info, TemplateName ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record, unsigned &Idx) { + ASTContext &Context = getContext(); TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++]; switch (Kind) { case TemplateName::Template: @@ -8458,6 +8501,7 @@ TemplateArgument ASTReader::ReadTemplateArgument(ModuleFile &F, const RecordData &Record, unsigned &Idx, bool Canonicalize) { + ASTContext &Context = getContext(); if (Canonicalize) { // The caller wants a canonical template argument. Sometimes the AST only // wants template arguments in canonical form (particularly as the template @@ -8521,9 +8565,8 @@ ASTReader::ReadTemplateParameterList(ModuleFile &F, Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx)); // TODO: Concepts - TemplateParameterList* TemplateParams = - TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, - Params, RAngleLoc, nullptr); + TemplateParameterList *TemplateParams = TemplateParameterList::Create( + getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, nullptr); return TemplateParams; } @@ -8542,11 +8585,11 @@ ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs, void ASTReader::ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set, const RecordData &Record, unsigned &Idx) { unsigned NumDecls = Record[Idx++]; - Set.reserve(Context, NumDecls); + Set.reserve(getContext(), NumDecls); while (NumDecls--) { DeclID ID = ReadDeclID(F, Record, Idx); AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; - Set.addLazyDecl(Context, ID, AS); + Set.addLazyDecl(getContext(), ID, AS); } } @@ -8569,6 +8612,7 @@ ASTReader::ReadCXXBaseSpecifier(ModuleFile &F, CXXCtorInitializer ** ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, unsigned &Idx) { + ASTContext &Context = getContext(); unsigned NumInitializers = Record[Idx++]; assert(NumInitializers && "wrote ctor initializers but have no inits"); auto **CtorInitializers = new (Context) CXXCtorInitializer*[NumInitializers]; @@ -8634,6 +8678,7 @@ ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, NestedNameSpecifier * ASTReader::ReadNestedNameSpecifier(ModuleFile &F, const RecordData &Record, unsigned &Idx) { + ASTContext &Context = getContext(); unsigned N = Record[Idx++]; NestedNameSpecifier *NNS = nullptr, *Prev = nullptr; for (unsigned I = 0; I != N; ++I) { @@ -8689,6 +8734,7 @@ ASTReader::ReadNestedNameSpecifier(ModuleFile &F, NestedNameSpecifierLoc ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record, unsigned &Idx) { + ASTContext &Context = getContext(); unsigned N = Record[Idx++]; NestedNameSpecifierLocBuilder Builder; for (unsigned I = 0; I != N; ++I) { @@ -8810,7 +8856,7 @@ CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F, const RecordData &Record, unsigned &Idx) { CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx); - return CXXTemporary::Create(Context, Decl); + return CXXTemporary::Create(getContext(), Decl); } DiagnosticBuilder ASTReader::Diag(unsigned DiagID) const { @@ -8846,6 +8892,7 @@ void ASTReader::ClearSwitchCaseIDs() { } void ASTReader::ReadComments() { + ASTContext &Context = getContext(); std::vector<RawComment *> Comments; for (SmallVectorImpl<std::pair<BitstreamCursor, serialization::ModuleFile *> >::iterator @@ -8915,6 +8962,19 @@ void ASTReader::visitInputFiles(serialization::ModuleFile &MF, } } +void ASTReader::visitTopLevelModuleMaps( + serialization::ModuleFile &MF, + llvm::function_ref<void(const FileEntry *FE)> Visitor) { + unsigned NumInputs = MF.InputFilesLoaded.size(); + for (unsigned I = 0; I < NumInputs; ++I) { + InputFileInfo IFI = readInputFileInfo(MF, I + 1); + if (IFI.TopLevelModuleMap) + // FIXME: This unnecessarily re-reads the InputFileInfo. + if (auto *FE = getInputFile(MF, I + 1).getFile()) + Visitor(FE); + } +} + std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) { // If we know the owning module, use it. if (Module *M = D->getImportedOwningModule()) @@ -9514,8 +9574,8 @@ void ASTReader::diagnoseOdrViolations() { break; } - assert( - Context.hasSameType(FirstField->getType(), SecondField->getType())); + assert(getContext().hasSameType(FirstField->getType(), + SecondField->getType())); QualType FirstType = FirstField->getType(); QualType SecondType = SecondField->getType(); @@ -9966,10 +10026,10 @@ void ASTReader::FinishedDeserializing() { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); auto *FPT = Update.second->getType()->castAs<FunctionProtoType>(); auto ESI = FPT->getExtProtoInfo().ExceptionSpec; - if (auto *Listener = Context.getASTMutationListener()) + if (auto *Listener = getContext().getASTMutationListener()) Listener->ResolvedExceptionSpec(cast<FunctionDecl>(Update.second)); for (auto *Redecl : Update.second->redecls()) - Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); + getContext().adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); } } @@ -10011,7 +10071,7 @@ void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { } } -ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, +ASTReader::ASTReader(Preprocessor &PP, ASTContext *Context, const PCHContainerReader &PCHContainerRdr, ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, StringRef isysroot, bool DisableValidation, @@ -10024,7 +10084,7 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, : cast<ASTReaderListener>(new PCHValidator(PP, *this))), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), PCHContainerRdr(PCHContainerRdr), Diags(PP.getDiagnostics()), PP(PP), - Context(Context), + ContextObj(Context), ModuleMgr(PP.getFileManager(), PP.getPCMCache(), PCHContainerRdr), PCMCache(PP.getPCMCache()), DummyIdResolver(PP), ReadTimer(std::move(ReadTimer)), isysroot(isysroot), diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 07ab421cfc51..4d9ddd2ff506 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -126,6 +126,9 @@ namespace clang { void ReadObjCDefinitionData(struct ObjCInterfaceDecl::DefinitionData &Data); void MergeDefinitionData(ObjCInterfaceDecl *D, struct ObjCInterfaceDecl::DefinitionData &&NewDD); + void ReadObjCDefinitionData(struct ObjCProtocolDecl::DefinitionData &Data); + void MergeDefinitionData(ObjCProtocolDecl *D, + struct ObjCProtocolDecl::DefinitionData &&NewDD); static NamedDecl *getAnonymousDeclForMerging(ASTReader &Reader, DeclContext *DC, @@ -216,6 +219,30 @@ namespace clang { TypedefNameForLinkage(nullptr), HasPendingBody(false), IsDeclMarkedUsed(false) {} + template <typename T> static + void AddLazySpecializations(T *D, + SmallVectorImpl<serialization::DeclID>& IDs) { + if (IDs.empty()) + return; + + // FIXME: We should avoid this pattern of getting the ASTContext. + ASTContext &C = D->getASTContext(); + + auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations; + + if (auto &Old = LazySpecializations) { + IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]); + std::sort(IDs.begin(), IDs.end()); + IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); + } + + auto *Result = new (C) serialization::DeclID[1 + IDs.size()]; + *Result = IDs.size(); + std::copy(IDs.begin(), IDs.end(), Result + 1); + + LazySpecializations = Result; + } + template <typename DeclT> static Decl *getMostRecentDeclImpl(Redeclarable<DeclT> *D); static Decl *getMostRecentDeclImpl(...); @@ -244,7 +271,7 @@ namespace clang { void ReadFunctionDefinition(FunctionDecl *FD); void Visit(Decl *D); - void UpdateDecl(Decl *D); + void UpdateDecl(Decl *D, llvm::SmallVectorImpl<serialization::DeclID>&); static void setNextObjCCategory(ObjCCategoryDecl *Cat, ObjCCategoryDecl *Next) { @@ -1045,18 +1072,8 @@ void ASTDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) { IVD->setSynthesize(synth); } -void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) { - RedeclarableResult Redecl = VisitRedeclarable(PD); - VisitObjCContainerDecl(PD); - mergeRedeclarable(PD, Redecl); - - if (Record.readInt()) { - // Read the definition. - PD->allocateDefinitionData(); - - // Set the definition data of the canonical declaration, so other - // redeclarations will see it. - PD->getCanonicalDecl()->Data = PD->Data; +void ASTDeclReader::ReadObjCDefinitionData( + struct ObjCProtocolDecl::DefinitionData &Data) { unsigned NumProtoRefs = Record.readInt(); SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; @@ -1067,9 +1084,37 @@ void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) { ProtoLocs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoLocs.push_back(ReadSourceLocation()); - PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), - Reader.getContext()); + Data.ReferencedProtocols.set(ProtoRefs.data(), NumProtoRefs, + ProtoLocs.data(), Reader.getContext()); +} + +void ASTDeclReader::MergeDefinitionData(ObjCProtocolDecl *D, + struct ObjCProtocolDecl::DefinitionData &&NewDD) { + // FIXME: odr checking? +} + +void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) { + RedeclarableResult Redecl = VisitRedeclarable(PD); + VisitObjCContainerDecl(PD); + mergeRedeclarable(PD, Redecl); + + if (Record.readInt()) { + // Read the definition. + PD->allocateDefinitionData(); + + ReadObjCDefinitionData(PD->data()); + ObjCProtocolDecl *Canon = PD->getCanonicalDecl(); + if (Canon->Data.getPointer()) { + // If we already have a definition, keep the definition invariant and + // merge the data. + MergeDefinitionData(Canon, std::move(PD->data())); + PD->Data = Canon->Data; + } else { + // Set the definition data of the canonical declaration, so other + // redeclarations will see it. + PD->getCanonicalDecl()->Data = PD->Data; + } // Note that we have deserialized a definition. Reader.PendingDefinitions.insert(PD); } else { @@ -1566,8 +1611,8 @@ void ASTDeclReader::ReadCXXDefinitionData( Lambda.NumExplicitCaptures = Record.readInt(); Lambda.ManglingNumber = Record.readInt(); Lambda.ContextDecl = ReadDeclID(); - Lambda.Captures - = (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures); + Lambda.Captures = (Capture *)Reader.getContext().Allocate( + sizeof(Capture) * Lambda.NumCaptures); Capture *ToCapture = Lambda.Captures; Lambda.MethodTyInfo = GetTypeSourceInfo(); for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { @@ -1950,21 +1995,6 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { return Redecl; } -static DeclID *newDeclIDList(ASTContext &Context, DeclID *Old, - SmallVectorImpl<DeclID> &IDs) { - assert(!IDs.empty() && "no IDs to add to list"); - if (Old) { - IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]); - std::sort(IDs.begin(), IDs.end()); - IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); - } - - auto *Result = new (Context) DeclID[1 + IDs.size()]; - *Result = IDs.size(); - std::copy(IDs.begin(), IDs.end(), Result + 1); - return Result; -} - void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D); @@ -1973,19 +2003,14 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { // the specializations. SmallVector<serialization::DeclID, 32> SpecIDs; ReadDeclIDList(SpecIDs); - - if (!SpecIDs.empty()) { - auto *CommonPtr = D->getCommonPtr(); - CommonPtr->LazySpecializations = newDeclIDList( - Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs); - } + ASTDeclReader::AddLazySpecializations(D, SpecIDs); } if (D->getTemplatedDecl()->TemplateOrInstantiation) { // We were loaded before our templated declaration was. We've not set up // its corresponding type yet (see VisitCXXRecordDeclImpl), so reconstruct // it now. - Reader.Context.getInjectedClassNameType( + Reader.getContext().getInjectedClassNameType( D->getTemplatedDecl(), D->getInjectedClassNameSpecialization()); } } @@ -2005,12 +2030,7 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) { // the specializations. SmallVector<serialization::DeclID, 32> SpecIDs; ReadDeclIDList(SpecIDs); - - if (!SpecIDs.empty()) { - auto *CommonPtr = D->getCommonPtr(); - CommonPtr->LazySpecializations = newDeclIDList( - Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs); - } + ASTDeclReader::AddLazySpecializations(D, SpecIDs); } } @@ -2116,12 +2136,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // This FunctionTemplateDecl owns a CommonPtr; read it. SmallVector<serialization::DeclID, 32> SpecIDs; ReadDeclIDList(SpecIDs); - - if (!SpecIDs.empty()) { - auto *CommonPtr = D->getCommonPtr(); - CommonPtr->LazySpecializations = newDeclIDList( - Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs); - } + ASTDeclReader::AddLazySpecializations(D, SpecIDs); } } @@ -2472,8 +2487,8 @@ void ASTDeclReader::mergeMergeable(Mergeable<T> *D) { if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D))) if (T *Existing = ExistingRes) - Reader.Context.setPrimaryMergedDecl(static_cast<T*>(D), - Existing->getCanonicalDecl()); + Reader.getContext().setPrimaryMergedDecl(static_cast<T *>(D), + Existing->getCanonicalDecl()); } void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { @@ -2509,6 +2524,7 @@ void ASTReader::ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs) { Attr *New = nullptr; attr::Kind Kind = (attr::Kind)Record.readInt(); SourceRange Range = Record.readSourceRange(); + ASTContext &Context = getContext(); #include "clang/Serialization/AttrPCHRead.inc" @@ -2907,7 +2923,7 @@ DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader, // commit to DC being the canonical definition now, and will fix this when // we load the update record. if (!DD) { - DD = new (Reader.Context) struct CXXRecordDecl::DefinitionData(RD); + DD = new (Reader.getContext()) struct CXXRecordDecl::DefinitionData(RD); RD->IsCompleteDefinition = true; RD->DefinitionData = DD; RD->getCanonicalDecl()->DefinitionData = DD; @@ -3352,6 +3368,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { ASTDeclReader Reader(*this, Record, Loc, ID, DeclLoc); unsigned Code = DeclsCursor.ReadCode(); + ASTContext &Context = getContext(); Decl *D = nullptr; switch ((DeclCode)Record.readRecord(DeclsCursor, Code)) { case DECL_CONTEXT_LEXICAL: @@ -3652,7 +3669,7 @@ void ASTReader::PassInterestingDeclsToConsumer() { while (!PotentiallyInterestingDecls.empty()) { InterestingDecl D = PotentiallyInterestingDecls.front(); PotentiallyInterestingDecls.pop_front(); - if (isConsumerInterestedIn(Context, D.getDecl(), D.hasPendingBody())) + if (isConsumerInterestedIn(getContext(), D.getDecl(), D.hasPendingBody())) PassInterestingDeclToConsumer(D.getDecl()); } } @@ -3665,6 +3682,9 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { Decl *D = Record.D; ProcessingUpdatesRAIIObj ProcessingUpdates(*this); DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); + + llvm::SmallVector<serialization::DeclID, 8> PendingLazySpecializationIDs; + if (UpdI != DeclUpdateOffsets.end()) { auto UpdateOffsets = std::move(UpdI->second); DeclUpdateOffsets.erase(UpdI); @@ -3674,7 +3694,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { // to isConsumerInterestedIn because it is unsafe to call in the // current ASTReader state. bool WasInteresting = - Record.JustLoaded || isConsumerInterestedIn(Context, D, false); + Record.JustLoaded || isConsumerInterestedIn(getContext(), D, false); for (auto &FileAndOffset : UpdateOffsets) { ModuleFile *F = FileAndOffset.first; uint64_t Offset = FileAndOffset.second; @@ -3689,18 +3709,29 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID, SourceLocation()); - Reader.UpdateDecl(D); + Reader.UpdateDecl(D, PendingLazySpecializationIDs); // We might have made this declaration interesting. If so, remember that // we need to hand it off to the consumer. if (!WasInteresting && - isConsumerInterestedIn(Context, D, Reader.hasPendingBody())) { + isConsumerInterestedIn(getContext(), D, Reader.hasPendingBody())) { PotentiallyInterestingDecls.push_back( InterestingDecl(D, Reader.hasPendingBody())); WasInteresting = true; } } } + // Add the lazy specializations to the template. + assert((PendingLazySpecializationIDs.empty() || isa<ClassTemplateDecl>(D) || + isa<FunctionTemplateDecl>(D) || isa<VarTemplateDecl>(D)) && + "Must not have pending specializations"); + if (auto *CTD = dyn_cast<ClassTemplateDecl>(D)) + ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs); + else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) + ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs); + else if (auto *VTD = dyn_cast<VarTemplateDecl>(D)) + ASTDeclReader::AddLazySpecializations(VTD, PendingLazySpecializationIDs); + PendingLazySpecializationIDs.clear(); // Load the pending visible updates for this decl context, if it has any. auto I = PendingVisibleUpdates.find(ID); @@ -3897,7 +3928,8 @@ static void forAllLaterRedecls(DeclT *D, Fn F) { } } -void ASTDeclReader::UpdateDecl(Decl *D) { +void ASTDeclReader::UpdateDecl(Decl *D, + llvm::SmallVectorImpl<serialization::DeclID> &PendingLazySpecializationIDs) { while (Record.getIdx() < Record.size()) { switch ((DeclUpdateKind)Record.readInt()) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: { @@ -3913,8 +3945,8 @@ void ASTDeclReader::UpdateDecl(Decl *D) { } case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: - // It will be added to the template's specializations set when loaded. - (void)Record.readDecl(); + // It will be added to the template's lazy specialization set. + PendingLazySpecializationIDs.push_back(ReadDeclID()); break; case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { @@ -4083,7 +4115,7 @@ void ASTDeclReader::UpdateDecl(Decl *D) { // FIXME: If the exception specification is already present, check that it // matches. if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) { - FD->setType(Reader.Context.getFunctionType( + FD->setType(Reader.getContext().getFunctionType( FPT->getReturnType(), FPT->getParamTypes(), FPT->getExtProtoInfo().withExceptionSpec(ESI))); @@ -4101,28 +4133,31 @@ void ASTDeclReader::UpdateDecl(Decl *D) { for (auto *Redecl : merged_redecls(D)) { // FIXME: If the return type is already deduced, check that it matches. FunctionDecl *FD = cast<FunctionDecl>(Redecl); - Reader.Context.adjustDeducedFunctionResultType(FD, DeducedResultType); + Reader.getContext().adjustDeducedFunctionResultType(FD, + DeducedResultType); } break; } case UPD_DECL_MARKED_USED: { // Maintain AST consistency: any later redeclarations are used too. - D->markUsed(Reader.Context); + D->markUsed(Reader.getContext()); break; } case UPD_MANGLING_NUMBER: - Reader.Context.setManglingNumber(cast<NamedDecl>(D), Record.readInt()); + Reader.getContext().setManglingNumber(cast<NamedDecl>(D), + Record.readInt()); break; case UPD_STATIC_LOCAL_NUMBER: - Reader.Context.setStaticLocalNumber(cast<VarDecl>(D), Record.readInt()); + Reader.getContext().setStaticLocalNumber(cast<VarDecl>(D), + Record.readInt()); break; case UPD_DECL_MARKED_OPENMP_THREADPRIVATE: - D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit( - Reader.Context, ReadSourceRange())); + D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(Reader.getContext(), + ReadSourceRange())); break; case UPD_DECL_EXPORTED: { diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 3d314a85ff17..afee50ffa3b9 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -2954,6 +2954,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; } + ASTContext &Context = getContext(); Stmt *S = nullptr; bool Finished = false; bool IsStmtReference = false; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 1c0db14ced14..c6129d326cb6 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1692,6 +1692,7 @@ namespace { bool IsSystemFile; bool IsTransient; bool BufferOverridden; + bool IsTopLevelModuleMap; }; } // end anonymous namespace @@ -1710,6 +1711,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Transient + IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Module map IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name unsigned IFAbbrevCode = Stream.EmitAbbrev(std::move(IFAbbrev)); @@ -1724,7 +1726,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, // We only care about file entries that were not overridden. if (!SLoc->isFile()) continue; - const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache(); + const SrcMgr::FileInfo &File = SLoc->getFile(); + const SrcMgr::ContentCache *Cache = File.getContentCache(); if (!Cache->OrigEntry) continue; @@ -1733,6 +1736,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, Entry.IsSystemFile = Cache->IsSystemFile; Entry.IsTransient = Cache->IsTransient; Entry.BufferOverridden = Cache->BufferOverridden; + Entry.IsTopLevelModuleMap = isModuleMap(File.getFileCharacteristic()) && + File.getIncludeLoc().isInvalid(); if (Cache->IsSystemFile) SortedFiles.push_back(Entry); else @@ -1763,7 +1768,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, (uint64_t)Entry.File->getSize(), (uint64_t)getTimestampForOutput(Entry.File), Entry.BufferOverridden, - Entry.IsTransient}; + Entry.IsTransient, + Entry.IsTopLevelModuleMap}; EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName()); } @@ -1798,7 +1804,7 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_FILE_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives // FileEntry fields. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Input File ID @@ -1817,7 +1823,7 @@ static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) { Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob return Stream.EmitAbbrev(std::move(Abbrev)); @@ -1925,8 +1931,8 @@ namespace { endian::Writer<little> LE(Out); uint64_t Start = Out.tell(); (void)Start; - unsigned char Flags = (Data.HFI.isImport << 4) - | (Data.HFI.isPragmaOnce << 3) + unsigned char Flags = (Data.HFI.isImport << 5) + | (Data.HFI.isPragmaOnce << 4) | (Data.HFI.DirInfo << 1) | Data.HFI.IndexHeaderMapHeader; LE.write<uint8_t>(Flags); diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index 26bf597bd950..7f9a00ff876d 100644 --- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -45,6 +45,8 @@ class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > { mutable Optional<uint64_t> Val_O_CREAT; public: + DefaultBool CheckMisuse, CheckPortability; + void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; void CheckOpen(CheckerContext &C, const CallExpr *CE) const; @@ -437,29 +439,42 @@ void UnixAPIChecker::checkPreStmt(const CallExpr *CE, if (FName.empty()) return; - SubChecker SC = - llvm::StringSwitch<SubChecker>(FName) - .Case("open", &UnixAPIChecker::CheckOpen) - .Case("openat", &UnixAPIChecker::CheckOpenAt) - .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce) - .Case("calloc", &UnixAPIChecker::CheckCallocZero) - .Case("malloc", &UnixAPIChecker::CheckMallocZero) - .Case("realloc", &UnixAPIChecker::CheckReallocZero) - .Case("reallocf", &UnixAPIChecker::CheckReallocfZero) - .Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero) - .Case("__builtin_alloca_with_align", - &UnixAPIChecker::CheckAllocaWithAlignZero) - .Case("valloc", &UnixAPIChecker::CheckVallocZero) - .Default(nullptr); - - if (SC) - (this->*SC)(C, CE); + if (CheckMisuse) { + if (SubChecker SC = + llvm::StringSwitch<SubChecker>(FName) + .Case("open", &UnixAPIChecker::CheckOpen) + .Case("openat", &UnixAPIChecker::CheckOpenAt) + .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce) + .Default(nullptr)) { + (this->*SC)(C, CE); + } + } + if (CheckPortability) { + if (SubChecker SC = + llvm::StringSwitch<SubChecker>(FName) + .Case("calloc", &UnixAPIChecker::CheckCallocZero) + .Case("malloc", &UnixAPIChecker::CheckMallocZero) + .Case("realloc", &UnixAPIChecker::CheckReallocZero) + .Case("reallocf", &UnixAPIChecker::CheckReallocfZero) + .Cases("alloca", "__builtin_alloca", + &UnixAPIChecker::CheckAllocaZero) + .Case("__builtin_alloca_with_align", + &UnixAPIChecker::CheckAllocaWithAlignZero) + .Case("valloc", &UnixAPIChecker::CheckVallocZero) + .Default(nullptr)) { + (this->*SC)(C, CE); + } + } } //===----------------------------------------------------------------------===// // Registration. //===----------------------------------------------------------------------===// -void ento::registerUnixAPIChecker(CheckerManager &mgr) { - mgr.registerChecker<UnixAPIChecker>(); -} +#define REGISTER_CHECKER(Name) \ + void ento::registerUnixAPI##Name##Checker(CheckerManager &mgr) { \ + mgr.registerChecker<UnixAPIChecker>()->Check##Name = true; \ + } + +REGISTER_CHECKER(Misuse) +REGISTER_CHECKER(Portability) diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp index 77c5b547ca09..0e835579e04e 100644 --- a/lib/Tooling/CompilationDatabase.cpp +++ b/lib/Tooling/CompilationDatabase.cpp @@ -255,10 +255,12 @@ static bool stripPositionalArgs(std::vector<const char *> Args, CompileJobAnalyzer CompileAnalyzer; for (const auto &Cmd : Jobs) { - // Collect only for Assemble jobs. If we do all jobs we get duplicates - // since Link jobs point to Assemble jobs as inputs. - if (Cmd.getSource().getKind() == driver::Action::AssembleJobClass) + // Collect only for Assemble and Compile jobs. If we do all jobs we get + // duplicates since Link jobs point to Assemble jobs as inputs. + if (Cmd.getSource().getKind() == driver::Action::AssembleJobClass || + Cmd.getSource().getKind() == driver::Action::CompileJobClass) { CompileAnalyzer.run(&Cmd.getSource()); + } } if (CompileAnalyzer.Inputs.empty()) { diff --git a/lib/Tooling/Refactoring/AtomicChange.cpp b/lib/Tooling/Refactoring/AtomicChange.cpp index 321bbfa2866a..79dd346acf72 100644 --- a/lib/Tooling/Refactoring/AtomicChange.cpp +++ b/lib/Tooling/Refactoring/AtomicChange.cpp @@ -12,7 +12,6 @@ #include "llvm/Support/YAMLTraits.h" #include <string> -LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string) LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::AtomicChange) namespace { diff --git a/lib/Tooling/Refactoring/CMakeLists.txt b/lib/Tooling/Refactoring/CMakeLists.txt index b2f9b4f4c0cd..288582fc1b6b 100644 --- a/lib/Tooling/Refactoring/CMakeLists.txt +++ b/lib/Tooling/Refactoring/CMakeLists.txt @@ -5,8 +5,16 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangToolingRefactor AtomicChange.cpp + Rename/RenamingAction.cpp + Rename/USRFinder.cpp + Rename/USRFindingAction.cpp + Rename/USRLocFinder.cpp LINK_LIBS + clangAST + clangASTMatchers clangBasic + clangIndex + clangLex clangToolingCore ) diff --git a/lib/Tooling/Refactoring/Rename/RenamingAction.cpp b/lib/Tooling/Refactoring/Rename/RenamingAction.cpp new file mode 100644 index 000000000000..de6aba944a4a --- /dev/null +++ b/lib/Tooling/Refactoring/Rename/RenamingAction.cpp @@ -0,0 +1,134 @@ +//===--- RenamingAction.cpp - Clang refactoring library -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides an action to rename every symbol at a point. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Refactoring/Rename/RenamingAction.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/FileManager.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h" +#include "clang/Tooling/Tooling.h" +#include <string> +#include <vector> + +using namespace llvm; + +namespace clang { +namespace tooling { + +class RenamingASTConsumer : public ASTConsumer { +public: + RenamingASTConsumer( + const std::vector<std::string> &NewNames, + const std::vector<std::string> &PrevNames, + const std::vector<std::vector<std::string>> &USRList, + std::map<std::string, tooling::Replacements> &FileToReplaces, + bool PrintLocations) + : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList), + FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {} + + void HandleTranslationUnit(ASTContext &Context) override { + for (unsigned I = 0; I < NewNames.size(); ++I) + HandleOneRename(Context, NewNames[I], PrevNames[I], USRList[I]); + } + + void HandleOneRename(ASTContext &Context, const std::string &NewName, + const std::string &PrevName, + const std::vector<std::string> &USRs) { + const SourceManager &SourceMgr = Context.getSourceManager(); + std::vector<SourceLocation> RenamingCandidates; + std::vector<SourceLocation> NewCandidates; + + NewCandidates = tooling::getLocationsOfUSRs( + USRs, PrevName, Context.getTranslationUnitDecl()); + RenamingCandidates.insert(RenamingCandidates.end(), NewCandidates.begin(), + NewCandidates.end()); + + unsigned PrevNameLen = PrevName.length(); + for (const auto &Loc : RenamingCandidates) { + if (PrintLocations) { + FullSourceLoc FullLoc(Loc, SourceMgr); + errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(Loc) + << ":" << FullLoc.getSpellingLineNumber() << ":" + << FullLoc.getSpellingColumnNumber() << "\n"; + } + // FIXME: better error handling. + tooling::Replacement Replace(SourceMgr, Loc, PrevNameLen, NewName); + llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace); + if (Err) + llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! " + << llvm::toString(std::move(Err)) << "\n"; + } + } + +private: + const std::vector<std::string> &NewNames, &PrevNames; + const std::vector<std::vector<std::string>> &USRList; + std::map<std::string, tooling::Replacements> &FileToReplaces; + bool PrintLocations; +}; + +// A renamer to rename symbols which are identified by a give USRList to +// new name. +// +// FIXME: Merge with the above RenamingASTConsumer. +class USRSymbolRenamer : public ASTConsumer { +public: + USRSymbolRenamer(const std::vector<std::string> &NewNames, + const std::vector<std::vector<std::string>> &USRList, + std::map<std::string, tooling::Replacements> &FileToReplaces) + : NewNames(NewNames), USRList(USRList), FileToReplaces(FileToReplaces) { + assert(USRList.size() == NewNames.size()); + } + + void HandleTranslationUnit(ASTContext &Context) override { + for (unsigned I = 0; I < NewNames.size(); ++I) { + // FIXME: Apply AtomicChanges directly once the refactoring APIs are + // ready. + auto AtomicChanges = tooling::createRenameAtomicChanges( + USRList[I], NewNames[I], Context.getTranslationUnitDecl()); + for (const auto AtomicChange : AtomicChanges) { + for (const auto &Replace : AtomicChange.getReplacements()) { + llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace); + if (Err) { + llvm::errs() << "Renaming failed in " << Replace.getFilePath() + << "! " << llvm::toString(std::move(Err)) << "\n"; + } + } + } + } + } + +private: + const std::vector<std::string> &NewNames; + const std::vector<std::vector<std::string>> &USRList; + std::map<std::string, tooling::Replacements> &FileToReplaces; +}; + +std::unique_ptr<ASTConsumer> RenamingAction::newASTConsumer() { + return llvm::make_unique<RenamingASTConsumer>(NewNames, PrevNames, USRList, + FileToReplaces, PrintLocations); +} + +std::unique_ptr<ASTConsumer> QualifiedRenamingAction::newASTConsumer() { + return llvm::make_unique<USRSymbolRenamer>(NewNames, USRList, FileToReplaces); +} + +} // end namespace tooling +} // end namespace clang diff --git a/lib/Tooling/Refactoring/Rename/USRFinder.cpp b/lib/Tooling/Refactoring/Rename/USRFinder.cpp new file mode 100644 index 000000000000..f36387dafdbf --- /dev/null +++ b/lib/Tooling/Refactoring/Rename/USRFinder.cpp @@ -0,0 +1,213 @@ +//===--- USRFinder.cpp - Clang refactoring library ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file Implements a recursive AST visitor that finds the USR of a symbol at a +/// point. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Refactoring/Rename/USRFinder.h" +#include "clang/AST/AST.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" +#include "llvm/ADT/SmallVector.h" + +using namespace llvm; + +namespace clang { +namespace tooling { + +// NamedDeclFindingASTVisitor recursively visits each AST node to find the +// symbol underneath the cursor. +// FIXME: move to separate .h/.cc file if this gets too large. +namespace { +class NamedDeclFindingASTVisitor + : public clang::RecursiveASTVisitor<NamedDeclFindingASTVisitor> { +public: + // \brief Finds the NamedDecl at a point in the source. + // \param Point the location in the source to search for the NamedDecl. + explicit NamedDeclFindingASTVisitor(const SourceLocation Point, + const ASTContext &Context) + : Result(nullptr), Point(Point), Context(Context) {} + + // \brief Finds the NamedDecl for a name in the source. + // \param Name the fully qualified name. + explicit NamedDeclFindingASTVisitor(const std::string &Name, + const ASTContext &Context) + : Result(nullptr), Name(Name), Context(Context) {} + + // Declaration visitors: + + // \brief Checks if the point falls within the NameDecl. This covers every + // declaration of a named entity that we may come across. Usually, just + // checking if the point lies within the length of the name of the declaration + // and the start location is sufficient. + bool VisitNamedDecl(const NamedDecl *Decl) { + return dyn_cast<CXXConversionDecl>(Decl) + ? true + : setResult(Decl, Decl->getLocation(), + Decl->getNameAsString().length()); + } + + // Expression visitors: + + bool VisitDeclRefExpr(const DeclRefExpr *Expr) { + const NamedDecl *Decl = Expr->getFoundDecl(); + return setResult(Decl, Expr->getLocation(), + Decl->getNameAsString().length()); + } + + bool VisitMemberExpr(const MemberExpr *Expr) { + const NamedDecl *Decl = Expr->getFoundDecl().getDecl(); + return setResult(Decl, Expr->getMemberLoc(), + Decl->getNameAsString().length()); + } + + // Other visitors: + + bool VisitTypeLoc(const TypeLoc Loc) { + const SourceLocation TypeBeginLoc = Loc.getBeginLoc(); + const SourceLocation TypeEndLoc = Lexer::getLocForEndOfToken( + TypeBeginLoc, 0, Context.getSourceManager(), Context.getLangOpts()); + if (const auto *TemplateTypeParm = + dyn_cast<TemplateTypeParmType>(Loc.getType())) + return setResult(TemplateTypeParm->getDecl(), TypeBeginLoc, TypeEndLoc); + if (const auto *TemplateSpecType = + dyn_cast<TemplateSpecializationType>(Loc.getType())) { + return setResult(TemplateSpecType->getTemplateName().getAsTemplateDecl(), + TypeBeginLoc, TypeEndLoc); + } + return setResult(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, + TypeEndLoc); + } + + bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) { + for (const auto *Initializer : ConstructorDecl->inits()) { + // Ignore implicit initializers. + if (!Initializer->isWritten()) + continue; + if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) { + const SourceLocation InitBeginLoc = Initializer->getSourceLocation(), + InitEndLoc = Lexer::getLocForEndOfToken( + InitBeginLoc, 0, Context.getSourceManager(), + Context.getLangOpts()); + if (!setResult(FieldDecl, InitBeginLoc, InitEndLoc)) + return false; + } + } + return true; + } + + // Other: + + const NamedDecl *getNamedDecl() { return Result; } + + // \brief Determines if a namespace qualifier contains the point. + // \returns false on success and sets Result. + void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) { + while (NameLoc) { + const NamespaceDecl *Decl = + NameLoc.getNestedNameSpecifier()->getAsNamespace(); + setResult(Decl, NameLoc.getLocalBeginLoc(), NameLoc.getLocalEndLoc()); + NameLoc = NameLoc.getPrefix(); + } + } + +private: + // \brief Sets Result to Decl if the Point is within Start and End. + // \returns false on success. + bool setResult(const NamedDecl *Decl, SourceLocation Start, + SourceLocation End) { + if (!Decl) + return true; + if (Name.empty()) { + // Offset is used to find the declaration. + if (!Start.isValid() || !Start.isFileID() || !End.isValid() || + !End.isFileID() || !isPointWithin(Start, End)) + return true; + } else { + // Fully qualified name is used to find the declaration. + if (Name != Decl->getQualifiedNameAsString() && + Name != "::" + Decl->getQualifiedNameAsString()) + return true; + } + Result = Decl; + return false; + } + + // \brief Sets Result to Decl if Point is within Loc and Loc + Offset. + // \returns false on success. + bool setResult(const NamedDecl *Decl, SourceLocation Loc, unsigned Offset) { + // FIXME: Add test for Offset == 0. Add test for Offset - 1 (vs -2 etc). + return Offset == 0 || + setResult(Decl, Loc, Loc.getLocWithOffset(Offset - 1)); + } + + // \brief Determines if the Point is within Start and End. + bool isPointWithin(const SourceLocation Start, const SourceLocation End) { + // FIXME: Add tests for Point == End. + return Point == Start || Point == End || + (Context.getSourceManager().isBeforeInTranslationUnit(Start, + Point) && + Context.getSourceManager().isBeforeInTranslationUnit(Point, End)); + } + + const NamedDecl *Result; + const SourceLocation Point; // The location to find the NamedDecl. + const std::string Name; + const ASTContext &Context; +}; +} // namespace + +const NamedDecl *getNamedDeclAt(const ASTContext &Context, + const SourceLocation Point) { + const SourceManager &SM = Context.getSourceManager(); + NamedDeclFindingASTVisitor Visitor(Point, Context); + + // Try to be clever about pruning down the number of top-level declarations we + // see. If both start and end is either before or after the point we're + // looking for the point cannot be inside of this decl. Don't even look at it. + for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) { + SourceLocation StartLoc = CurrDecl->getLocStart(); + SourceLocation EndLoc = CurrDecl->getLocEnd(); + if (StartLoc.isValid() && EndLoc.isValid() && + SM.isBeforeInTranslationUnit(StartLoc, Point) != + SM.isBeforeInTranslationUnit(EndLoc, Point)) + Visitor.TraverseDecl(CurrDecl); + } + + NestedNameSpecifierLocFinder Finder(const_cast<ASTContext &>(Context)); + for (const auto &Location : Finder.getNestedNameSpecifierLocations()) + Visitor.handleNestedNameSpecifierLoc(Location); + + return Visitor.getNamedDecl(); +} + +const NamedDecl *getNamedDeclFor(const ASTContext &Context, + const std::string &Name) { + NamedDeclFindingASTVisitor Visitor(Name, Context); + Visitor.TraverseDecl(Context.getTranslationUnitDecl()); + + return Visitor.getNamedDecl(); +} + +std::string getUSRForDecl(const Decl *Decl) { + llvm::SmallVector<char, 128> Buff; + + // FIXME: Add test for the nullptr case. + if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff)) + return ""; + + return std::string(Buff.data(), Buff.size()); +} + +} // end namespace tooling +} // end namespace clang diff --git a/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp b/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp new file mode 100644 index 000000000000..2769802ad2bc --- /dev/null +++ b/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp @@ -0,0 +1,236 @@ +//===--- USRFindingAction.cpp - Clang refactoring library -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides an action to find USR for the symbol at <offset>, as well as +/// all additional USRs. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h" +#include "clang/AST/AST.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Refactoring/Rename/USRFinder.h" +#include "clang/Tooling/Tooling.h" + +#include <algorithm> +#include <set> +#include <string> +#include <vector> + +using namespace llvm; + +namespace clang { +namespace tooling { + +namespace { +// \brief NamedDeclFindingConsumer should delegate finding USRs of given Decl to +// AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given +// Decl refers to class and adds USRs of all overridden methods if Decl refers +// to virtual method. +class AdditionalUSRFinder : public RecursiveASTVisitor<AdditionalUSRFinder> { +public: + AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context) + : FoundDecl(FoundDecl), Context(Context) {} + + std::vector<std::string> Find() { + // Fill OverriddenMethods and PartialSpecs storages. + TraverseDecl(Context.getTranslationUnitDecl()); + if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) { + addUSRsOfOverridenFunctions(MethodDecl); + for (const auto &OverriddenMethod : OverriddenMethods) { + if (checkIfOverriddenFunctionAscends(OverriddenMethod)) + USRSet.insert(getUSRForDecl(OverriddenMethod)); + } + } else if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundDecl)) { + handleCXXRecordDecl(RecordDecl); + } else if (const auto *TemplateDecl = + dyn_cast<ClassTemplateDecl>(FoundDecl)) { + handleClassTemplateDecl(TemplateDecl); + } else { + USRSet.insert(getUSRForDecl(FoundDecl)); + } + return std::vector<std::string>(USRSet.begin(), USRSet.end()); + } + + bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) { + if (MethodDecl->isVirtual()) + OverriddenMethods.push_back(MethodDecl); + return true; + } + + bool VisitClassTemplatePartialSpecializationDecl( + const ClassTemplatePartialSpecializationDecl *PartialSpec) { + PartialSpecs.push_back(PartialSpec); + return true; + } + +private: + void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) { + RecordDecl = RecordDecl->getDefinition(); + if (const auto *ClassTemplateSpecDecl = + dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl)) + handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecializedTemplate()); + addUSRsOfCtorDtors(RecordDecl); + } + + void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) { + for (const auto *Specialization : TemplateDecl->specializations()) + addUSRsOfCtorDtors(Specialization); + + for (const auto *PartialSpec : PartialSpecs) { + if (PartialSpec->getSpecializedTemplate() == TemplateDecl) + addUSRsOfCtorDtors(PartialSpec); + } + addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl()); + } + + void addUSRsOfCtorDtors(const CXXRecordDecl *RecordDecl) { + RecordDecl = RecordDecl->getDefinition(); + + // Skip if the CXXRecordDecl doesn't have definition. + if (!RecordDecl) + return; + + for (const auto *CtorDecl : RecordDecl->ctors()) + USRSet.insert(getUSRForDecl(CtorDecl)); + + USRSet.insert(getUSRForDecl(RecordDecl->getDestructor())); + USRSet.insert(getUSRForDecl(RecordDecl)); + } + + void addUSRsOfOverridenFunctions(const CXXMethodDecl *MethodDecl) { + USRSet.insert(getUSRForDecl(MethodDecl)); + // Recursively visit each OverridenMethod. + for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) + addUSRsOfOverridenFunctions(OverriddenMethod); + } + + bool checkIfOverriddenFunctionAscends(const CXXMethodDecl *MethodDecl) { + for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) { + if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end()) + return true; + return checkIfOverriddenFunctionAscends(OverriddenMethod); + } + return false; + } + + const Decl *FoundDecl; + ASTContext &Context; + std::set<std::string> USRSet; + std::vector<const CXXMethodDecl *> OverriddenMethods; + std::vector<const ClassTemplatePartialSpecializationDecl *> PartialSpecs; +}; +} // namespace + +class NamedDeclFindingConsumer : public ASTConsumer { +public: + NamedDeclFindingConsumer(ArrayRef<unsigned> SymbolOffsets, + ArrayRef<std::string> QualifiedNames, + std::vector<std::string> &SpellingNames, + std::vector<std::vector<std::string>> &USRList, + bool Force, bool &ErrorOccurred) + : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames), + SpellingNames(SpellingNames), USRList(USRList), Force(Force), + ErrorOccurred(ErrorOccurred) {} + +private: + bool FindSymbol(ASTContext &Context, const SourceManager &SourceMgr, + unsigned SymbolOffset, const std::string &QualifiedName) { + DiagnosticsEngine &Engine = Context.getDiagnostics(); + const FileID MainFileID = SourceMgr.getMainFileID(); + + if (SymbolOffset >= SourceMgr.getFileIDSize(MainFileID)) { + ErrorOccurred = true; + unsigned InvalidOffset = Engine.getCustomDiagID( + DiagnosticsEngine::Error, + "SourceLocation in file %0 at offset %1 is invalid"); + Engine.Report(SourceLocation(), InvalidOffset) + << SourceMgr.getFileEntryForID(MainFileID)->getName() << SymbolOffset; + return false; + } + + const SourceLocation Point = SourceMgr.getLocForStartOfFile(MainFileID) + .getLocWithOffset(SymbolOffset); + const NamedDecl *FoundDecl = QualifiedName.empty() + ? getNamedDeclAt(Context, Point) + : getNamedDeclFor(Context, QualifiedName); + + if (FoundDecl == nullptr) { + if (QualifiedName.empty()) { + FullSourceLoc FullLoc(Point, SourceMgr); + unsigned CouldNotFindSymbolAt = Engine.getCustomDiagID( + DiagnosticsEngine::Error, + "clang-rename could not find symbol (offset %0)"); + Engine.Report(Point, CouldNotFindSymbolAt) << SymbolOffset; + ErrorOccurred = true; + return false; + } + + if (Force) + return true; + + unsigned CouldNotFindSymbolNamed = Engine.getCustomDiagID( + DiagnosticsEngine::Error, "clang-rename could not find symbol %0"); + Engine.Report(CouldNotFindSymbolNamed) << QualifiedName; + ErrorOccurred = true; + return false; + } + + // If FoundDecl is a constructor or destructor, we want to instead take + // the Decl of the corresponding class. + if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl)) + FoundDecl = CtorDecl->getParent(); + else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl)) + FoundDecl = DtorDecl->getParent(); + + SpellingNames.push_back(FoundDecl->getNameAsString()); + AdditionalUSRFinder Finder(FoundDecl, Context); + USRList.push_back(Finder.Find()); + return true; + } + + void HandleTranslationUnit(ASTContext &Context) override { + const SourceManager &SourceMgr = Context.getSourceManager(); + for (unsigned Offset : SymbolOffsets) { + if (!FindSymbol(Context, SourceMgr, Offset, "")) + return; + } + for (const std::string &QualifiedName : QualifiedNames) { + if (!FindSymbol(Context, SourceMgr, 0, QualifiedName)) + return; + } + } + + ArrayRef<unsigned> SymbolOffsets; + ArrayRef<std::string> QualifiedNames; + std::vector<std::string> &SpellingNames; + std::vector<std::vector<std::string>> &USRList; + bool Force; + bool &ErrorOccurred; +}; + +std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() { + return llvm::make_unique<NamedDeclFindingConsumer>( + SymbolOffsets, QualifiedNames, SpellingNames, USRList, Force, + ErrorOccurred); +} + +} // end namespace tooling +} // end namespace clang diff --git a/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp new file mode 100644 index 000000000000..934507fe6eae --- /dev/null +++ b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp @@ -0,0 +1,509 @@ +//===--- USRLocFinder.cpp - Clang refactoring library ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Methods for finding all instances of a USR. Our strategy is very +/// simple; we just compare the USR at every relevant AST node with the one +/// provided. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Lexer.h" +#include "clang/Tooling/Core/Lookup.h" +#include "clang/Tooling/Refactoring/Rename/USRFinder.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include <cstddef> +#include <set> +#include <string> +#include <vector> + +using namespace llvm; + +namespace clang { +namespace tooling { + +namespace { + +// \brief This visitor recursively searches for all instances of a USR in a +// translation unit and stores them for later usage. +class USRLocFindingASTVisitor + : public clang::RecursiveASTVisitor<USRLocFindingASTVisitor> { +public: + explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs, + StringRef PrevName, + const ASTContext &Context) + : USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) { + } + + // Declaration visitors: + + bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) { + for (const auto *Initializer : ConstructorDecl->inits()) { + // Ignore implicit initializers. + if (!Initializer->isWritten()) + continue; + if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) { + if (USRSet.find(getUSRForDecl(FieldDecl)) != USRSet.end()) + LocationsFound.push_back(Initializer->getSourceLocation()); + } + } + return true; + } + + bool VisitNamedDecl(const NamedDecl *Decl) { + if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) + checkAndAddLocation(Decl->getLocation()); + return true; + } + + // Expression visitors: + + bool VisitDeclRefExpr(const DeclRefExpr *Expr) { + const NamedDecl *Decl = Expr->getFoundDecl(); + + if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) { + const SourceManager &Manager = Decl->getASTContext().getSourceManager(); + SourceLocation Location = Manager.getSpellingLoc(Expr->getLocation()); + checkAndAddLocation(Location); + } + + return true; + } + + bool VisitMemberExpr(const MemberExpr *Expr) { + const NamedDecl *Decl = Expr->getFoundDecl().getDecl(); + if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) { + const SourceManager &Manager = Decl->getASTContext().getSourceManager(); + SourceLocation Location = Manager.getSpellingLoc(Expr->getMemberLoc()); + checkAndAddLocation(Location); + } + return true; + } + + // Other visitors: + + bool VisitTypeLoc(const TypeLoc Loc) { + if (USRSet.find(getUSRForDecl(Loc.getType()->getAsCXXRecordDecl())) != + USRSet.end()) + checkAndAddLocation(Loc.getBeginLoc()); + if (const auto *TemplateTypeParm = + dyn_cast<TemplateTypeParmType>(Loc.getType())) { + if (USRSet.find(getUSRForDecl(TemplateTypeParm->getDecl())) != + USRSet.end()) + checkAndAddLocation(Loc.getBeginLoc()); + } + return true; + } + + // Non-visitors: + + // \brief Returns a list of unique locations. Duplicate or overlapping + // locations are erroneous and should be reported! + const std::vector<clang::SourceLocation> &getLocationsFound() const { + return LocationsFound; + } + + // Namespace traversal: + void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) { + while (NameLoc) { + const NamespaceDecl *Decl = + NameLoc.getNestedNameSpecifier()->getAsNamespace(); + if (Decl && USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) + checkAndAddLocation(NameLoc.getLocalBeginLoc()); + NameLoc = NameLoc.getPrefix(); + } + } + +private: + void checkAndAddLocation(SourceLocation Loc) { + const SourceLocation BeginLoc = Loc; + const SourceLocation EndLoc = Lexer::getLocForEndOfToken( + BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts()); + StringRef TokenName = + Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), + Context.getSourceManager(), Context.getLangOpts()); + size_t Offset = TokenName.find(PrevName); + + // The token of the source location we find actually has the old + // name. + if (Offset != StringRef::npos) + LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset)); + } + + const std::set<std::string> USRSet; + const std::string PrevName; + std::vector<clang::SourceLocation> LocationsFound; + const ASTContext &Context; +}; + +SourceLocation StartLocationForType(TypeLoc TL) { + // For elaborated types (e.g. `struct a::A`) we want the portion after the + // `struct` but including the namespace qualifier, `a::`. + if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) { + NestedNameSpecifierLoc NestedNameSpecifier = + ElaboratedTypeLoc.getQualifierLoc(); + if (NestedNameSpecifier.getNestedNameSpecifier()) + return NestedNameSpecifier.getBeginLoc(); + TL = TL.getNextTypeLoc(); + } + return TL.getLocStart(); +} + +SourceLocation EndLocationForType(TypeLoc TL) { + // Dig past any namespace or keyword qualifications. + while (TL.getTypeLocClass() == TypeLoc::Elaborated || + TL.getTypeLocClass() == TypeLoc::Qualified) + TL = TL.getNextTypeLoc(); + + // The location for template specializations (e.g. Foo<int>) includes the + // templated types in its location range. We want to restrict this to just + // before the `<` character. + if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) { + return TL.castAs<TemplateSpecializationTypeLoc>() + .getLAngleLoc() + .getLocWithOffset(-1); + } + return TL.getEndLoc(); +} + +NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) { + // Dig past any keyword qualifications. + while (TL.getTypeLocClass() == TypeLoc::Qualified) + TL = TL.getNextTypeLoc(); + + // For elaborated types (e.g. `struct a::A`) we want the portion after the + // `struct` but including the namespace qualifier, `a::`. + if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) + return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier(); + return nullptr; +} + +// Find all locations identified by the given USRs for rename. +// +// This class will traverse the AST and find every AST node whose USR is in the +// given USRs' set. +class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> { +public: + RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context) + : USRSet(USRs.begin(), USRs.end()), Context(Context) {} + + // A structure records all information of a symbol reference being renamed. + // We try to add as few prefix qualifiers as possible. + struct RenameInfo { + // The begin location of a symbol being renamed. + SourceLocation Begin; + // The end location of a symbol being renamed. + SourceLocation End; + // The declaration of a symbol being renamed (can be nullptr). + const NamedDecl *FromDecl; + // The declaration in which the nested name is contained (can be nullptr). + const Decl *Context; + // The nested name being replaced (can be nullptr). + const NestedNameSpecifier *Specifier; + }; + + // FIXME: Currently, prefix qualifiers will be added to the renamed symbol + // definition (e.g. "class Foo {};" => "class b::Bar {};" when renaming + // "a::Foo" to "b::Bar"). + // For renaming declarations/definitions, prefix qualifiers should be filtered + // out. + bool VisitNamedDecl(const NamedDecl *Decl) { + // UsingDecl has been handled in other place. + if (llvm::isa<UsingDecl>(Decl)) + return true; + + // DestructorDecl has been handled in Typeloc. + if (llvm::isa<CXXDestructorDecl>(Decl)) + return true; + + if (Decl->isImplicit()) + return true; + + if (isInUSRSet(Decl)) { + RenameInfo Info = {Decl->getLocation(), Decl->getLocation(), nullptr, + nullptr, nullptr}; + RenameInfos.push_back(Info); + } + return true; + } + + bool VisitDeclRefExpr(const DeclRefExpr *Expr) { + const NamedDecl *Decl = Expr->getFoundDecl(); + if (isInUSRSet(Decl)) { + RenameInfo Info = {Expr->getSourceRange().getBegin(), + Expr->getSourceRange().getEnd(), Decl, + getClosestAncestorDecl(*Expr), Expr->getQualifier()}; + RenameInfos.push_back(Info); + } + + return true; + } + + bool VisitUsingDecl(const UsingDecl *Using) { + for (const auto *UsingShadow : Using->shadows()) { + if (isInUSRSet(UsingShadow->getTargetDecl())) { + UsingDecls.push_back(Using); + break; + } + } + return true; + } + + bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) { + if (!NestedLoc.getNestedNameSpecifier()->getAsType()) + return true; + if (IsTypeAliasWhichWillBeRenamedElsewhere(NestedLoc.getTypeLoc())) + return true; + + if (const auto *TargetDecl = + getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) { + if (isInUSRSet(TargetDecl)) { + RenameInfo Info = {NestedLoc.getBeginLoc(), + EndLocationForType(NestedLoc.getTypeLoc()), + TargetDecl, getClosestAncestorDecl(NestedLoc), + NestedLoc.getNestedNameSpecifier()->getPrefix()}; + RenameInfos.push_back(Info); + } + } + return true; + } + + bool VisitTypeLoc(TypeLoc Loc) { + if (IsTypeAliasWhichWillBeRenamedElsewhere(Loc)) + return true; + + auto Parents = Context.getParents(Loc); + TypeLoc ParentTypeLoc; + if (!Parents.empty()) { + // Handle cases of nested name specificier locations. + // + // The VisitNestedNameSpecifierLoc interface is not impelmented in + // RecursiveASTVisitor, we have to handle it explicitly. + if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) { + VisitNestedNameSpecifierLocations(*NSL); + return true; + } + + if (const auto *TL = Parents[0].get<TypeLoc>()) + ParentTypeLoc = *TL; + } + + // Handle the outermost TypeLoc which is directly linked to the interesting + // declaration and don't handle nested name specifier locations. + if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) { + if (isInUSRSet(TargetDecl)) { + // Only handle the outermost typeLoc. + // + // For a type like "a::Foo", there will be two typeLocs for it. + // One ElaboratedType, the other is RecordType: + // + // ElaboratedType 0x33b9390 'a::Foo' sugar + // `-RecordType 0x338fef0 'class a::Foo' + // `-CXXRecord 0x338fe58 'Foo' + // + // Skip if this is an inner typeLoc. + if (!ParentTypeLoc.isNull() && + isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc))) + return true; + RenameInfo Info = {StartLocationForType(Loc), EndLocationForType(Loc), + TargetDecl, getClosestAncestorDecl(Loc), + GetNestedNameForType(Loc)}; + RenameInfos.push_back(Info); + return true; + } + } + + // Handle specific template class specialiation cases. + if (const auto *TemplateSpecType = + dyn_cast<TemplateSpecializationType>(Loc.getType())) { + TypeLoc TargetLoc = Loc; + if (!ParentTypeLoc.isNull()) { + if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType())) + TargetLoc = ParentTypeLoc; + } + + if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) { + TypeLoc TargetLoc = Loc; + // FIXME: Find a better way to handle this case. + // For the qualified template class specification type like + // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc + // (ElaboratedType) of the TemplateSpecializationType in order to + // catch the prefix qualifiers "ns::". + if (!ParentTypeLoc.isNull() && + llvm::isa<ElaboratedType>(ParentTypeLoc.getType())) + TargetLoc = ParentTypeLoc; + RenameInfo Info = { + StartLocationForType(TargetLoc), EndLocationForType(TargetLoc), + TemplateSpecType->getTemplateName().getAsTemplateDecl(), + getClosestAncestorDecl( + ast_type_traits::DynTypedNode::create(TargetLoc)), + GetNestedNameForType(TargetLoc)}; + RenameInfos.push_back(Info); + } + } + return true; + } + + // Returns a list of RenameInfo. + const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; } + + // Returns a list of using declarations which are needed to update. + const std::vector<const UsingDecl *> &getUsingDecls() const { + return UsingDecls; + } + +private: + // FIXME: This method may not be suitable for renaming other types like alias + // types. Need to figure out a way to handle it. + bool IsTypeAliasWhichWillBeRenamedElsewhere(TypeLoc TL) const { + while (!TL.isNull()) { + // SubstTemplateTypeParm is the TypeLocation class for a substituted type + // inside a template expansion so we ignore these. For example: + // + // template<typename T> struct S { + // T t; // <-- this T becomes a TypeLoc(int) with class + // // SubstTemplateTypeParm when S<int> is instantiated + // } + if (TL.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm) + return true; + + // Typedef is the TypeLocation class for a type which is a typedef to the + // type we want to replace. We ignore the use of the typedef as we will + // replace the definition of it. For example: + // + // typedef int T; + // T a; // <--- This T is a TypeLoc(int) with class Typedef. + if (TL.getTypeLocClass() == TypeLoc::Typedef) + return true; + TL = TL.getNextTypeLoc(); + } + return false; + } + + // Get the supported declaration from a given typeLoc. If the declaration type + // is not supported, returns nullptr. + // + // FIXME: support more types, e.g. enum, type alias. + const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) { + if (const auto *RD = Loc.getType()->getAsCXXRecordDecl()) + return RD; + return nullptr; + } + + // Get the closest ancester which is a declaration of a given AST node. + template <typename ASTNodeType> + const Decl *getClosestAncestorDecl(const ASTNodeType &Node) { + auto Parents = Context.getParents(Node); + // FIXME: figure out how to handle it when there are multiple parents. + if (Parents.size() != 1) + return nullptr; + if (ast_type_traits::ASTNodeKind::getFromNodeKind<Decl>().isBaseOf( + Parents[0].getNodeKind())) + return Parents[0].template get<Decl>(); + return getClosestAncestorDecl(Parents[0]); + } + + // Get the parent typeLoc of a given typeLoc. If there is no such parent, + // return nullptr. + const TypeLoc *getParentTypeLoc(TypeLoc Loc) const { + auto Parents = Context.getParents(Loc); + // FIXME: figure out how to handle it when there are multiple parents. + if (Parents.size() != 1) + return nullptr; + return Parents[0].get<TypeLoc>(); + } + + // Check whether the USR of a given Decl is in the USRSet. + bool isInUSRSet(const Decl *Decl) const { + auto USR = getUSRForDecl(Decl); + if (USR.empty()) + return false; + return llvm::is_contained(USRSet, USR); + } + + const std::set<std::string> USRSet; + ASTContext &Context; + std::vector<RenameInfo> RenameInfos; + // Record all interested using declarations which contains the using-shadow + // declarations of the symbol declarations being renamed. + std::vector<const UsingDecl *> UsingDecls; +}; + +} // namespace + +std::vector<SourceLocation> +getLocationsOfUSRs(const std::vector<std::string> &USRs, StringRef PrevName, + Decl *Decl) { + USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext()); + Visitor.TraverseDecl(Decl); + NestedNameSpecifierLocFinder Finder(Decl->getASTContext()); + + for (const auto &Location : Finder.getNestedNameSpecifierLocations()) + Visitor.handleNestedNameSpecifierLoc(Location); + + return Visitor.getLocationsFound(); +} + +std::vector<tooling::AtomicChange> +createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs, + llvm::StringRef NewName, Decl *TranslationUnitDecl) { + RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext()); + Finder.TraverseDecl(TranslationUnitDecl); + + const SourceManager &SM = + TranslationUnitDecl->getASTContext().getSourceManager(); + + std::vector<tooling::AtomicChange> AtomicChanges; + auto Replace = [&](SourceLocation Start, SourceLocation End, + llvm::StringRef Text) { + tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start); + llvm::Error Err = ReplaceChange.replace( + SM, CharSourceRange::getTokenRange(Start, End), Text); + if (Err) { + llvm::errs() << "Faile to add replacement to AtomicChange: " + << llvm::toString(std::move(Err)) << "\n"; + return; + } + AtomicChanges.push_back(std::move(ReplaceChange)); + }; + + for (const auto &RenameInfo : Finder.getRenameInfos()) { + std::string ReplacedName = NewName.str(); + if (RenameInfo.FromDecl && RenameInfo.Context) { + if (!llvm::isa<clang::TranslationUnitDecl>( + RenameInfo.Context->getDeclContext())) { + ReplacedName = tooling::replaceNestedName( + RenameInfo.Specifier, RenameInfo.Context->getDeclContext(), + RenameInfo.FromDecl, + NewName.startswith("::") ? NewName.str() : ("::" + NewName).str()); + } + } + // If the NewName contains leading "::", add it back. + if (NewName.startswith("::") && NewName.substr(2) == ReplacedName) + ReplacedName = NewName.str(); + Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName); + } + + // Hanlde using declarations explicitly as "using a::Foo" don't trigger + // typeLoc for "a::Foo". + for (const auto *Using : Finder.getUsingDecls()) + Replace(Using->getLocStart(), Using->getLocEnd(), "using " + NewName.str()); + + return AtomicChanges; +} + +} // end namespace tooling +} // end namespace clang |